C++ support.
[yaz-moved-to-github.git] / retrieval / d1_absyn.c
1 /*
2  * Copyright (c) 1995, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_absyn.c,v $
7  * Revision 1.10  1997-05-14 06:54:01  adam
8  * C++ support.
9  *
10  * Revision 1.9  1997/02/19 14:46:15  adam
11  * The "all" specifier only affects elements that are indexed (and not
12  * all elements).
13  *
14  * Revision 1.8  1997/01/02 10:47:59  quinn
15  * Added optional, physical ANY
16  *
17  * Revision 1.7  1996/06/10 08:56:01  quinn
18  * Work on Summary.
19  *
20  * Revision 1.6  1996/05/31  13:52:21  quinn
21  * Fixed uninitialized variable for local tags in abstract syntax.
22  *
23  * Revision 1.5  1996/05/09  07:27:43  quinn
24  * Multiple local attributes values supported.
25  *
26  * Revision 1.4  1996/05/01  12:45:28  quinn
27  * Support use of local tag names in abs file.
28  *
29  * Revision 1.3  1995/11/01  16:34:55  quinn
30  * Making data1 look for tables in data1_tabpath
31  *
32  * Revision 1.2  1995/11/01  13:54:44  quinn
33  * Minor adjustments
34  *
35  * Revision 1.1  1995/11/01  11:56:06  quinn
36  * Added Retrieval (data management) functions en masse.
37  *
38  *
39  */
40
41 #include <ctype.h>
42 #include <stdio.h>
43 #include <assert.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <xmalloc.h>
48 #include <oid.h>
49 #include <log.h>
50 #include <tpath.h>
51
52 #include <data1.h>
53
54 #define D1_MAX_NESTING  128
55 #define DATA1_MAX_SYNTAXES 30 /* max no of syntaxes to handle in one session */
56
57 static struct /* cache of abstract syntaxes */
58 {
59     char *name;
60     data1_absyn *absyn;
61 } syntaxes[DATA1_MAX_SYNTAXES] = {{0,0}};
62
63 data1_absyn *data1_get_absyn(char *name)
64 {
65     char fname[512];
66     int i;
67
68     for (i = 0; syntaxes[i].name; i++)
69         if (!strcmp(name, syntaxes[i].name))
70             return syntaxes[i].absyn;
71
72     if (i >= DATA1_MAX_SYNTAXES - 1)
73     {
74         logf(LOG_WARN, "Too many abstract syntaxes loaded");
75         return 0;
76     }
77     sprintf(fname, "%s.abs", name);
78     if (!(syntaxes[i].absyn = data1_read_absyn(fname)))
79         return 0;
80     if (!(syntaxes[i].name = xmalloc(strlen(name)+1)))
81         abort();
82     strcpy(syntaxes[i].name, name);
83     syntaxes[i+1].name = 0;
84     return syntaxes[i].absyn;
85 }
86
87 data1_esetname *data1_getesetbyname(data1_absyn *a, char *name)
88 {
89     data1_esetname *r;
90
91     for (r = a->esetnames; r; r = r->next)
92         if (!data1_matchstr(r->name, name))
93             return r;
94     return 0;
95 }
96
97 data1_element *data1_getelementbytagname(data1_absyn *abs,
98     data1_element *parent, char *tagname)
99 {
100     data1_element *r;
101
102     if (!parent)
103         r = abs->elements;
104     else
105         r = parent->children;
106     for (; r; r = r->next)
107     {
108         data1_name *n;
109
110         for (n = r->tag->names; n; n = n->next)
111             if (!data1_matchstr(tagname, n->name))
112                 return r;
113     }
114     return 0;
115 }
116
117 data1_element *data1_getelementbyname(data1_absyn *absyn, char *name)
118 {
119     data1_element *r;
120
121     for (r = absyn->elements; r; r = r->next)
122         if (!data1_matchstr(r->name, name))
123             return r;
124     return 0;
125 }
126
127 data1_absyn *data1_read_absyn(char *file)
128 {
129     char line[512], *r, cmd[512], args[512];
130     data1_absyn *res = 0;
131     FILE *f;
132     data1_element **ppl[D1_MAX_NESTING], *cur[D1_MAX_NESTING];
133     data1_esetname **esetpp;
134     data1_maptab **maptabp;
135     data1_marctab **marcp;
136     data1_termlist *all = 0;
137     int level = 0;
138
139     if (!(f = yaz_path_fopen(data1_tabpath, file, "r")))
140     {
141         logf(LOG_WARN|LOG_ERRNO, "%s", file);
142         return 0;
143     }
144
145     if (!(res = xmalloc(sizeof(*res))))
146         abort();
147     res->name = 0;
148     res->reference = VAL_NONE;
149     res->tagset = 0;
150     res->attset = 0;
151     res->varset = 0;
152     res->esetnames = 0;
153     res->maptabs = 0;
154     maptabp = &res->maptabs;
155     res->marc = 0;
156     marcp = &res->marc;
157     res->elements = 0;
158     ppl[0] = &res->elements;
159     cur[0] = 0;
160     esetpp = &res->esetnames;
161
162     for (;;)
163     {
164         while ((r = fgets(line, 512, f)))
165         {
166             while (*r && isspace(*r))
167                 r++;
168             if (*r && *r != '#')
169                 break;
170         }
171         if (!r)
172         {
173             fclose(f);
174             return res;
175         }
176         if (sscanf(r, "%s %[^\n]", cmd, args) < 2)
177             *args = '\0';
178         if (!strcmp(cmd, "elm"))
179         {
180             data1_element *new_element;
181             int i;
182             char path[512], name[512], termlists[512], *p;
183             int type, value;
184             data1_termlist **tp;
185
186             if (sscanf(args, "%511s %511s %511s", path, name, termlists) < 3)
187             {
188                 logf(LOG_WARN, "Bad # of args to elm in %s: '%s'", 
189                     file, args);
190                 fclose(f);
191                 return 0;
192             }
193             p = path;
194             for (i = 0;; i++)
195             {
196                 char *e;
197
198                 if ((e = strchr(p, '/')))
199                     p = e+1;
200                 else
201                     break;
202             }
203             if (i > level + 1)
204             {
205                 logf(LOG_WARN, "Bad level inc in %s in '%s'", file, args);
206                 fclose(f);
207                 return 0;
208             }
209             level = i;
210             if (!(new_element = cur[level] = *ppl[level] = xmalloc(sizeof(*new_element))))
211                 abort;
212             new_element->next = new_element->children = 0;
213             new_element->tag = 0;
214             new_element->termlists = 0;
215             new_element->parent = level ? cur[level - 1] : 0;
216             tp = &new_element->termlists;
217             ppl[level] = &new_element->next;
218             ppl[level+1] = &new_element->children;
219
220             /* well-defined tag */
221             if (sscanf(p, "(%d,%d)", &type, &value) == 2)
222             {
223                 if (!res->tagset)
224                 {
225                     logf(LOG_WARN, "No tagset loaded in %s", file);
226                     fclose(f);
227                     return 0;
228                 }
229                 if (!(new_element->tag = data1_gettagbynum(res->tagset, type, value)))
230                 {
231                     logf(LOG_WARN, "Couldn't find tag %s in tagset in %s",
232                         p, file);
233                     fclose(f);
234                     return 0;
235                 }
236             }
237             /* private tag */
238             else if (*p)
239             {
240                 data1_tag *nt = new_element->tag = xmalloc(sizeof(*new_element->tag));
241                 nt->which = DATA1T_string;
242                 nt->value.string = xstrdup(p);
243                 nt->names = xmalloc(sizeof(*new_element->tag->names));
244                 nt->names->name = nt->value.string;
245                 nt->names->next = 0;
246                 nt->kind = DATA1K_string;
247                 nt->next = 0;
248                 nt->tagset = 0;
249             }
250             else
251             {
252                 logf(LOG_WARN, "Bad element is %s", file);
253                 fclose(f);
254                 return 0;
255             }
256
257             /* parse termList definitions */
258             p = termlists;
259             if (*p == '-')
260                 new_element->termlists = 0;
261             else
262             {
263                 if (!res->attset)
264                 {
265                     logf(LOG_WARN, "No attset loaded in %s", file);
266                     fclose(f);
267                     return 0;
268                 }
269                 do
270                 {
271                     char attname[512], structure[512];
272                     int r;
273
274                     if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
275                         structure)))
276                     {
277                         logf(LOG_WARN, "Syntax error in termlistspec in %s",
278                             file);
279                         fclose(f);
280                         return 0;
281                     }
282                     if (*attname == '!')
283                         strcpy(attname, name);
284                     *tp = xmalloc(sizeof(**tp));
285                     if (!((*tp)->att = data1_getattbyname(res->attset,
286                         attname)))
287                     {
288                         logf(LOG_WARN, "Couldn't find att '%s' in attset",
289                             attname);
290                         fclose(f);
291                         return 0;
292                     }
293                     if (r < 2) /* is the structure qualified? */
294                         (*tp)->structure = DATA1S_word;
295                     else if (!data1_matchstr(structure, "w"))
296                         (*tp)->structure = DATA1S_word;
297                     else if (!data1_matchstr(structure, "p"))
298                         (*tp)->structure = DATA1S_phrase;
299
300                     (*tp)->next = 0;
301                     tp = &(*tp)->next;
302                 }
303                 while ((p = strchr(p, ',')) && *(++p));
304                 *tp = all; /* append any ALL entries to the list */
305             }
306
307             new_element->name = xstrdup(name);
308         }
309         else if (!strcmp(cmd, "all"))
310         {
311             char *p;
312             data1_termlist **tp = &all;
313
314             if (all)
315             {
316                 logf(LOG_WARN, "Too many ALL declarations in %s - ignored",
317                     file);
318                 continue;
319             }
320
321             p = args;
322             if (!res->attset)
323             {
324                 logf(LOG_WARN, "No attset loaded in %s", file);
325                 fclose(f);
326                 return 0;
327             }
328             do
329             {
330                 char attname[512], structure[512];
331                 int r;
332
333                 if (!(r = sscanf(p, "%511[^:,]:%511[^,]", attname,
334                     structure)))
335                 {
336                     logf(LOG_WARN, "Syntax error in termlistspec in %s",
337                         file);
338                     fclose(f);
339                     return 0;
340                 }
341                 *tp = xmalloc(sizeof(**tp));
342                 if (!((*tp)->att = data1_getattbyname(res->attset,
343                     attname)))
344                 {
345                     logf(LOG_WARN, "Couldn't find att '%s' in attset",
346                         attname);
347                     fclose(f);
348                     return 0;
349                 }
350                 if (r < 2) /* is the structure qualified? */
351                     (*tp)->structure = DATA1S_word;
352                 else if (!data1_matchstr(structure, "w"))
353                     (*tp)->structure = DATA1S_word;
354                 else if (!data1_matchstr(structure, "p"))
355                     (*tp)->structure = DATA1S_phrase;
356
357                 (*tp)->next = 0;
358                 tp = &(*tp)->next;
359             }
360             while ((p = strchr(p, ',')) && *(++p));
361         }
362         else if (!strcmp(cmd, "name"))
363         {
364             char name[512];
365
366             if (!sscanf(args, "%s", name))
367             {
368                 logf(LOG_WARN, "%s malformed name directive in %s", file);
369                 fclose(f);
370                 return 0;
371             }
372             if (!(res->name = xmalloc(strlen(args)+1)))
373                 abort();
374             strcpy(res->name, name);
375         }
376         else if (!strcmp(cmd, "reference"))
377         {
378             char name[512];
379
380             if (!sscanf(args, "%s", name))
381             {
382                 logf(LOG_WARN, "%s malformed reference directive in %s", file);
383                 fclose(f);
384                 return 0;
385             }
386             if ((res->reference = oid_getvalbyname(name)) == VAL_NONE)
387             {
388                 logf(LOG_WARN, "Unknown tagset ref '%s' in %s", name, file);
389                 fclose(f);
390                 return 0;
391             }
392         }
393         else if (!strcmp(cmd, "attset"))
394         {
395             char name[512];
396
397             if (!sscanf(args, "%s", name))
398             {
399                 logf(LOG_WARN, "%s malformed attset directive in %s", file);
400                 fclose(f);
401                 return 0;
402             }
403             if (!(res->attset = data1_read_attset(name)))
404             {
405                 logf(LOG_WARN, "Attset failed in %s", file);
406                 fclose(f);
407                 return 0;
408             }
409         }
410         else if (!strcmp(cmd, "tagset"))
411         {
412             char name[512];
413
414             if (!sscanf(args, "%s", name))
415             {
416                 logf(LOG_WARN, "%s malformed tagset directive in %s", file);
417                 fclose(f);
418                 return 0;
419             }
420             if (!(res->tagset = data1_read_tagset(name)))
421             {
422                 logf(LOG_WARN, "Tagset failed in %s", file);
423                 fclose(f);
424                 return 0;
425             }
426         }
427         else if (!strcmp(cmd, "varset"))
428         {
429             char name[512];
430
431             if (!sscanf(args, "%s", name))
432             {
433                 logf(LOG_WARN, "%s malformed varset directive in %s", file);
434                 fclose(f);
435                 return 0;
436             }
437             if (!(res->varset = data1_read_varset(name)))
438             {
439                 logf(LOG_WARN, "Varset failed in %s", file);
440                 fclose(f);
441                 return 0;
442             }
443         }
444         else if (!strcmp(cmd, "esetname"))
445         {
446             char name[512], fname[512];
447
448             if (sscanf(args, "%s %s", name, fname) != 2)
449             {
450                 logf(LOG_WARN, "%s: Two arg's required for esetname directive");
451                 fclose(f);
452                 return 0;
453             }
454             *esetpp = xmalloc(sizeof(**esetpp));
455             (*esetpp)->name = xmalloc(strlen(name)+1);
456             strcpy((*esetpp)->name, name);
457             if (*fname == '@')
458                 (*esetpp)->spec = 0;
459             else if (!((*esetpp)->spec = data1_read_espec1(fname, 0)))
460             {
461                 logf(LOG_WARN, "%s: Espec-1 read failed", file);
462                 fclose(f);
463                 return 0;
464             }
465             (*esetpp)->next = 0;
466             esetpp = &(*esetpp)->next;
467         }
468         else if (!strcmp(cmd, "maptab"))
469         {
470             char name[512];
471
472             if (sscanf(args, "%s", name) != 1)
473             {
474                 logf(LOG_WARN, "%s: One argument required for maptab directive",
475                     file);
476                 continue;
477             }
478             if (!(*maptabp = data1_read_maptab(name)))
479             {
480                 logf(LOG_WARN, "%s: Failed to read maptab.");
481                 continue;
482             }
483             maptabp = &(*maptabp)->next;
484         }
485         else if (!strcmp(cmd, "marc"))
486         {
487             char name[512];
488
489             if (sscanf(args, "%s", name) != 1)
490             {
491                 logf(LOG_WARN, "%s: One argument required for marc directive",
492                     file);
493                 continue;
494             }
495             if (!(*marcp = data1_read_marctab(name)))
496             {
497                 logf(LOG_WARN, "%s: Failed to read marctab.");
498                 continue;
499             }
500             marcp = &(*marcp)->next;
501         }
502         else
503         {
504             logf(LOG_WARN, "Unknown directive '%s' in %s", cmd, file);
505             fclose(f);
506             return 0;
507         }
508     }
509 }