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