Reorganized header files so that a certain subset are public. These
[idzebra-moved-to-github.git] / data1 / d1_absyn.c
1 /* $Id: d1_absyn.c,v 1.12 2004-09-28 10:15:02 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <yaz/oid.h>
29 #include <yaz/log.h>
30 #include <idzebra/data1.h>
31 #include <zebra_xpath.h>
32 #include <d1_absyn.h>
33
34 #define D1_MAX_NESTING  128
35
36 #if PRIVATE_DATA1_ABSYN
37 #endif
38
39 struct data1_systag {
40     char *name;
41     char *value;
42     struct data1_systag *next;
43 };
44
45 struct data1_absyn_cache_info 
46 {
47     char *name;
48     data1_absyn *absyn;
49     data1_absyn_cache next;
50 };
51
52 struct data1_attset_cache_info 
53 {
54     char *name;
55     data1_attset *attset;
56     data1_attset_cache next;
57 };
58
59 data1_absyn *data1_absyn_search (data1_handle dh, const char *name)
60 {
61     data1_absyn_cache p = *data1_absyn_cache_get (dh);
62
63     while (p)
64     {
65         if (!yaz_matchstr (name, p->name))
66             return p->absyn;
67         p = p->next;
68     }
69     return NULL;
70 }
71 /* *ostrich*
72    We need to destroy DFAs, in xp_element (xelm) definitions 
73    pop, 2002-12-13
74 */
75
76 void data1_absyn_destroy (data1_handle dh)
77 {
78     data1_absyn_cache p = *data1_absyn_cache_get (dh);
79     
80     while (p)
81     {
82         data1_absyn *abs = p->absyn;
83         if (abs)
84         {
85             data1_xpelement *xpe = abs->xp_elements;
86             while (xpe) {
87                 logf (LOG_DEBUG,"Destroy xp element %s",xpe->xpath_expr);
88                 if (xpe->dfa) {  dfa_delete (&xpe->dfa); }
89                 xpe = xpe->next;
90             } 
91         }
92         p = p->next;
93     }
94 }
95
96
97 void data1_absyn_trav (data1_handle dh, void *handle,
98                        void (*fh)(data1_handle dh, void *h, data1_absyn *a))
99 {
100     data1_absyn_cache p = *data1_absyn_cache_get (dh);
101
102     while (p)
103     {
104         (*fh)(dh, handle, p->absyn);
105         p = p->next;
106     }
107 }
108
109 data1_absyn *data1_absyn_add (data1_handle dh, const char *name)
110 {
111     char fname[512];
112     NMEM mem = data1_nmem_get (dh);
113
114     data1_absyn_cache p = (data1_absyn_cache)nmem_malloc (mem, sizeof(*p));
115     data1_absyn_cache *pp = data1_absyn_cache_get (dh);
116
117     sprintf(fname, "%s.abs", name);
118     p->absyn = data1_read_absyn (dh, fname, 0);
119     p->name = nmem_strdup (mem, name);
120     p->next = *pp;
121     *pp = p;
122     return p->absyn;
123 }
124
125 data1_absyn *data1_get_absyn (data1_handle dh, const char *name)
126 {
127     data1_absyn *absyn;
128
129     if (!(absyn = data1_absyn_search (dh, name)))
130         absyn = data1_absyn_add (dh, name);
131     return absyn;
132 }
133
134 data1_attset *data1_attset_search_name (data1_handle dh, const char *name)
135 {
136     data1_attset_cache p = *data1_attset_cache_get (dh);
137
138     while (p)
139     {
140         if (!yaz_matchstr (name, p->name))
141             return p->attset;
142         p = p->next;
143     }
144     return NULL;
145 }
146
147 data1_attset *data1_attset_search_id (data1_handle dh, int id)
148 {
149     data1_attset_cache p = *data1_attset_cache_get (dh);
150
151     while (p)
152     {
153         if (id == p->attset->reference)
154             return p->attset;
155         p = p->next;
156     }
157     return NULL;
158 }
159
160 data1_attset *data1_attset_add (data1_handle dh, const char *name)
161 {
162     char fname[512], aname[512];
163     NMEM mem = data1_nmem_get (dh);
164     data1_attset *attset;
165
166     strcpy (aname, name);
167     sprintf(fname, "%s.att", name);
168     attset = data1_read_attset (dh, fname);
169     if (!attset)
170     {
171         char *cp;
172         attset = data1_read_attset (dh, name);
173         if (attset && (cp = strrchr (aname, '.')))
174             *cp = '\0';
175     }
176     if (!attset)
177         yaz_log (LOG_WARN|LOG_ERRNO, "Couldn't load attribute set %s", name);
178     else
179     {
180         data1_attset_cache p = (data1_attset_cache)
181             nmem_malloc (mem, sizeof(*p));
182         data1_attset_cache *pp = data1_attset_cache_get (dh);
183         
184         attset->name = p->name = nmem_strdup (mem, aname);
185         p->attset = attset;
186         p->next = *pp;
187         *pp = p;
188     }
189     return attset;
190 }
191
192 data1_attset *data1_get_attset (data1_handle dh, const char *name)
193 {
194     data1_attset *attset;
195
196     if (!(attset = data1_attset_search_name (dh, name)))
197         attset = data1_attset_add (dh, name);
198     return attset;
199 }
200
201 data1_esetname *data1_getesetbyname(data1_handle dh, data1_absyn *a,
202                                     const char *name)
203 {
204     data1_esetname *r;
205
206     for (r = a->esetnames; r; r = r->next)
207         if (!data1_matchstr(r->name, name))
208             return r;
209     return 0;
210 }
211
212 data1_element *data1_getelementbytagname (data1_handle dh, data1_absyn *abs,
213                                           data1_element *parent,
214                                           const char *tagname)
215 {
216     data1_element *r;
217
218     /* It's now possible to have a data1 tree with no abstract syntax */
219     if ( !abs )
220         return 0;
221
222     if (!parent)
223         r = abs->main_elements;
224     else
225         r = parent->children;
226
227     for (; r; r = r->next)
228     {
229         data1_name *n;
230
231         for (n = r->tag->names; n; n = n->next)
232             if (!data1_matchstr(tagname, n->name))
233                 return r;
234     }
235     return 0;
236 }
237
238 data1_element *data1_getelementbyname (data1_handle dh, data1_absyn *absyn,
239                                        const char *name)
240 {
241     data1_element *r;
242
243     /* It's now possible to have a data1 tree with no abstract syntax */
244     if ( !absyn )
245         return 0;
246     for (r = absyn->main_elements; r; r = r->next)
247         if (!data1_matchstr(r->name, name))
248             return r;
249     return 0;
250 }
251
252
253 void fix_element_ref (data1_handle dh, data1_absyn *absyn, data1_element *e)
254 {
255     /* It's now possible to have a data1 tree with no abstract syntax */
256     if ( !absyn )
257         return;
258
259     for (; e; e = e->next)
260     {
261         if (!e->sub_name)
262         {
263             if (e->children)
264                 fix_element_ref (dh, absyn, e->children);
265         }
266         else
267         {
268             data1_sub_elements *sub_e = absyn->sub_elements;
269             while (sub_e && strcmp (e->sub_name, sub_e->name))
270                 sub_e = sub_e->next;
271             if (sub_e)
272                 e->children = sub_e->elements;
273             else
274                 yaz_log (LOG_WARN, "Unresolved reference to sub-elements %s",
275                       e->sub_name);
276         }
277     }
278 }
279 /* *ostrich*
280
281    New function, a bit dummy now... I've seen it in zrpn.c... We should build
282    more clever regexps...
283
284
285       //a    ->    ^a/.*$
286       //a/b  ->    ^b/a/.*$
287       /a     ->    ^a/$
288       /a/b   ->    ^b/a/$
289
290       /      ->    none
291
292    pop, 2002-12-13
293
294    Now [] predicates are supported
295
296    pop, 2003-01-17
297
298  */
299
300 const char * mk_xpath_regexp (data1_handle dh, char *expr) 
301 {
302     char *p = expr;
303     char *pp;
304     char *s;
305     int abs = 1;
306     int i;
307     int j;
308     int e=0;
309     int is_predicate = 0;
310     
311     static char *stack[32];
312     static char res[1024];
313     char *r = "";
314     
315     if (*p != '/') { return (""); }
316     p++;
317     if (*p == '/') { abs=0; p++; }
318     
319     while (*p) {
320         i=0;
321         while (*p && !strchr("/",*p)) { 
322           i++; p++; 
323         }
324         stack[e] = (char *) nmem_malloc (data1_nmem_get (dh), i+1);
325         s = stack[e];
326         for (j=0; j< i; j++) {
327           pp = p-i+j;
328           if (*pp == '[') {
329             is_predicate=1;
330           }
331           else if (*pp == ']') {
332             is_predicate=0;
333           }
334           else {
335             if (!is_predicate) {
336               if (*pp == '*') 
337                  *s++ = '.';
338               *s++ = *pp;
339             }
340           }
341         }
342         *s = 0;
343         e++;
344         if (*p) {p++;}
345     }
346     e--;  p = &res[0]; i=0;
347     sprintf (p, "^"); p++;
348     while (e >= 0) {
349         /* !!! res size is not checked !!! */
350         sprintf (p, "%s/",stack[e]);
351         p += strlen(stack[e]) + 1;
352         e--;
353     }
354     if (!abs) { sprintf (p, ".*"); p+=2; }
355     sprintf (p, "$"); p++;
356     r = nmem_strdup (data1_nmem_get (dh), res);
357     yaz_log(LOG_DEBUG,"Got regexp: %s",r);
358     return (r);
359 }
360
361 /* *ostrich*
362
363    added arg xpelement... when called from xelm context, it's 1, saying
364    that ! means xpath, not element name as attribute name...
365
366    pop, 2002-12-13
367  */
368 static int parse_termlists (data1_handle dh, data1_termlist ***tpp,
369                             char *cp, const char *file, int lineno,
370                             const char *element_name, data1_absyn *res,
371                             int xpelement)
372 {
373     data1_termlist **tp = *tpp;
374     while(1)
375     {
376         char attname[512], structure[512];
377         char *source;
378         int r, i;
379         int level = 0;
380         structure[0] = '\0';
381         for (i = 0; cp[i] && i<sizeof(attname)-1; i++)
382             if (strchr(":,", cp[i]))
383                 break;
384             else
385                 attname[i] = cp[i];
386         if (i == 0)
387         {
388             if (*cp)
389                 yaz_log(LOG_WARN,
390                         "%s:%d: Syntax error in termlistspec '%s'",
391                         file, lineno, cp);
392             break;
393         }
394         attname[i] = '\0';
395         r = 1;
396         cp += i;
397         if (*cp == ':')
398             cp++;
399
400         for (i = 0; cp[i] && i<sizeof(structure)-1; i++)
401             if (level == 0 && strchr(",", cp[i]))
402                 break;
403             else
404             {
405                 structure[i] = cp[i];
406                 if (cp[i] == '(')
407                     level++;
408                 else if (cp[i] == ')')
409                     level--;
410             }
411         structure[i] = '\0';
412         if (i)
413             r = 2;
414         cp += i;
415         if (*cp)
416             cp++;  /* skip , */
417
418         *tp = (data1_termlist *)
419             nmem_malloc(data1_nmem_get(dh), sizeof(**tp));
420         (*tp)->next = 0;
421         
422         if (!xpelement) {
423             if (*attname == '!')
424                 strcpy(attname, element_name);
425         }
426         if (!((*tp)->att = data1_getattbyname(dh, res->attset,
427                                               attname))) {
428             if ((!xpelement) || (*attname != '!')) {
429                 yaz_log(LOG_WARN,
430                         "%s:%d: Couldn't find att '%s' in attset",
431                         file, lineno, attname);
432                 return -1;
433             } else {
434                 (*tp)->att = 0;
435             }
436         }
437         
438         if (r == 2 && (source = strchr(structure, ':')))
439             *source++ = '\0';   /* cut off structure .. */
440         else
441             source = "data";    /* ok: default is leaf data */
442         (*tp)->source = (char *)
443             nmem_strdup (data1_nmem_get (dh), source);
444         
445         if (r < 2) /* is the structure qualified? */
446             (*tp)->structure = "w";
447         else 
448             (*tp)->structure = (char *)
449                 nmem_strdup (data1_nmem_get (dh), structure);
450         tp = &(*tp)->next;
451     }
452
453     *tpp = tp;
454     return 0;
455 }
456
457 const char *data1_systag_lookup(data1_absyn *absyn, const char *tag,
458                                 const char *default_value)
459 {
460     struct data1_systag *p = absyn->systags;
461     for (; p; p = p->next)
462         if (!strcmp(p->name, tag))
463             return p->value;
464     return default_value;
465 }
466
467 #define l_isspace(c) ((c) == '\t' || (c) == ' ' || (c) == '\n' || (c) == '\r')
468
469 int read_absyn_line(FILE *f, int *lineno, char *line, int len,
470                     char *argv[], int num)
471 {
472     char *p;
473     int argc;
474     int quoted = 0;
475     
476     while ((p = fgets(line, len, f)))
477     {
478         (*lineno)++;
479         while (*p && l_isspace(*p))
480             p++;
481         if (*p && *p != '#')
482             break;
483     }
484     if (!p)
485         return 0;
486     
487     for (argc = 0; *p ; argc++)
488     {
489         if (*p == '#')  /* trailing comment */
490             break;
491         argv[argc] = p;
492         while (*p && !(l_isspace(*p) && !quoted)) {
493           if (*p =='"') quoted = 1 - quoted;
494           if (*p =='[') quoted = 1;
495           if (*p ==']') quoted = 0;
496           p++;
497         }
498         if (*p)
499         {
500             *(p++) = '\0';
501             while (*p && l_isspace(*p))
502                 p++;
503         }
504     }
505     return argc;
506 }
507
508 data1_marctab *data1_absyn_getmarctab(data1_handle dh, data1_absyn *absyn)
509 {
510     return absyn->marc;
511 }
512
513 YAZ_EXPORT data1_element *data1_absyn_getelements(data1_handle dh,
514                                                   data1_absyn *absyn)
515 {
516     return absyn->main_elements;
517 }
518
519 data1_absyn *data1_read_absyn (data1_handle dh, const char *file,
520                                int file_must_exist)
521 {
522     data1_sub_elements *cur_elements = NULL;
523     data1_xpelement *cur_xpelement = NULL;
524
525     data1_absyn *res = 0;
526     FILE *f;
527     data1_element **ppl[D1_MAX_NESTING];
528     data1_esetname **esetpp;
529     data1_maptab **maptabp;
530     data1_marctab **marcp;
531     data1_termlist *all = 0;
532     data1_attset_child **attset_childp;
533     data1_tagset **tagset_childp;
534     struct data1_systag **systagsp;
535     int level = 0;
536     int lineno = 0;
537     int argc;
538     char *argv[50], line[512];
539
540     if (!(f = data1_path_fopen(dh, file, "r")))
541     {
542         yaz_log(LOG_WARN|LOG_ERRNO, "Couldn't open %s", file);
543         if (file_must_exist)
544             return 0;
545     }
546     
547     res = (data1_absyn *) nmem_malloc(data1_nmem_get(dh), sizeof(*res));
548     res->name = 0;
549     res->reference = VAL_NONE;
550     res->tagset = 0;
551     res->encoding = 0;
552     res->enable_xpath_indexing = (f ? 0 : 1);
553     res->systags = 0;
554     systagsp = &res->systags;
555     tagset_childp = &res->tagset;
556
557     res->attset = data1_empty_attset (dh);
558     attset_childp =  &res->attset->children;
559
560     res->varset = 0;
561     res->esetnames = 0;
562     esetpp = &res->esetnames;
563     res->maptabs = 0;
564     maptabp = &res->maptabs;
565     res->marc = 0;
566     marcp = &res->marc;
567     res->sub_elements = NULL;
568     res->main_elements = NULL;
569     res->xp_elements = NULL;
570     
571     while (f && (argc = read_absyn_line(f, &lineno, line, 512, argv, 50)))
572     {
573         char *cmd = *argv;
574         if (!strcmp(cmd, "elm") || !strcmp(cmd, "element"))
575         {
576             data1_element *new_element;
577             int i;
578             char *p, *sub_p, *path, *name, *termlists;
579             int type, value;
580             data1_termlist **tp;
581
582             if (argc < 4)
583             {
584                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to elm", file, lineno);
585                 continue;
586             }
587             path = argv[1];
588             name = argv[2];
589             termlists = argv[3];
590
591             if (!cur_elements)
592             {
593                 cur_elements = (data1_sub_elements *)
594                     nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
595                 cur_elements->next = res->sub_elements;
596                 cur_elements->elements = NULL;
597                 cur_elements->name = "main";
598                 res->sub_elements = cur_elements;
599                 
600                 level = 0;
601                 ppl[level] = &cur_elements->elements;
602             }
603             p = path;
604             for (i = 1;; i++)
605             {
606                 char *e;
607
608                 if ((e = strchr(p, '/')))
609                     p = e+1;
610                 else
611                     break;
612             }
613             if (i > level+1)
614             {
615                 yaz_log(LOG_WARN, "%s:%d: Bad level increase", file, lineno);
616                 fclose(f);
617                 return 0;
618             }
619             level = i;
620             new_element = *ppl[level-1] = (data1_element *)
621                 nmem_malloc(data1_nmem_get(dh), sizeof(*new_element));
622             new_element->next = new_element->children = 0;
623             new_element->tag = 0;
624             new_element->termlists = 0;
625             new_element->sub_name = 0;
626             
627             tp = &new_element->termlists;
628             ppl[level-1] = &new_element->next;
629             ppl[level] = &new_element->children;
630             
631             /* consider subtree (if any) ... */
632             if ((sub_p = strchr (p, ':')) && sub_p[1])
633             {
634                 *sub_p++ = '\0';
635                 new_element->sub_name =
636                     nmem_strdup (data1_nmem_get(dh), sub_p);            
637             }
638             /* well-defined tag */
639             if (sscanf(p, "(%d,%d)", &type, &value) == 2)
640             {
641                 if (!res->tagset)
642                 {
643                     yaz_log(LOG_WARN, "%s:%d: No tagset loaded", file, lineno);
644                     fclose(f);
645                     return 0;
646                 }
647                 if (!(new_element->tag = data1_gettagbynum (dh, res->tagset,
648                                                             type, value)))
649                 {
650                     yaz_log(LOG_WARN, "%s:%d: Couldn't find tag %s in tagset",
651                          file, lineno, p);
652                     fclose(f);
653                     return 0;
654                 }
655             }
656             /* private tag */
657             else if (*p)
658             {
659                 data1_tag *nt =
660                     new_element->tag = (data1_tag *)
661                     nmem_malloc(data1_nmem_get (dh),
662                                 sizeof(*new_element->tag));
663                 nt->which = DATA1T_string;
664                 nt->value.string = nmem_strdup(data1_nmem_get (dh), p);
665                 nt->names = (data1_name *)
666                     nmem_malloc(data1_nmem_get(dh), 
667                                 sizeof(*new_element->tag->names));
668                 nt->names->name = nt->value.string;
669                 nt->names->next = 0;
670                 nt->kind = DATA1K_string;
671                 nt->next = 0;
672                 nt->tagset = 0;
673             }
674             else
675             {
676                 yaz_log(LOG_WARN, "%s:%d: Bad element", file, lineno);
677                 fclose(f);
678                 return 0;
679             }
680             /* parse termList definitions */
681             p = termlists;
682             if (*p != '-')
683             {
684                 assert (res->attset);
685                 
686                 if (parse_termlists (dh, &tp, p, file, lineno, name, res, 0))
687                 {
688                     fclose (f);
689                     return 0;
690                 }
691                 *tp = all; /* append any ALL entries to the list */
692             }
693             new_element->name = nmem_strdup(data1_nmem_get (dh), name);
694         }
695         /* *ostrich*
696            New code to support xelm directive
697            for each xelm a dfa is built. xelms are stored in res->xp_elements
698            
699            maybe we should use a simple sscanf instead of dfa?
700            
701            pop, 2002-12-13
702
703            Now [] predicates are supported. regexps and xpath structure is
704            a bit redundant, however it's comfortable later...
705
706            pop, 2003-01-17
707         */
708
709         else if (!strcmp(cmd, "xelm")) {
710
711             int i;
712             char *p, *xpath_expr, *termlists;
713             const char *regexp;
714             struct DFA *dfa = dfa = dfa_init();
715             data1_termlist **tp;
716             
717             if (argc < 3)
718             {
719                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to xelm", file, lineno);
720                 continue;
721             }
722             xpath_expr = argv[1];
723             termlists = argv[2];
724             regexp = mk_xpath_regexp(dh, xpath_expr);
725             i = dfa_parse (dfa, &regexp);
726             if (i || *regexp) {
727                 yaz_log(LOG_WARN, "%s:%d: Bad xpath to xelm", file, lineno);
728                 dfa_delete (&dfa);
729                 continue;
730             }
731             
732             if (!cur_xpelement)
733             {
734                 cur_xpelement = (data1_xpelement *)
735                     nmem_malloc(data1_nmem_get(dh), sizeof(*cur_xpelement));
736                 res->xp_elements = cur_xpelement;
737             } else {
738                 cur_xpelement->next = (data1_xpelement *)
739                     nmem_malloc(data1_nmem_get(dh), sizeof(*cur_xpelement));
740                 cur_xpelement = cur_xpelement->next;
741             }
742             cur_xpelement->next = NULL;
743             cur_xpelement->xpath_expr = nmem_strdup(data1_nmem_get (dh), 
744                                                     xpath_expr); 
745             
746             dfa_mkstate (dfa);
747             cur_xpelement->dfa = dfa;
748
749 #ifdef ENHANCED_XELM 
750             cur_xpelement->xpath_len =
751                 zebra_parse_xpath_str(xpath_expr, 
752                                       cur_xpelement->xpath, XPATH_STEP_COUNT,
753                                       data1_nmem_get(dh));
754             
755             /*
756             dump_xp_steps(cur_xpelement->xpath,cur_xpelement->xpath_len);
757             */
758 #endif
759             cur_xpelement->termlists = 0;
760             tp = &cur_xpelement->termlists;
761             
762             /* parse termList definitions */
763             p = termlists;
764             if (*p != '-')
765             {
766                 assert (res->attset);
767                 
768                 if (parse_termlists (dh, &tp, p, file, lineno,
769                                      xpath_expr, res, 1))
770                 {
771                     fclose (f);
772                     return 0;
773                 }
774                 *tp = all; /* append any ALL entries to the list */
775             }
776         }
777         else if (!strcmp(cmd, "section"))
778         {
779             char *name;
780             
781             if (argc < 2)
782             {
783                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to section",
784                         file, lineno);
785                 continue;
786             }
787             name = argv[1];
788             
789             cur_elements = (data1_sub_elements *)
790                 nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
791             cur_elements->next = res->sub_elements;
792             cur_elements->elements = NULL;
793             cur_elements->name = nmem_strdup (data1_nmem_get(dh), name);
794             res->sub_elements = cur_elements;
795             
796             level = 0;
797             ppl[level] = &cur_elements->elements;
798         }
799         else if (!strcmp(cmd, "xpath"))
800         {
801             if (argc != 2)
802             {
803                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'xpath' directive",
804                      file, lineno);
805                 continue;
806             }
807             if (!strcmp(argv[1], "enable"))
808                 res->enable_xpath_indexing = 1;
809             else if (!strcmp (argv[1], "disable"))
810                 res->enable_xpath_indexing = 0;
811             else
812             {
813                 yaz_log(LOG_WARN, "%s:%d: Expecting disable/enable "
814                         "after 'xpath' directive", file, lineno);
815             }
816         }
817         else if (!strcmp(cmd, "all"))
818         {
819             data1_termlist **tp = &all;
820             if (all)
821             {
822                 yaz_log(LOG_WARN, "%s:%d: Too many 'all' directives - ignored",
823                      file, lineno);
824                 continue;
825             }
826             if (argc != 2)
827             {
828                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'all' directive",
829                      file, lineno);
830                 continue;
831             }
832             if (parse_termlists (dh, &tp, argv[1], file, lineno, 0, res, 0))
833             {
834                 fclose (f);
835                 return 0;
836             }
837         }
838         else if (!strcmp(cmd, "name"))
839         {
840             if (argc != 2)
841             {
842                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to name directive",
843                      file, lineno);
844                 continue;
845             }
846             res->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
847         }
848         else if (!strcmp(cmd, "reference"))
849         {
850             char *name;
851             
852             if (argc != 2)
853             {
854                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to reference",
855                      file, lineno);
856                 continue;
857             }
858             name = argv[1];
859             if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
860             {
861                 yaz_log(LOG_WARN, "%s:%d: Unknown tagset ref '%s'", 
862                      file, lineno, name);
863                 continue;
864             }
865         }
866         else if (!strcmp(cmd, "attset"))
867         {
868             char *name;
869             data1_attset *attset;
870             
871             if (argc != 2)
872             {
873                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to attset",
874                      file, lineno);
875                 continue;
876             }
877             name = argv[1];
878             if (!(attset = data1_get_attset (dh, name)))
879             {
880                 yaz_log(LOG_WARN, "%s:%d: Couldn't find attset  %s",
881                      file, lineno, name);
882                 continue;
883             }
884             *attset_childp = (data1_attset_child *)
885                 nmem_malloc (data1_nmem_get(dh), sizeof(**attset_childp));
886             (*attset_childp)->child = attset;
887             (*attset_childp)->next = 0;
888             attset_childp = &(*attset_childp)->next;
889         }
890         else if (!strcmp(cmd, "tagset"))
891         {
892             char *name;
893             int type = 0;
894             if (argc < 2)
895             {
896                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to tagset",
897                      file, lineno);
898                 continue;
899             }
900             name = argv[1];
901             if (argc == 3)
902                 type = atoi(argv[2]);
903             *tagset_childp = data1_read_tagset (dh, name, type);
904             if (!(*tagset_childp))
905             {
906                 yaz_log(LOG_WARN, "%s:%d: Couldn't load tagset %s",
907                      file, lineno, name);
908                 continue;
909             }
910             tagset_childp = &(*tagset_childp)->next;
911         }
912         else if (!strcmp(cmd, "varset"))
913         {
914             char *name;
915
916             if (argc != 2)
917             {
918                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in varset",
919                      file, lineno);
920                 continue;
921             }
922             name = argv[1];
923             if (!(res->varset = data1_read_varset (dh, name)))
924             {
925                 yaz_log(LOG_WARN, "%s:%d: Couldn't load Varset %s",
926                      file, lineno, name);
927                 continue;
928             }
929         }
930         else if (!strcmp(cmd, "esetname"))
931         {
932             char *name, *fname;
933
934             if (argc != 3)
935             {
936                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in esetname",
937                      file, lineno);
938                 continue;
939             }
940             name = argv[1];
941             fname = argv[2];
942             
943             *esetpp = (data1_esetname *)
944                 nmem_malloc(data1_nmem_get(dh), sizeof(**esetpp));
945             (*esetpp)->name = nmem_strdup(data1_nmem_get(dh), name);
946             (*esetpp)->next = 0;
947             if (*fname == '@')
948                 (*esetpp)->spec = 0;
949             else if (!((*esetpp)->spec = data1_read_espec1 (dh, fname)))
950             {
951                 yaz_log(LOG_WARN, "%s:%d: Espec-1 read failed for %s",
952                      file, lineno, fname);
953                 continue;
954             }
955             esetpp = &(*esetpp)->next;
956         }
957         else if (!strcmp(cmd, "maptab"))
958         {
959             char *name;
960             
961             if (argc != 2)
962             {
963                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for maptab",
964                      file, lineno);
965                 continue;
966             }
967             name = argv[1];
968             if (!(*maptabp = data1_read_maptab (dh, name)))
969             {
970                 yaz_log(LOG_WARN, "%s:%d: Couldn't load maptab %s",
971                      file, lineno, name);
972                 continue;
973             }
974             maptabp = &(*maptabp)->next;
975         }
976         else if (!strcmp(cmd, "marc"))
977         {
978             char *name;
979             
980             if (argc != 2)
981             {
982                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for marc",
983                      file, lineno);
984                 continue;
985             }
986             name = argv[1];
987             if (!(*marcp = data1_read_marctab (dh, name)))
988             {
989                 yaz_log(LOG_WARN, "%s:%d: Couldn't read marctab %s",
990                      file, lineno, name);
991                 continue;
992             }
993             marcp = &(*marcp)->next;
994         }
995         else if (!strcmp(cmd, "encoding"))
996         {
997             if (argc != 2)
998             {
999                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for encoding",
1000                      file, lineno);
1001                 continue;
1002             }
1003             res->encoding = nmem_strdup (data1_nmem_get(dh), argv[1]);
1004         }
1005         else if (!strcmp(cmd, "systag"))
1006         {
1007             if (argc != 3)
1008             {
1009                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for systag",
1010                      file, lineno);
1011                 continue;
1012             }
1013             *systagsp = nmem_malloc (data1_nmem_get(dh), sizeof(**systagsp));
1014
1015             (*systagsp)->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
1016             (*systagsp)->value = nmem_strdup(data1_nmem_get(dh), argv[2]);
1017             systagsp = &(*systagsp)->next;
1018         }
1019         else
1020         {
1021             yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'", file, 
1022                     lineno, cmd);
1023             continue;
1024         }
1025     }
1026     if (f)
1027         fclose(f);
1028     
1029     for (cur_elements = res->sub_elements; cur_elements;
1030          cur_elements = cur_elements->next)
1031     {
1032         if (!strcmp (cur_elements->name, "main"))
1033             res->main_elements = cur_elements->elements;
1034         fix_element_ref (dh, res, cur_elements->elements);
1035     }
1036     *systagsp = 0;
1037     yaz_log (LOG_DEBUG, "%s: data1_read_absyn end", file);
1038     return res;
1039 }