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