started adding conf_service and conf-metadata constructors. not finished yet, just...
[pazpar2-moved-to-github.git] / src / config.c
1 /* $Id: config.c,v 1.25 2007-04-19 11:57:53 marc Exp $
2    Copyright (c) 2006-2007, Index Data.
3
4 This file is part of Pazpar2.
5
6 Pazpar2 is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Pazpar2; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 /* $Id: config.c,v 1.25 2007-04-19 11:57:53 marc Exp $ */
23
24 #include <string.h>
25
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 #include <libxslt/xslt.h>
29 #include <libxslt/transform.h>
30 #include <libxslt/xsltutils.h>
31
32 #if HAVE_CONFIG_H
33 #include <cconfig.h>
34 #endif
35
36 #include <yaz/yaz-util.h>
37 #include <yaz/nmem.h>
38
39 #define CONFIG_NOEXTERNS
40 #include "config.h"
41
42 static NMEM nmem = 0;
43 static char confdir[256] = ".";
44
45 struct conf_config *config = 0;
46
47 struct conf_service * conf_service_create(NMEM nmem)
48 {
49     struct conf_service * service
50         = nmem_malloc(nmem, sizeof(struct conf_service));
51     service->num_metadata = 0;
52     service->metadata = 0;
53     service->num_sortkeys = 0;
54     service->sortkeys = 0;
55     return service; 
56 }
57
58
59 struct conf_metadata * conf_metadata_create(NMEM nmem, 
60                                             const char *name,
61                                             enum conf_metadata_type type,
62                                             enum conf_metadata_merge merge,
63                                             int brief,
64                                             int termlist,
65                                             int rank,
66                                             int sortkey_offset)
67 {
68
69     struct conf_metadata * metadata
70         = nmem_malloc(nmem, sizeof(struct conf_metadata));
71
72     metadata->name = nmem_strdup(nmem, name);
73     metadata->type = type;
74     metadata->merge = merge;
75     metadata->brief = brief;   
76     metadata->termlist = termlist;
77     metadata->rank = rank;    
78     metadata->sortkey_offset = sortkey_offset;
79     return metadata;
80 }
81
82 struct conf_metadata* conf_service_add_metadata(NMEM nmem,
83                                                 struct conf_service *service,
84                                                 const char *name,
85                                                 enum conf_metadata_type type,
86                                                 enum conf_metadata_merge merge,
87                                                 int brief,
88                                                 int termlist,
89                                                 int rank,
90                                                 int sortkey_offset)
91 {
92     struct conf_metadata * m = 0;
93
94     if (!service)
95         return m;
96
97     m = conf_metadata_create(nmem, name, type, merge, 
98                              brief, termlist, rank, sortkey_offset);
99
100     // Not finished, checked temporarily in for file move  // if (m)
101
102     return m;
103 }
104
105
106
107
108 /* Code to parse configuration file */
109 /* ==================================================== */
110
111 static struct conf_service *parse_service(xmlNode *node)
112 {
113     xmlNode *n;
114     struct conf_service *r = nmem_malloc(nmem, sizeof(struct conf_service));
115     int md_node = 0;
116     int sk_node = 0;
117
118     r->num_sortkeys = r->num_metadata = 0;
119     // Allocate array of conf metadata and sortkey tructs, if necessary
120     for (n = node->children; n; n = n->next)
121         if (n->type == XML_ELEMENT_NODE && !strcmp((const char *)
122                                                    n->name, "metadata"))
123         {
124             xmlChar *sortkey = xmlGetProp(n, (xmlChar *) "sortkey");
125             r->num_metadata++;
126             if (sortkey && strcmp((const char *) sortkey, "no"))
127                 r->num_sortkeys++;
128             xmlFree(sortkey);
129         }
130     if (r->num_metadata)
131         r->metadata = nmem_malloc(nmem, sizeof(struct conf_metadata) * r->num_metadata);
132     else
133         r->metadata = 0;
134     if (r->num_sortkeys)
135         r->sortkeys = nmem_malloc(nmem, sizeof(struct conf_sortkey) * r->num_sortkeys);
136     else
137         r->sortkeys = 0;
138
139     for (n = node->children; n; n = n->next)
140     {
141         if (n->type != XML_ELEMENT_NODE)
142             continue;
143         if (!strcmp((const char *) n->name, (const char *) "metadata"))
144         {
145             struct conf_metadata *md = &r->metadata[md_node];
146             xmlChar *name = xmlGetProp(n, (xmlChar *) "name");
147             xmlChar *brief = xmlGetProp(n, (xmlChar *) "brief");
148             xmlChar *sortkey = xmlGetProp(n, (xmlChar *) "sortkey");
149             xmlChar *merge = xmlGetProp(n, (xmlChar *) "merge");
150             xmlChar *type = xmlGetProp(n, (xmlChar *) "type");
151             xmlChar *termlist = xmlGetProp(n, (xmlChar *) "termlist");
152             xmlChar *rank = xmlGetProp(n, (xmlChar *) "rank");
153
154             if (!name)
155             {
156                 yaz_log(YLOG_FATAL, "Must specify name in metadata element");
157                 return 0;
158             }
159             md->name = nmem_strdup(nmem, (const char *) name);
160             if (brief)
161             {
162                 if (!strcmp((const char *) brief, "yes"))
163                     md->brief = 1;
164                 else if (strcmp((const char *) brief, "no"))
165                 {
166                     yaz_log(YLOG_FATAL, "metadata/brief must be yes or no");
167                     return 0;
168                 }
169             }
170             else
171                 md->brief = 0;
172
173             if (termlist)
174             {
175                 if (!strcmp((const char *) termlist, "yes"))
176                     md->termlist = 1;
177                 else if (strcmp((const char *) termlist, "no"))
178                 {
179                     yaz_log(YLOG_FATAL, "metadata/termlist must be yes or no");
180                     return 0;
181                 }
182             }
183             else
184                 md->termlist = 0;
185
186             if (rank)
187                 md->rank = atoi((const char *) rank);
188             else
189                 md->rank = 0;
190
191             if (type)
192             {
193                 if (!strcmp((const char *) type, "generic"))
194                     md->type = Metadata_type_generic;
195                 else if (!strcmp((const char *) type, "year"))
196                     md->type = Metadata_type_year;
197                 else
198                 {
199                     yaz_log(YLOG_FATAL, "Unknown value for metadata/type: %s", type);
200                     return 0;
201                 }
202             }
203             else
204                 md->type = Metadata_type_generic;
205
206             if (merge)
207             {
208                 if (!strcmp((const char *) merge, "no"))
209                     md->merge = Metadata_merge_no;
210                 else if (!strcmp((const char *) merge, "unique"))
211                     md->merge = Metadata_merge_unique;
212                 else if (!strcmp((const char *) merge, "longest"))
213                     md->merge = Metadata_merge_longest;
214                 else if (!strcmp((const char *) merge, "range"))
215                     md->merge = Metadata_merge_range;
216                 else if (!strcmp((const char *) merge, "all"))
217                     md->merge = Metadata_merge_all;
218                 else
219                 {
220                     yaz_log(YLOG_FATAL, "Unknown value for metadata/merge: %s", merge);
221                     return 0;
222                 }
223             }
224             else
225                 md->merge = Metadata_merge_no;
226
227             if (sortkey && strcmp((const char *) sortkey, "no"))
228             {
229                 struct conf_sortkey *sk = &r->sortkeys[sk_node];
230                 if (md->merge == Metadata_merge_no)
231                 {
232                     yaz_log(YLOG_FATAL, "Can't specify sortkey on a non-merged field");
233                     return 0;
234                 }
235                 if (!strcmp((const char *) sortkey, "numeric"))
236                     sk->type = Metadata_sortkey_numeric;
237                 else if (!strcmp((const char *) sortkey, "skiparticle"))
238                     sk->type = Metadata_sortkey_skiparticle;
239                 else
240                 {
241                     yaz_log(YLOG_FATAL, "Unknown sortkey in metadata element: %s", sortkey);
242                     return 0;
243                 }
244                 sk->name = md->name;
245                 md->sortkey_offset = sk_node;
246                 sk_node++;
247             }
248             else
249                 md->sortkey_offset = -1;
250
251             xmlFree(name);
252             xmlFree(brief);
253             xmlFree(sortkey);
254             xmlFree(merge);
255             xmlFree(type);
256             xmlFree(termlist);
257             xmlFree(rank);
258             md_node++;
259         }
260         else
261         {
262             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
263             return 0;
264         }
265     }
266     return r;
267 }
268
269 static char *parse_settings(xmlNode *node)
270 {
271     xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
272     char *r;
273
274     if (src)
275         r = nmem_strdup(nmem, (const char *) src);
276     else
277     {
278         yaz_log(YLOG_FATAL, "Must specify src in targetprofile");
279         return 0;
280     }
281     xmlFree(src);
282     return r;
283 }
284
285 static struct conf_server *parse_server(xmlNode *node)
286 {
287     xmlNode *n;
288     struct conf_server *r = nmem_malloc(nmem, sizeof(struct conf_server));
289
290     r->host = 0;
291     r->port = 0;
292     r->proxy_host = 0;
293     r->proxy_port = 0;
294     r->myurl = 0;
295     r->zproxy_host = 0;
296     r->zproxy_port = 0;
297     r->service = 0;
298     r->next = 0;
299     r->settings = 0;
300
301     for (n = node->children; n; n = n->next)
302     {
303         if (n->type != XML_ELEMENT_NODE)
304             continue;
305         if (!strcmp((const char *) n->name, "listen"))
306         {
307             xmlChar *port = xmlGetProp(n, (xmlChar *) "port");
308             xmlChar *host = xmlGetProp(n, (xmlChar *) "host");
309             if (port)
310                 r->port = atoi((const char *) port);
311             if (host)
312                 r->host = nmem_strdup(nmem, (const char *) host);
313             xmlFree(port);
314             xmlFree(host);
315         }
316         else if (!strcmp((const char *) n->name, "proxy"))
317         {
318             xmlChar *port = xmlGetProp(n, (xmlChar *) "port");
319             xmlChar *host = xmlGetProp(n, (xmlChar *) "host");
320             xmlChar *myurl = xmlGetProp(n, (xmlChar *) "myurl");
321             if (port)
322                 r->proxy_port = atoi((const char *) port);
323             if (host)
324                 r->proxy_host = nmem_strdup(nmem, (const char *) host);
325             if (myurl)
326                 r->myurl = nmem_strdup(nmem, (const char *) myurl);
327 #ifdef GAGA
328             else
329             {
330                 yaz_log(YLOG_FATAL, "Must specify @myurl for proxy");
331                 return 0;
332             }
333 #endif
334             xmlFree(port);
335             xmlFree(host);
336             xmlFree(myurl);
337         }
338         else if (!strcmp((const char *) n->name, "zproxy"))
339         {
340             xmlChar *port = 0;
341             xmlChar *host = 0;
342
343             port = xmlGetProp(n, (xmlChar *) "port");
344             host = xmlGetProp(n, (xmlChar *) "host");
345
346             if (port)
347                 r->zproxy_port = atoi((const char *) port);
348             if (host)
349                 r->zproxy_host = nmem_strdup(nmem, (const char *) host);
350
351             xmlFree(port);
352             xmlFree(host);
353         }
354         else if (!strcmp((const char *) n->name, "settings"))
355         {
356             if (r->settings)
357             {
358                 yaz_log(YLOG_FATAL, "Can't repeat 'settings'");
359                 return 0;
360             }
361             if (!(r->settings = parse_settings(n)))
362                 return 0;
363         }
364         else if (!strcmp((const char *) n->name, "service"))
365         {
366             struct conf_service *s = parse_service(n);
367             if (!s)
368                 return 0;
369             r->service = s;
370         }
371         else
372         {
373             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
374             return 0;
375         }
376     }
377     return r;
378 }
379
380 xsltStylesheet *conf_load_stylesheet(const char *fname)
381 {
382     char path[256];
383     sprintf(path, "%s/%s", confdir, fname);
384     return xsltParseStylesheetFile((xmlChar *) path);
385 }
386
387 static struct conf_targetprofiles *parse_targetprofiles(xmlNode *node)
388 {
389     struct conf_targetprofiles *r = nmem_malloc(nmem, sizeof(*r));
390     xmlChar *type = xmlGetProp(node, (xmlChar *) "type");
391     xmlChar *src = xmlGetProp(node, (xmlChar *) "src");
392
393     memset(r, 0, sizeof(*r));
394
395     if (type)
396     {
397         if (!strcmp((const char *) type, "local"))
398             r->type = Targetprofiles_local;
399         else
400         {
401             yaz_log(YLOG_FATAL, "Unknown targetprofile type");
402             return 0;
403         }
404     }
405     else
406     {
407         yaz_log(YLOG_FATAL, "Must specify type for targetprofile");
408         return 0;
409     }
410
411     if (src)
412         r->src = nmem_strdup(nmem, (const char *) src);
413     else
414     {
415         yaz_log(YLOG_FATAL, "Must specify src in targetprofile");
416         return 0;
417     }
418     xmlFree(type);
419     xmlFree(src);
420     return r;
421 }
422
423 static struct conf_config *parse_config(xmlNode *root)
424 {
425     xmlNode *n;
426     struct conf_config *r = nmem_malloc(nmem, sizeof(struct conf_config));
427
428     r->servers = 0;
429     r->targetprofiles = 0;
430
431     for (n = root->children; n; n = n->next)
432     {
433         if (n->type != XML_ELEMENT_NODE)
434             continue;
435         if (!strcmp((const char *) n->name, "server"))
436         {
437             struct conf_server *tmp = parse_server(n);
438             if (!tmp)
439                 return 0;
440             tmp->next = r->servers;
441             r->servers = tmp;
442         }
443         else if (!strcmp((const char *) n->name, "targetprofiles"))
444         {
445             // It would be fun to be able to fix this sometime
446             if (r->targetprofiles)
447             {
448                 yaz_log(YLOG_FATAL, "Can't repeat targetprofiles");
449                 return 0;
450             }
451             if (!(r->targetprofiles = parse_targetprofiles(n)))
452                 return 0;
453         }
454         else
455         {
456             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
457             return 0;
458         }
459     }
460     return r;
461 }
462
463 int read_config(const char *fname)
464 {
465     xmlDoc *doc = xmlParseFile(fname);
466     const char *p;
467
468     if (!nmem)  // Initialize
469     {
470         nmem = nmem_create();
471         xmlSubstituteEntitiesDefault(1);
472         xmlLoadExtDtdDefaultValue = 1;
473     }
474     if (!doc)
475     {
476         yaz_log(YLOG_FATAL, "Failed to read %s", fname);
477         exit(1);
478     }
479     if ((p = strrchr(fname, '/')))
480     {
481         int len = p - fname;
482         strncpy(confdir, fname, len);
483         confdir[len] = '\0';
484     }
485     config = parse_config(xmlDocGetRootElement(doc));
486     xmlFreeDoc(doc);
487
488     if (config)
489         return 1;
490     else
491         return 0;
492 }
493
494
495 /*
496  * Local variables:
497  * c-basic-offset: 4
498  * indent-tabs-mode: nil
499  * End:
500  * vim: shiftwidth=4 tabstop=8 expandtab
501  */