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