xelm
[idzebra-moved-to-github.git] / data1 / d1_absyn.c
1 /* $Id: d1_absyn.c,v 1.4 2002-12-16 20:27:18 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         }
647         else if (!strcmp(cmd, "section"))
648         {
649             char *name;
650             
651             if (argc < 2)
652             {
653                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to section",
654                         file, lineno);
655                 continue;
656             }
657             name = argv[1];
658             
659             cur_elements = (data1_sub_elements *)
660                 nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
661             cur_elements->next = res->sub_elements;
662             cur_elements->elements = NULL;
663             cur_elements->name = nmem_strdup (data1_nmem_get(dh), name);
664             res->sub_elements = cur_elements;
665             
666             level = 0;
667             ppl[level] = &cur_elements->elements;
668         }
669         else if (!strcmp(cmd, "xpath"))
670         {
671             if (argc != 2)
672             {
673                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'xpath' directive",
674                      file, lineno);
675                 continue;
676             }
677             if (!strcmp(argv[1], "enable"))
678                 res->enable_xpath_indexing = 1;
679             else if (!strcmp (argv[1], "disable"))
680                 res->enable_xpath_indexing = 0;
681             else
682             {
683                 yaz_log(LOG_WARN, "%s:%d: Expecting disable/enable "
684                         "after 'xpath' directive", file, lineno);
685             }
686         }
687         else if (!strcmp(cmd, "all"))
688         {
689             data1_termlist **tp = &all;
690             if (all)
691             {
692                 yaz_log(LOG_WARN, "%s:%d: Too many 'all' directives - ignored",
693                      file, lineno);
694                 continue;
695             }
696             if (argc != 2)
697             {
698                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'all' directive",
699                      file, lineno);
700                 continue;
701             }
702             if (parse_termlists (dh, &tp, argv[1], file, lineno, 0, res, 0))
703             {
704                 fclose (f);
705                 return 0;
706             }
707         }
708         else if (!strcmp(cmd, "name"))
709         {
710             if (argc != 2)
711             {
712                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to name directive",
713                      file, lineno);
714                 continue;
715             }
716             res->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
717         }
718         else if (!strcmp(cmd, "reference"))
719         {
720             char *name;
721             
722             if (argc != 2)
723             {
724                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to reference",
725                      file, lineno);
726                 continue;
727             }
728             name = argv[1];
729             if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
730             {
731                 yaz_log(LOG_WARN, "%s:%d: Unknown tagset ref '%s'", 
732                      file, lineno, name);
733                 continue;
734             }
735         }
736         else if (!strcmp(cmd, "attset"))
737         {
738             char *name;
739             data1_attset *attset;
740             
741             if (argc != 2)
742             {
743                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to attset",
744                      file, lineno);
745                 continue;
746             }
747             name = argv[1];
748             if (!(attset = data1_get_attset (dh, name)))
749             {
750                 yaz_log(LOG_WARN, "%s:%d: Couldn't find attset  %s",
751                      file, lineno, name);
752                 continue;
753             }
754             *attset_childp = (data1_attset_child *)
755                 nmem_malloc (data1_nmem_get(dh), sizeof(**attset_childp));
756             (*attset_childp)->child = attset;
757             (*attset_childp)->next = 0;
758             attset_childp = &(*attset_childp)->next;
759         }
760         else if (!strcmp(cmd, "tagset"))
761         {
762             char *name;
763             int type = 0;
764             if (argc < 2)
765             {
766                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to tagset",
767                      file, lineno);
768                 continue;
769             }
770             name = argv[1];
771             if (argc == 3)
772                 type = atoi(argv[2]);
773             *tagset_childp = data1_read_tagset (dh, name, type);
774             if (!(*tagset_childp))
775             {
776                 yaz_log(LOG_WARN, "%s:%d: Couldn't load tagset %s",
777                      file, lineno, name);
778                 continue;
779             }
780             tagset_childp = &(*tagset_childp)->next;
781         }
782         else if (!strcmp(cmd, "varset"))
783         {
784             char *name;
785
786             if (argc != 2)
787             {
788                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in varset",
789                      file, lineno);
790                 continue;
791             }
792             name = argv[1];
793             if (!(res->varset = data1_read_varset (dh, name)))
794             {
795                 yaz_log(LOG_WARN, "%s:%d: Couldn't load Varset %s",
796                      file, lineno, name);
797                 continue;
798             }
799         }
800         else if (!strcmp(cmd, "esetname"))
801         {
802             char *name, *fname;
803
804             if (argc != 3)
805             {
806                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in esetname",
807                      file, lineno);
808                 continue;
809             }
810             name = argv[1];
811             fname = argv[2];
812             
813             *esetpp = (data1_esetname *)
814                 nmem_malloc(data1_nmem_get(dh), sizeof(**esetpp));
815             (*esetpp)->name = nmem_strdup(data1_nmem_get(dh), name);
816             (*esetpp)->next = 0;
817             if (*fname == '@')
818                 (*esetpp)->spec = 0;
819             else if (!((*esetpp)->spec = data1_read_espec1 (dh, fname)))
820             {
821                 yaz_log(LOG_WARN, "%s:%d: Espec-1 read failed for %s",
822                      file, lineno, fname);
823                 continue;
824             }
825             esetpp = &(*esetpp)->next;
826         }
827         else if (!strcmp(cmd, "maptab"))
828         {
829             char *name;
830             
831             if (argc != 2)
832             {
833                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for maptab",
834                      file, lineno);
835                 continue;
836             }
837             name = argv[1];
838             if (!(*maptabp = data1_read_maptab (dh, name)))
839             {
840                 yaz_log(LOG_WARN, "%s:%d: Couldn't load maptab %s",
841                      file, lineno, name);
842                 continue;
843             }
844             maptabp = &(*maptabp)->next;
845         }
846         else if (!strcmp(cmd, "marc"))
847         {
848             char *name;
849             
850             if (argc != 2)
851             {
852                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for marc",
853                      file, lineno);
854                 continue;
855             }
856             name = argv[1];
857             if (!(*marcp = data1_read_marctab (dh, name)))
858             {
859                 yaz_log(LOG_WARN, "%s:%d: Couldn't read marctab %s",
860                      file, lineno, name);
861                 continue;
862             }
863             marcp = &(*marcp)->next;
864         }
865         else if (!strcmp(cmd, "encoding"))
866         {
867             if (argc != 2)
868             {
869                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for encoding",
870                      file, lineno);
871                 continue;
872             }
873             res->encoding = nmem_strdup (data1_nmem_get(dh), argv[1]);
874         }
875         else if (!strcmp(cmd, "systag"))
876         {
877             struct data1_systag *st;
878             if (argc != 3)
879             {
880                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for systag",
881                      file, lineno);
882                 continue;
883             }
884             *systagsp = nmem_malloc (data1_nmem_get(dh), sizeof(**systagsp));
885
886             (*systagsp)->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
887             (*systagsp)->value = nmem_strdup(data1_nmem_get(dh), argv[2]);
888             systagsp = &(*systagsp)->next;
889         }
890         else
891         {
892             yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'", file, 
893                     lineno, cmd);
894             continue;
895         }
896     }
897     if (f)
898         fclose(f);
899     
900     for (cur_elements = res->sub_elements; cur_elements;
901          cur_elements = cur_elements->next)
902     {
903         if (!strcmp (cur_elements->name, "main"))
904             res->main_elements = cur_elements->elements;
905         fix_element_ref (dh, res, cur_elements->elements);
906     }
907     *systagsp = 0;
908     yaz_log (LOG_DEBUG, "%s: data1_read_absyn end", file);
909     return res;
910 }