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