46c3f64f82f3694769b96e211ac4e2f9a7a3b8f7
[pazpar2-moved-to-github.git] / src / config.c
1 /* $Id: config.c,v 1.5 2007-01-08 18:32:35 quinn Exp $ */
2
3 #include <string.h>
4
5 #include <libxml/parser.h>
6 #include <libxml/tree.h>
7 #include <libxslt/xslt.h>
8 #include <libxslt/transform.h>
9 #include <libxslt/xsltutils.h>
10
11 #if HAVE_CONFIG_H
12 #include <cconfig.h>
13 #endif
14
15 #include <yaz/yaz-util.h>
16 #include <yaz/nmem.h>
17
18 #define CONFIG_NOEXTERNS
19 #include "config.h"
20
21 static NMEM nmem = 0;
22 static char confdir[256] = ".";
23
24 struct conf_config *config = 0;
25
26 /* Code to parse configuration file */
27 /* ==================================================== */
28
29 static struct conf_service *parse_service(xmlNode *node)
30 {
31     xmlNode *n;
32     struct conf_service *r = nmem_malloc(nmem, sizeof(struct conf_service));
33     int num_metadata = 0;
34     int md_node = 0;
35
36     // Allocate array of conf metadata structs, if necessary
37     for (n = node->children; n; n = n->next)
38         if (n->type == XML_ELEMENT_NODE && !strcmp(n->name, "metadata"))
39             num_metadata++;
40     if (num_metadata)
41         r->metadata = nmem_malloc(nmem, sizeof(struct conf_metadata) * num_metadata);
42     r->num_metadata = num_metadata;
43
44     for (n = node->children; n; n = n->next)
45     {
46         if (n->type != XML_ELEMENT_NODE)
47             continue;
48         if (!strcmp(n->name, "metadata"))
49         {
50             struct conf_metadata *md = &r->metadata[md_node];
51             xmlChar *name = xmlGetProp(n, "name");
52             xmlChar *brief = xmlGetProp(n, "brief");
53             xmlChar *sortkey = xmlGetProp(n, "sortkey");
54             xmlChar *merge = xmlGetProp(n, "merge");
55             xmlChar *type = xmlGetProp(n, "type");
56             xmlChar *termlist = xmlGetProp(n, "termlist");
57
58             if (!name)
59             {
60                 yaz_log(YLOG_FATAL, "Must specify name in metadata element");
61                 return 0;
62             }
63             md->name = nmem_strdup(nmem, name);
64             if (brief)
65             {
66                 if (!strcmp(brief, "yes"))
67                     md->brief = 1;
68                 else if (strcmp(brief, "no"))
69                 {
70                     yaz_log(YLOG_FATAL, "metadata/brief must be yes or no");
71                     return 0;
72                 }
73             }
74             else
75                 md->brief = 0;
76
77             if (termlist)
78             {
79                 if (!strcmp(termlist, "yes"))
80                     md->termlist = 1;
81                 else if (strcmp(termlist, "no"))
82                 {
83                     yaz_log(YLOG_FATAL, "metadata/termlist must be yes or no");
84                     return 0;
85                 }
86             }
87             else
88                 md->termlist = 0;
89
90             if (type)
91             {
92                 if (!strcmp(type, "generic"))
93                     md->type = Metadata_type_generic;
94                 else if (!strcmp(type, "integer"))
95                     md->type = Metadata_type_integer;
96                 else if (!strcmp(type, "year"))
97                     md->type = Metadata_type_year;
98                 else
99                 {
100                     yaz_log(YLOG_FATAL, "Unknown value for metadata/type: %s", type);
101                     return 0;
102                 }
103             }
104             md->type = Metadata_type_generic;
105
106             if (sortkey)
107             {
108                 if (!strcmp(sortkey, "no"))
109                     md->sortkey = Metadata_sortkey_no;
110                 else if (!strcmp(sortkey, "numeric"))
111                     md->sortkey = Metadata_sortkey_numeric;
112                 else if (!strcmp(sortkey, "range"))
113                     md->sortkey = Metadata_sortkey_range;
114                 else if (!strcmp(sortkey, "skiparticle"))
115                     md->sortkey = Metadata_sortkey_skiparticle;
116                 else
117                 {
118                     yaz_log(YLOG_FATAL, "Unknown sortkey in metadata element: %s", sortkey);
119                     return 0;
120                 }
121             }
122             else
123                 md->sortkey = Metadata_sortkey_no;
124
125             if (merge)
126             {
127                 if (!strcmp(merge, "no"))
128                     md->merge = Metadata_merge_no;
129                 else if (!strcmp(merge, "unique"))
130                     md->merge = Metadata_merge_unique;
131                 else if (!strcmp(merge, "longest"))
132                     md->merge = Metadata_merge_longest;
133                 else if (!strcmp(merge, "range"))
134                     md->merge = Metadata_merge_range;
135                 else if (!strcmp(merge, "all"))
136                     md->merge = Metadata_merge_all;
137                 else
138                 {
139                     yaz_log(YLOG_FATAL, "Unknown value for metadata/merge: %s", merge);
140                     return 0;
141                 }
142             }
143             else
144                 md->merge = Metadata_merge_no;
145
146             xmlFree(name);
147             xmlFree(brief);
148             xmlFree(sortkey);
149             xmlFree(merge);
150             xmlFree(termlist);
151             md_node++;
152         }
153         else
154         {
155             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
156             return 0;
157         }
158     }
159     return r;
160 }
161
162 static struct conf_server *parse_server(xmlNode *node)
163 {
164     xmlNode *n;
165     struct conf_server *r = nmem_malloc(nmem, sizeof(struct conf_server));
166
167     r->host = 0;
168     r->port = 0;
169     r->proxy_host = 0;
170     r->proxy_port = 0;
171     r->service = 0;
172     r->next = 0;
173
174     for (n = node->children; n; n = n->next)
175     {
176         if (n->type != XML_ELEMENT_NODE)
177             continue;
178         if (!strcmp(n->name, "listen"))
179         {
180             xmlChar *port = xmlGetProp(n, "port");
181             xmlChar *host = xmlGetProp(n, "host");
182             if (port)
183                 r->port = atoi(port);
184             if (host)
185                 r->host = nmem_strdup(nmem, host);
186             xmlFree(port);
187             xmlFree(host);
188         }
189         else if (!strcmp(n->name, "proxy"))
190         {
191             xmlChar *port = xmlGetProp(n, "port");
192             xmlChar *host = xmlGetProp(n, "host");
193             if (port)
194                 r->proxy_port = atoi(port);
195             if (host)
196                 r->proxy_host = nmem_strdup(nmem, host);
197             xmlFree(port);
198             xmlFree(host);
199         }
200         else if (!strcmp(n->name, "service"))
201         {
202             struct conf_service *s = parse_service(n);
203             if (!s)
204                 return 0;
205             r->service = s;
206         }
207         else
208         {
209             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
210             return 0;
211         }
212     }
213     return r;
214 }
215
216 static xsltStylesheet *load_stylesheet(const char *fname)
217 {
218     char path[256];
219     sprintf(path, "%s/%s", confdir, fname);
220     return xsltParseStylesheetFile(path);
221 }
222
223 static void setup_marc(struct conf_retrievalprofile *r)
224 {
225     yaz_iconv_t cm;
226     r->yaz_marc = yaz_marc_create();
227     if (!(cm = yaz_iconv_open("utf-8", r->native_encoding)))
228     {
229         yaz_log(YLOG_WARN, "Unable to support mapping from %s", r->native_encoding);
230         return;
231     }
232     yaz_marc_iconv(r->yaz_marc, cm);
233 }
234
235 static struct conf_retrievalprofile *parse_retrievalprofile(xmlNode *node)
236 {
237     struct conf_retrievalprofile *r = nmem_malloc(nmem, sizeof(struct conf_retrievalprofile));
238     xmlNode *n;
239     struct conf_retrievalmap **rm = &r->maplist;
240
241     r->requestsyntax = 0;
242     r->native_syntax = Nativesyn_xml;
243     r->native_format = Nativeform_na;
244     r->native_encoding = 0;
245     r->native_mapto = Nativemapto_na;
246     r->yaz_marc = 0;
247     r->maplist = 0;
248     r->next = 0;
249
250     for (n = node->children; n; n = n->next)
251     {
252         if (n->type != XML_ELEMENT_NODE)
253             continue;
254         if (!strcmp(n->name, "requestsyntax"))
255         {
256             xmlChar *content = xmlNodeGetContent(n);
257             if (content)
258                 r->requestsyntax = nmem_strdup(nmem, content);
259         }
260         else if (!strcmp(n->name, "nativesyntax"))
261         {
262             xmlChar *name = xmlGetProp(n, "name");
263             xmlChar *format = xmlGetProp(n, "format");
264             xmlChar *encoding = xmlGetProp(n, "encoding");
265             xmlChar *mapto = xmlGetProp(n, "mapto");
266             if (!name)
267             {
268                 yaz_log(YLOG_WARN, "Missing name in 'nativesyntax' element");
269                 return 0;
270             }
271             if (!strcmp(name, "iso2709"))
272             {
273                 r->native_syntax = Nativesyn_iso2709;
274                 // Set a few defaults, too
275                 r->native_format = Nativeform_marc21;
276                 r->native_mapto = Nativemapto_marcxml;
277                 r->native_encoding = "marc-8";
278                 setup_marc(r);
279             }
280             else if (!strcmp(name, "xml"))
281                 r->native_syntax = Nativesyn_xml;
282             else
283             {
284                 yaz_log(YLOG_WARN, "Unknown native syntax name %s", name);
285                 return 0;
286             }
287             if (format)
288             {
289                 if (!strcmp(format, "marc21") || !strcmp(format, "usmarc"))
290                     r->native_format = Nativeform_marc21;
291                 else
292                 {
293                     yaz_log(YLOG_WARN, "Unknown native format name %s", format);
294                     return 0;
295                 }
296             }
297             if (encoding)
298                 r->native_encoding = encoding;
299             if (mapto)
300             {
301                 if (!strcmp(mapto, "marcxml"))
302                     r->native_mapto = Nativemapto_marcxml;
303                 else if (!strcmp(mapto, "marcxchange"))
304                     r->native_mapto = Nativemapto_marcxchange;
305                 else
306                 {
307                     yaz_log(YLOG_WARN, "Unknown mapto target %s", format);
308                     return 0;
309                 }
310             }
311             xmlFree(name);
312             xmlFree(format);
313             xmlFree(encoding);
314             xmlFree(mapto);
315         }
316         else if (!strcmp(n->name, "map"))
317         {
318             struct conf_retrievalmap *m = nmem_malloc(nmem, sizeof(struct conf_retrievalmap));
319             xmlChar *type = xmlGetProp(n, "type");
320             xmlChar *charset = xmlGetProp(n, "charset");
321             xmlChar *format = xmlGetProp(n, "format");
322             xmlChar *stylesheet = xmlGetProp(n, "stylesheet");
323             bzero(m, sizeof(*m));
324             if (type)
325             {
326                 if (!strcmp(type, "xslt"))
327                     m->type = Map_xslt;
328                 else
329                 {
330                     yaz_log(YLOG_WARN, "Unknown map type: %s", type);
331                     return 0;
332                 }
333             }
334             if (charset)
335                 m->charset = nmem_strdup(nmem, charset);
336             if (format)
337                 m->format = nmem_strdup(nmem, format);
338             if (stylesheet)
339             {
340                 if (!(m->stylesheet = load_stylesheet(stylesheet)))
341                     return 0;
342             }
343             *rm = m;
344             rm = &m->next;
345             xmlFree(type);
346             xmlFree(charset);
347             xmlFree(format);
348             xmlFree(stylesheet);
349         }
350         else
351         {
352             yaz_log(YLOG_FATAL, "Bad element in retrievalprofile: %s", n->name);
353             return 0;
354         }
355     }
356
357     return r;
358 }
359
360 static struct conf_config *parse_config(xmlNode *root)
361 {
362     xmlNode *n;
363     struct conf_config *r = nmem_malloc(nmem, sizeof(struct conf_config));
364     struct conf_retrievalprofile **rp = &r->retrievalprofiles;
365
366     r->servers = 0;
367     r->queryprofiles = 0;
368     r->retrievalprofiles = 0;
369
370     for (n = root->children; n; n = n->next)
371     {
372         if (n->type != XML_ELEMENT_NODE)
373             continue;
374         if (!strcmp(n->name, "server"))
375         {
376             struct conf_server *tmp = parse_server(n);
377             if (!tmp)
378                 return 0;
379             tmp->next = r->servers;
380             r->servers = tmp;
381         }
382         else if (!strcmp(n->name, "queryprofile"))
383         {
384         }
385         else if (!strcmp(n->name, "retrievalprofile"))
386         {
387             if (!(*rp = parse_retrievalprofile(n)))
388                 return 0;
389             rp = &(*rp)->next;
390         }
391         else
392         {
393             yaz_log(YLOG_FATAL, "Bad element: %s", n->name);
394             return 0;
395         }
396     }
397     return r;
398 }
399
400 int read_config(const char *fname)
401 {
402     xmlDoc *doc = xmlReadFile(fname, NULL, 0);
403     const char *p;
404
405     if (!nmem)  // Initialize
406     {
407         nmem = nmem_create();
408         xmlSubstituteEntitiesDefault(1);
409         xmlLoadExtDtdDefaultValue = 1;
410     }
411     if (!doc)
412     {
413         yaz_log(YLOG_FATAL, "Failed to read %s", fname);
414         exit(1);
415     }
416     if ((p = rindex(fname, '/')))
417     {
418         int len = p - fname;
419         strncpy(confdir, fname, len);
420         confdir[len] = '\0';
421     }
422     config = parse_config(xmlDocGetRootElement(doc));
423     xmlFreeDoc(doc);
424
425     if (config)
426         return 1;
427     else
428         return 0;
429 }
430
431
432 /*
433  * Local variables:
434  * c-basic-offset: 4
435  * indent-tabs-mode: nil
436  * End:
437  * vim: shiftwidth=4 tabstop=8 expandtab
438  */