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