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