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