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