c664825a57a0741d1e46c39d3f11ebde0a9032e1
[yaz-moved-to-github.git] / retrieval / d1_absyn.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_absyn.c,v $
7  * Revision 1.28  2000-12-05 12:21:45  adam
8  * Added termlist source for data1 system.
9  *
10  * Revision 1.27  1999/12/21 14:16:19  ian
11  * Changed retrieval module to allow data1 trees with no associated absyn.
12  * Also added a simple interface for extracting values from data1 trees using
13  * a string based tagpath.
14  *
15  * Revision 1.26  1999/11/30 13:47:12  adam
16  * Improved installation. Moved header files to include/yaz.
17  *
18  * Revision 1.25  1999/10/21 12:06:29  adam
19  * Retrieval module no longer uses ctype.h - functions.
20  *
21  * Revision 1.24  1999/08/27 09:40:32  adam
22  * Renamed logf function to yaz_log. Removed VC++ project files.
23  *
24  * Revision 1.23  1998/10/15 08:29:16  adam
25  * Tag set type may be specified in reference to it using "tagset"
26  * directive in .abs-files and "include" directive in .tag-files.
27  *
28  * Revision 1.22  1998/10/13 16:09:47  adam
29  * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
30  * Added support for multiple attribute set references and tagset references
31  * from an abstract syntax file.
32  * Fixed many bad logs-calls in routines that read the various
33  * specifications regarding data1 (*.abs,*.att,...) and made the messages
34  * consistent whenever possible.
35  * Added extra 'lineno' argument to function readconf_line.
36  *
37  * Revision 1.21  1998/06/09 13:55:07  adam
38  * Minor changes.
39  *
40  * Revision 1.20  1998/05/18 13:07:02  adam
41  * Changed the way attribute sets are handled by the retriaval module.
42  * Extended Explain conversion / schema.
43  * Modified server and client to work with ASN.1 compiled protocol handlers.
44  *
45  * Revision 1.19  1998/03/05 08:15:32  adam
46  * Implemented data1_add_insert_taggeddata utility which is more flexible
47  * than data1_insert_taggeddata.
48  *
49  * Revision 1.18  1998/02/27 14:08:04  adam
50  * Added const to some char pointer arguments.
51  * Reworked data1_read_node so that it doesn't create a tree with
52  * pointers to original "SGML"-buffer.
53  *
54  * Revision 1.17  1998/02/11 11:53:34  adam
55  * Changed code so that it compiles as C++.
56  *
57  * Revision 1.16  1997/12/18 10:51:30  adam
58  * Implemented sub-trees feature for schemas - including forward
59  * references.
60  *
61  * Revision 1.15  1997/12/09 16:18:16  adam
62  * Work on EXPLAIN schema. First implementation of sub-schema facility
63  * in the *.abs files.
64  *
65  * Revision 1.14  1997/10/31 12:20:09  adam
66  * Improved memory debugging for xmalloc/nmem.c. References to NMEM
67  * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
68  * Bug fix: missing fclose in data1_read_espec1.
69  *
70  * Revision 1.13  1997/10/27 13:54:18  adam
71  * Changed structure field in data1 node to be simple string which
72  * is "unknown" to the retrieval system itself.
73  *
74  * Revision 1.12  1997/09/17 12:10:34  adam
75  * YAZ version 1.4.
76  *
77  * Revision 1.11  1997/09/05 09:50:55  adam
78  * Removed global data1_tabpath - uses data1_get_tabpath() instead.
79  *
80  * Revision 1.10  1997/05/14 06:54:01  adam
81  * C++ support.
82  *
83  * Revision 1.9  1997/02/19 14:46:15  adam
84  * The "all" specifier only affects elements that are indexed (and not
85  * all elements).
86  *
87  * Revision 1.8  1997/01/02 10:47:59  quinn
88  * Added optional, physical ANY
89  *
90  * Revision 1.7  1996/06/10 08:56:01  quinn
91  * Work on Summary.
92  *
93  * Revision 1.6  1996/05/31  13:52:21  quinn
94  * Fixed uninitialized variable for local tags in abstract syntax.
95  *
96  * Revision 1.5  1996/05/09  07:27:43  quinn
97  * Multiple local attributes values supported.
98  *
99  * Revision 1.4  1996/05/01  12:45:28  quinn
100  * Support use of local tag names in abs file.
101  *
102  * Revision 1.3  1995/11/01  16:34:55  quinn
103  * Making data1 look for tables in data1_tabpath
104  *
105  * Revision 1.2  1995/11/01  13:54:44  quinn
106  * Minor adjustments
107  *
108  * Revision 1.1  1995/11/01  11:56:06  quinn
109  * Added Retrieval (data management) functions en masse.
110  *
111  */
112
113 #include <stdio.h>
114 #include <assert.h>
115 #include <stdlib.h>
116 #include <string.h>
117
118 #include <yaz/oid.h>
119 #include <yaz/log.h>
120 #include <yaz/data1.h>
121
122 #define D1_MAX_NESTING  128
123
124 struct data1_absyn_cache_info 
125 {
126     char *name;
127     data1_absyn *absyn;
128     data1_absyn_cache next;
129 };
130
131 struct data1_attset_cache_info 
132 {
133     char *name;
134     data1_attset *attset;
135     data1_attset_cache next;
136 };
137
138 data1_absyn *data1_absyn_search (data1_handle dh, const char *name)
139 {
140     data1_absyn_cache p = *data1_absyn_cache_get (dh);
141
142     while (p)
143     {
144         if (!strcmp (name, p->name))
145             return p->absyn;
146         p = p->next;
147     }
148     return NULL;
149 }
150
151 void data1_absyn_trav (data1_handle dh, void *handle,
152                        void (*fh)(data1_handle dh, void *h, data1_absyn *a))
153 {
154     data1_absyn_cache p = *data1_absyn_cache_get (dh);
155
156     while (p)
157     {
158         (*fh)(dh, handle, p->absyn);
159         p = p->next;
160     }
161 }
162
163 data1_absyn *data1_absyn_add (data1_handle dh, const char *name)
164 {
165     char fname[512];
166     NMEM mem = data1_nmem_get (dh);
167
168     data1_absyn_cache p = (data1_absyn_cache)nmem_malloc (mem, sizeof(*p));
169     data1_absyn_cache *pp = data1_absyn_cache_get (dh);
170
171     sprintf(fname, "%s.abs", name);
172     p->absyn = data1_read_absyn (dh, fname);
173     p->name = nmem_strdup (mem, name);
174     p->next = *pp;
175     *pp = p;
176     return p->absyn;
177 }
178
179 data1_absyn *data1_get_absyn (data1_handle dh, const char *name)
180 {
181     data1_absyn *absyn;
182
183     if (!(absyn = data1_absyn_search (dh, name)))
184         absyn = data1_absyn_add (dh, name);
185     return absyn;
186 }
187
188 data1_attset *data1_attset_search_name (data1_handle dh, const char *name)
189 {
190     data1_attset_cache p = *data1_attset_cache_get (dh);
191
192     while (p)
193     {
194         if (!strcmp (name, p->name))
195             return p->attset;
196         p = p->next;
197     }
198     return NULL;
199 }
200
201 data1_attset *data1_attset_search_id (data1_handle dh, int id)
202 {
203     data1_attset_cache p = *data1_attset_cache_get (dh);
204
205     while (p)
206     {
207         if (id == p->attset->reference)
208             return p->attset;
209         p = p->next;
210     }
211     return NULL;
212 }
213
214 data1_attset *data1_attset_add (data1_handle dh, const char *name)
215 {
216     char fname[512], aname[512];
217     NMEM mem = data1_nmem_get (dh);
218     data1_attset *attset;
219
220     strcpy (aname, name);
221     sprintf(fname, "%s.att", name);
222     attset = data1_read_attset (dh, fname);
223     if (!attset)
224     {
225         char *cp;
226         attset = data1_read_attset (dh, name);
227         if (attset && (cp = strrchr (aname, '.')))
228             *cp = '\0';
229     }
230     if (!attset)
231         yaz_log (LOG_WARN|LOG_ERRNO, "Couldn't load attribute set %s", name);
232     else
233     {
234         data1_attset_cache p = (data1_attset_cache)
235             nmem_malloc (mem, sizeof(*p));
236         data1_attset_cache *pp = data1_attset_cache_get (dh);
237         
238         attset->name = p->name = nmem_strdup (mem, aname);
239         p->attset = attset;
240         p->next = *pp;
241         *pp = p;
242     }
243     return attset;
244 }
245
246 data1_attset *data1_get_attset (data1_handle dh, const char *name)
247 {
248     data1_attset *attset;
249
250     if (!(attset = data1_attset_search_name (dh, name)))
251         attset = data1_attset_add (dh, name);
252     return attset;
253 }
254
255 data1_esetname *data1_getesetbyname(data1_handle dh, data1_absyn *a,
256                                     const char *name)
257 {
258     data1_esetname *r;
259
260     for (r = a->esetnames; r; r = r->next)
261         if (!data1_matchstr(r->name, name))
262             return r;
263     return 0;
264 }
265
266 data1_element *data1_getelementbytagname (data1_handle dh, data1_absyn *abs,
267                                           data1_element *parent,
268                                           const char *tagname)
269 {
270     data1_element *r;
271
272     /* It's now possible to have a data1 tree with no abstract syntax */
273     if ( !abs )
274         return 0;
275
276     if (!parent)
277         r = abs->main_elements;
278     else
279         r = parent->children;
280     assert (abs->main_elements);
281     for (; r; r = r->next)
282     {
283         data1_name *n;
284
285         for (n = r->tag->names; n; n = n->next)
286             if (!data1_matchstr(tagname, n->name))
287                 return r;
288     }
289     return 0;
290 }
291
292 data1_element *data1_getelementbyname (data1_handle dh, data1_absyn *absyn,
293                                        const char *name)
294 {
295     data1_element *r;
296
297     /* It's now possible to have a data1 tree with no abstract syntax */
298     if ( !absyn )
299         return 0;
300     
301     assert (absyn->main_elements);
302     for (r = absyn->main_elements; r; r = r->next)
303         if (!data1_matchstr(r->name, name))
304             return r;
305     return 0;
306 }
307
308
309 void fix_element_ref (data1_handle dh, data1_absyn *absyn, data1_element *e)
310 {
311     /* It's now possible to have a data1 tree with no abstract syntax */
312     if ( !absyn )
313         return;
314
315     for (; e; e = e->next)
316     {
317         if (!e->sub_name)
318         {
319             if (e->children)
320                 fix_element_ref (dh, absyn, e->children);
321         }
322         else
323         {
324             data1_sub_elements *sub_e = absyn->sub_elements;
325             while (sub_e && strcmp (e->sub_name, sub_e->name))
326                 sub_e = sub_e->next;
327             if (sub_e)
328                 e->children = sub_e->elements;
329             else
330                 yaz_log (LOG_WARN, "Unresolved reference to sub-elements %s",
331                       e->sub_name);
332         }
333     }
334 }
335
336 data1_absyn *data1_read_absyn (data1_handle dh, const char *file)
337 {
338     data1_sub_elements *cur_elements = NULL;
339     data1_absyn *res = 0;
340     FILE *f;
341     data1_element **ppl[D1_MAX_NESTING];
342     data1_esetname **esetpp;
343     data1_maptab **maptabp;
344     data1_marctab **marcp;
345     data1_termlist *all = 0;
346     data1_attset_child **attset_childp;
347     data1_tagset **tagset_childp;
348     int level = 0;
349     int lineno = 0;
350     int argc;
351     char *argv[50], line[512];
352
353     if (!(f = yaz_path_fopen(data1_get_tabpath (dh), file, "r")))
354     {
355         yaz_log(LOG_WARN|LOG_ERRNO, "Couldn't open %s", file);
356         return 0;
357     }
358     
359     res = (data1_absyn *) nmem_malloc(data1_nmem_get(dh), sizeof(*res));
360     res->name = 0;
361     res->reference = VAL_NONE;
362     res->tagset = 0;
363     tagset_childp = &res->tagset;
364
365     res->attset = data1_empty_attset (dh);
366     attset_childp =  &res->attset->children;
367
368     res->varset = 0;
369     res->esetnames = 0;
370     esetpp = &res->esetnames;
371     res->maptabs = 0;
372     maptabp = &res->maptabs;
373     res->marc = 0;
374     marcp = &res->marc;
375
376     res->sub_elements = NULL;
377     res->main_elements = NULL;
378
379     while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
380     {
381         char *cmd = *argv;
382         if (!strcmp(cmd, "elm"))
383         {
384             data1_element *new_element;
385             int i;
386             char *p, *sub_p, *path, *name, *termlists;
387             int type, value;
388             data1_termlist **tp;
389
390             if (argc < 4)
391             {
392                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to elm", file, lineno);
393                 continue;
394             }
395             path = argv[1];
396             name = argv[2];
397             termlists = argv[3];
398
399             if (!cur_elements)
400             {
401                 cur_elements = (data1_sub_elements *)
402                     nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
403                 cur_elements->next = res->sub_elements;
404                 cur_elements->elements = NULL;
405                 cur_elements->name = "main";
406                 res->sub_elements = cur_elements;
407                 
408                 level = 0;
409                 ppl[level] = &cur_elements->elements;
410             }
411             p = path;
412             for (i = 0;; i++)
413             {
414                 char *e;
415
416                 if ((e = strchr(p, '/')))
417                     p = e+1;
418                 else
419                     break;
420             }
421             if (i > level + 1)
422             {
423                 yaz_log(LOG_WARN, "%s:%d: Bad level increase", file, lineno);
424                 fclose(f);
425                 return 0;
426             }
427             level = i;
428             new_element = *ppl[level] = (data1_element *)
429                 nmem_malloc(data1_nmem_get(dh), sizeof(*new_element));
430             new_element->next = new_element->children = 0;
431             new_element->tag = 0;
432             new_element->termlists = 0;
433             new_element->sub_name = 0;
434             
435             tp = &new_element->termlists;
436             ppl[level] = &new_element->next;
437             ppl[level+1] = &new_element->children;
438             
439             /* consider subtree (if any) ... */
440             if ((sub_p = strchr (p, ':')) && sub_p[1])
441             {
442                 *sub_p++ = '\0';
443                 new_element->sub_name =
444                     nmem_strdup (data1_nmem_get(dh), sub_p);            
445             }
446             /* well-defined tag */
447             if (sscanf(p, "(%d,%d)", &type, &value) == 2)
448             {
449                 if (!res->tagset)
450                 {
451                     yaz_log(LOG_WARN, "%s:%d: No tagset loaded", file, lineno);
452                     fclose(f);
453                     return 0;
454                 }
455                 if (!(new_element->tag = data1_gettagbynum (dh, res->tagset,
456                                                             type, value)))
457                 {
458                     yaz_log(LOG_WARN, "%s:%d: Couldn't find tag %s in tagset",
459                          file, lineno, p);
460                     fclose(f);
461                     return 0;
462                 }
463             }
464             /* private tag */
465             else if (*p)
466             {
467                 data1_tag *nt =
468                     new_element->tag = (data1_tag *)
469                     nmem_malloc(data1_nmem_get (dh),
470                                 sizeof(*new_element->tag));
471                 nt->which = DATA1T_string;
472                 nt->value.string = nmem_strdup(data1_nmem_get (dh), p);
473                 nt->names = (data1_name *)
474                     nmem_malloc(data1_nmem_get(dh), 
475                                 sizeof(*new_element->tag->names));
476                 nt->names->name = nt->value.string;
477                 nt->names->next = 0;
478                 nt->kind = DATA1K_string;
479                 nt->next = 0;
480                 nt->tagset = 0;
481             }
482             else
483             {
484                 yaz_log(LOG_WARN, "%s:%d: Bad element", file, lineno);
485                 fclose(f);
486                 return 0;
487             }
488             /* parse termList definitions */
489             p = termlists;
490             if (*p == '-')
491                 new_element->termlists = 0;
492             else
493             {
494                 assert (res->attset);
495                 do
496                 {
497                     char attname[512], structure[512];
498                     char *source;
499                     int r;
500                     
501                     if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
502                                      structure)))
503                     {
504                         yaz_log(LOG_WARN,
505                              "%s:%d: Syntax error in termlistspec '%s'",
506                              file, lineno, p);
507                         fclose(f);
508                         return 0;
509                     }
510                     if (*attname == '!')
511                         strcpy(attname, name);
512                     *tp = (data1_termlist *)
513                         nmem_malloc(data1_nmem_get(dh), sizeof(**tp));
514                     (*tp)->next = 0;
515                     if (!((*tp)->att = data1_getattbyname(dh, res->attset,
516                                                           attname)))
517                     {
518                         yaz_log(LOG_WARN,
519                              "%s:%d: Couldn't find att '%s' in attset",
520                              file, lineno, attname);
521                         fclose(f);
522                         return 0;
523                     }
524                     if (r == 2 && (source = strchr(structure, ':')))
525                         *source++ = '\0';   /* cut off structure .. */
526                     else
527                         source = "data";    /* ok: default is leaf data */
528                     (*tp)->source = (char *)
529                         nmem_strdup (data1_nmem_get (dh), source);
530
531                     if (r < 2) /* is the structure qualified? */
532                         (*tp)->structure = "w";
533                     else 
534                         (*tp)->structure = (char *)
535                             nmem_strdup (data1_nmem_get (dh), structure);
536                     tp = &(*tp)->next;
537                 }
538                 while ((p = strchr(p, ',')) && *(++p));
539                 *tp = all; /* append any ALL entries to the list */
540             }
541             new_element->name = nmem_strdup(data1_nmem_get (dh), name);
542         }
543         else if (!strcmp(cmd, "section"))
544         {
545             char *name;
546             
547             if (argc < 2)
548             {
549                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to section",
550                      file, lineno);
551                 continue;
552             }
553             name = argv[1];
554             
555             cur_elements = (data1_sub_elements *)
556                 nmem_malloc(data1_nmem_get(dh), sizeof(*cur_elements));
557             cur_elements->next = res->sub_elements;
558             cur_elements->elements = NULL;
559             cur_elements->name = nmem_strdup (data1_nmem_get(dh), name);
560             res->sub_elements = cur_elements;
561             
562             level = 0;
563             ppl[level] = &cur_elements->elements;
564         }
565         else if (!strcmp(cmd, "all"))
566         {
567             char *p;
568             data1_termlist **tp = &all;
569             
570             if (all)
571             {
572                 yaz_log(LOG_WARN, "%s:%d: Too many 'all' directives - ignored",
573                      file, lineno);
574                 continue;
575             }
576
577             if (argc != 2)
578             {
579                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to 'all' directive",
580                      file, lineno);
581                 continue;
582             }
583             p = argv[1];
584             assert (res->attset);
585             do
586             {
587                 char attname[512], structure[512];
588                 int r;
589                 
590                 if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
591                                  structure)))
592                 {
593                     yaz_log(LOG_WARN, "%s:%d: Syntax error in termlistspec",
594                          file, lineno);
595                     fclose(f);
596                     return 0;
597                 }
598                 *tp = (data1_termlist *)
599                     nmem_malloc(data1_nmem_get(dh), sizeof(**tp));
600                 if (!((*tp)->att =
601                       data1_getattbyname (dh, res->attset, attname)))
602                 {
603                     yaz_log(LOG_WARN, "%s:%d: Couldn't find att '%s' in attset",
604                          file, lineno, attname);
605                     fclose(f);
606                     return 0;
607                 }
608                 if (r < 2) /* is the structure qualified? */
609                     (*tp)->structure = "w";
610                 else 
611                 {
612                     (*tp)->structure =
613                         (char *)nmem_malloc (data1_nmem_get (dh),
614                                              strlen(structure)+1);
615                     strcpy ((*tp)->structure, structure);
616                 }
617                 (*tp)->next = 0;
618                 tp = &(*tp)->next;
619             }
620             while ((p = strchr(p, ',')) && *(++p));
621         }
622         else if (!strcmp(cmd, "name"))
623         {
624             if (argc != 2)
625             {
626                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to name directive",
627                      file, lineno);
628                 continue;
629             }
630             res->name = nmem_strdup(data1_nmem_get(dh), argv[1]);
631         }
632         else if (!strcmp(cmd, "reference"))
633         {
634             char *name;
635             
636             if (argc != 2)
637             {
638                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to reference",
639                      file, lineno);
640                 continue;
641             }
642             name = argv[1];
643             if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
644             {
645                 yaz_log(LOG_WARN, "%s:%d: Unknown tagset ref '%s'", 
646                      file, lineno, name);
647                 continue;
648             }
649         }
650         else if (!strcmp(cmd, "attset"))
651         {
652             char *name;
653             data1_attset *attset;
654             
655             if (argc != 2)
656             {
657                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to attset",
658                      file, lineno);
659                 continue;
660             }
661             name = argv[1];
662             if (!(attset = data1_get_attset (dh, name)))
663             {
664                 yaz_log(LOG_WARN, "%s:%d: Couldn't find attset  %s",
665                      file, lineno, name);
666                 continue;
667             }
668             *attset_childp = (data1_attset_child *)
669                 nmem_malloc (data1_nmem_get(dh), sizeof(**attset_childp));
670             (*attset_childp)->child = attset;
671             (*attset_childp)->next = 0;
672             attset_childp = &(*attset_childp)->next;
673         }
674         else if (!strcmp(cmd, "tagset"))
675         {
676             char *name;
677             int type = 0;
678             if (argc < 2)
679             {
680                 yaz_log(LOG_WARN, "%s:%d: Bad # of args to tagset",
681                      file, lineno);
682                 continue;
683             }
684             name = argv[1];
685             if (argc == 3)
686                 type = atoi(argv[2]);
687             *tagset_childp = data1_read_tagset (dh, name, type);
688             if (!(*tagset_childp))
689             {
690                 yaz_log(LOG_WARN, "%s:%d: Couldn't load tagset %s",
691                      file, lineno, name);
692                 continue;
693             }
694             tagset_childp = &(*tagset_childp)->next;
695         }
696         else if (!strcmp(cmd, "varset"))
697         {
698             char *name;
699
700             if (argc != 2)
701             {
702                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in varset",
703                      file, lineno);
704                 continue;
705             }
706             name = argv[1];
707             if (!(res->varset = data1_read_varset (dh, name)))
708             {
709                 yaz_log(LOG_WARN, "%s:%d: Couldn't load Varset %s",
710                      file, lineno, name);
711                 continue;
712             }
713         }
714         else if (!strcmp(cmd, "esetname"))
715         {
716             char *name, *fname;
717
718             if (argc != 3)
719             {
720                 yaz_log(LOG_WARN, "%s:%d: Bad # of args in esetname",
721                      file, lineno);
722                 continue;
723             }
724             name = argv[1];
725             fname = argv[2];
726             
727             *esetpp = (data1_esetname *)
728                 nmem_malloc(data1_nmem_get(dh), sizeof(**esetpp));
729             (*esetpp)->name = nmem_strdup(data1_nmem_get(dh), name);
730             (*esetpp)->next = 0;
731             if (*fname == '@')
732                 (*esetpp)->spec = 0;
733             else if (!((*esetpp)->spec = data1_read_espec1 (dh, fname)))
734             {
735                 yaz_log(LOG_WARN, "%s:%d: Espec-1 read failed for %s",
736                      file, lineno, fname);
737                 continue;
738             }
739             esetpp = &(*esetpp)->next;
740         }
741         else if (!strcmp(cmd, "maptab"))
742         {
743             char *name;
744             
745             if (argc != 2)
746             {
747                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for maptab",
748                      file, lineno);
749                 continue;
750             }
751             name = argv[1];
752             if (!(*maptabp = data1_read_maptab (dh, name)))
753             {
754                 yaz_log(LOG_WARN, "%s:%d: Couldn't load maptab %s",
755                      file, lineno, name);
756                 continue;
757             }
758             maptabp = &(*maptabp)->next;
759         }
760         else if (!strcmp(cmd, "marc"))
761         {
762             char *name;
763             
764             if (argc != 2)
765             {
766                 yaz_log(LOG_WARN, "%s:%d: Bad # or args for marc",
767                      file, lineno);
768                 continue;
769             }
770             name = argv[1];
771             if (!(*marcp = data1_read_marctab (dh, name)))
772             {
773                 yaz_log(LOG_WARN, "%s:%d: Couldn't read marctab %s",
774                      file, lineno, name);
775                 continue;
776             }
777             marcp = &(*marcp)->next;
778         }
779         else
780         {
781             yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'", file, lineno, cmd);
782             continue;
783         }
784     }
785     fclose(f);
786     
787     for (cur_elements = res->sub_elements; cur_elements;
788          cur_elements = cur_elements->next)
789     {
790         if (!strcmp (cur_elements->name, "main"))
791             res->main_elements = cur_elements->elements;
792         fix_element_ref (dh, res, cur_elements->elements);
793     }
794     yaz_log (LOG_DEBUG, "%s: data1_read_absyn end", file);
795     return res;
796 }