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