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