Retrieval module no longer uses ctype.h - functions.
[yaz-moved-to-github.git] / retrieval / d1_espec.c
1 /*
2  * Copyright (c) 1995-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_espec.c,v $
7  * Revision 1.17  1999-10-21 12:06:29  adam
8  * Retrieval module no longer uses ctype.h - functions.
9  *
10  * Revision 1.16  1999/08/27 09:40:32  adam
11  * Renamed logf function to yaz_log. Removed VC++ project files.
12  *
13  * Revision 1.15  1998/10/13 16:09:49  adam
14  * Added support for arbitrary OID's for tagsets, schemas and attribute sets.
15  * Added support for multiple attribute set references and tagset references
16  * from an abstract syntax file.
17  * Fixed many bad logs-calls in routines that read the various
18  * specifications regarding data1 (*.abs,*.att,...) and made the messages
19  * consistent whenever possible.
20  * Added extra 'lineno' argument to function readconf_line.
21  *
22  * Revision 1.14  1998/02/11 11:53:35  adam
23  * Changed code so that it compiles as C++.
24  *
25  * Revision 1.13  1997/11/24 11:33:56  adam
26  * Using function odr_nullval() instead of global ODR_NULLVAL when
27  * appropriate.
28  *
29  * Revision 1.12  1997/10/31 12:20:09  adam
30  * Improved memory debugging for xmalloc/nmem.c. References to NMEM
31  * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
32  * Bug fix: missing fclose in data1_read_espec1.
33  *
34  * Revision 1.11  1997/09/29 13:18:59  adam
35  * Added function, oid_ent_to_oid, to replace the function
36  * oid_getoidbyent, which is not thread safe.
37  *
38  * Revision 1.10  1997/09/29 07:21:10  adam
39  * Added typecast to avoid warnings on MSVC.
40  *
41  * Revision 1.9  1997/09/17 12:10:35  adam
42  * YAZ version 1.4.
43  *
44  * Revision 1.8  1997/09/05 09:50:56  adam
45  * Removed global data1_tabpath - uses data1_get_tabpath() instead.
46  *
47  * Revision 1.7  1997/05/14 06:54:02  adam
48  * C++ support.
49  *
50  * Revision 1.6  1996/07/06 19:58:34  quinn
51  * System headerfiles gathered in yconfig
52  *
53  * Revision 1.5  1996/01/02  08:57:44  quinn
54  * Changed enums in the ASN.1 .h files to #defines. Changed oident.class to oclass
55  *
56  * Revision 1.4  1995/12/05  11:16:10  quinn
57  * Fixed malloc of 0.
58  *
59  * Revision 1.3  1995/11/13  09:27:34  quinn
60  * Fiddling with the variant stuff.
61  *
62  * Revision 1.2  1995/11/01  16:34:56  quinn
63  * Making data1 look for tables in data1_tabpath
64  *
65  * Revision 1.1  1995/11/01  11:56:07  quinn
66  * Added Retrieval (data management) functions en masse.
67  *
68  *
69  */
70
71
72 #include <stdlib.h>
73 #include <assert.h>
74 #include <string.h>
75 #include <odr.h>
76 #include <proto.h>
77 #include <log.h>
78 #include <data1.h>
79
80 static Z_Variant *read_variant(int argc, char **argv, NMEM nmem,
81                                const char *file, int lineno)
82 {
83     Z_Variant *r = (Z_Variant *)nmem_malloc(nmem, sizeof(*r));
84     oident var1;
85     int i;
86     int oid[OID_SIZE];
87
88     var1.proto = PROTO_Z3950;
89     var1.oclass = CLASS_VARSET;
90     var1.value = VAL_VAR1;
91     r->globalVariantSetId = odr_oiddup_nmem(nmem, oid_ent_to_oid(&var1, oid));
92
93     if (argc)
94         r->triples = (Z_Triple **)nmem_malloc(nmem, sizeof(Z_Triple*) * argc);
95     else
96         r->triples = 0;
97     r->num_triples = argc;
98     for (i = 0; i < argc; i++)
99     {
100         int zclass, type;
101         char value[512];
102         Z_Triple *t;
103
104         if (sscanf(argv[i], "(%d,%d,%[^)])", &zclass, &type, value) < 3)
105         {
106             yaz_log(LOG_WARN, "%s:%d: Syntax error in variant component '%s'",
107                     file, lineno, argv[i]);
108             return 0;
109         }
110         t = r->triples[i] = (Z_Triple *)nmem_malloc(nmem, sizeof(Z_Triple));
111         t->variantSetId = 0;
112         t->zclass = (int *)nmem_malloc(nmem, sizeof(int));
113         *t->zclass = zclass;
114         t->type = (int *)nmem_malloc(nmem, sizeof(int));
115         *t->type = type;
116         /*
117          * This is wrong.. we gotta look up the correct type for the
118          * variant, I guess... damn this stuff.
119          */
120         if (*value == '@')
121         {
122             t->which = Z_Triple_null;
123             t->value.null = odr_nullval();
124         }
125         else if (d1_isdigit(*value))
126         {
127             t->which = Z_Triple_integer;
128             t->value.integer = (int *)
129                 nmem_malloc(nmem, sizeof(*t->value.integer));
130             *t->value.integer = atoi(value);
131         }
132         else
133         {
134             t->which = Z_Triple_internationalString;
135             t->value.internationalString = (char *)
136                 nmem_malloc(nmem, strlen(value)+1);
137             strcpy(t->value.internationalString, value);
138         }
139     }
140     return r;
141 }
142
143 static Z_Occurrences *read_occurrences(char *occ, NMEM nmem,
144                                        const char *file, int lineno)
145 {
146     Z_Occurrences *op = (Z_Occurrences *)nmem_malloc(nmem, sizeof(*op));
147     char *p;
148     
149     if (!occ)
150     {
151         op->which = Z_Occurrences_values;
152         op->u.values = (Z_OccurValues *)
153             nmem_malloc(nmem, sizeof(Z_OccurValues));
154         op->u.values->start = (int *)nmem_malloc(nmem, sizeof(int));
155         *op->u.values->start = 1;
156         op->u.values->howMany = 0;
157     }
158     else if (!strcmp(occ, "all"))
159     {
160         op->which = Z_Occurrences_all;
161         op->u.all = odr_nullval();
162     }
163     else if (!strcmp(occ, "last"))
164     {
165         op->which = Z_Occurrences_last;
166         op->u.all = odr_nullval();
167     }
168     else
169     {
170         Z_OccurValues *ov = (Z_OccurValues *)nmem_malloc(nmem, sizeof(*ov));
171     
172         if (!d1_isdigit(*occ))
173         {
174             yaz_log(LOG_WARN, "%s:%d: Bad occurrences-spec %s",
175                     file, lineno, occ);
176             return 0;
177         }
178         op->which = Z_Occurrences_values;
179         op->u.values = ov;
180         ov->start = (int *)nmem_malloc(nmem, sizeof(*ov->start));
181         *ov->start = atoi(occ);
182         if ((p = strchr(occ, '+')))
183         {
184             ov->howMany = (int *)nmem_malloc(nmem, sizeof(*ov->howMany));
185             *ov->howMany = atoi(p + 1);
186         }
187         else
188             ov->howMany = 0;
189     }
190     return op;
191 }
192
193
194 static Z_ETagUnit *read_tagunit(char *buf, NMEM nmem,
195                                 const char *file, int lineno)
196 {
197     Z_ETagUnit *u = (Z_ETagUnit *)nmem_malloc(nmem, sizeof(*u));
198     int terms;
199     int type;
200     char value[512], occ[512];
201     
202     if (*buf == '*')
203     {
204         u->which = Z_ETagUnit_wildPath;
205         u->u.wildPath = odr_nullval();
206     }
207     else if (*buf == '?')
208     {
209         u->which = Z_ETagUnit_wildThing;
210         if (buf[1] == ':')
211             u->u.wildThing = read_occurrences(buf+2, nmem, file, lineno);
212         else
213             u->u.wildThing = read_occurrences(0, nmem, file, lineno);
214     }
215     else if ((terms = sscanf(buf, "(%d,%[^)]):%[a-z0-9+]", &type, value,
216                              occ)) >= 2)
217     {
218         int numval;
219         Z_SpecificTag *t;
220         char *valp = value;
221         int force_string = 0;
222         
223         if (*valp == '\'')
224         {
225             valp++;
226             force_string = 1;
227         }
228         u->which = Z_ETagUnit_specificTag;
229         u->u.specificTag = t = (Z_SpecificTag *)nmem_malloc(nmem, sizeof(*t));
230         t->tagType = (int *)nmem_malloc(nmem, sizeof(*t->tagType));
231         *t->tagType = type;
232         t->tagValue = (Z_StringOrNumeric *)
233             nmem_malloc(nmem, sizeof(*t->tagValue));
234         if (!force_string && (numval = atoi(valp)))
235         {
236             t->tagValue->which = Z_StringOrNumeric_numeric;
237             t->tagValue->u.numeric = (int *)nmem_malloc(nmem, sizeof(int));
238             *t->tagValue->u.numeric = numval;
239         }
240         else
241         {
242             t->tagValue->which = Z_StringOrNumeric_string;
243             t->tagValue->u.string = (char *)nmem_malloc(nmem, strlen(valp)+1);
244             strcpy(t->tagValue->u.string, valp);
245         }
246         if (terms > 2) /* an occurrences-spec exists */
247             t->occurrences = read_occurrences(occ, nmem, file, lineno);
248         else
249             t->occurrences = 0;
250     }
251     return u;
252 }
253
254 /*
255  * Read an element-set specification from a file.
256  * NOTE: If !o, memory is allocated directly from the heap by nmem_malloc().
257  */
258 Z_Espec1 *data1_read_espec1 (data1_handle dh, const char *file)
259 {
260     FILE *f;
261     NMEM nmem = data1_nmem_get (dh);
262     int lineno = 0;
263     int argc, size_esn = 0;
264     char *argv[50], line[512];
265     Z_Espec1 *res = (Z_Espec1 *)nmem_malloc(nmem, sizeof(*res));
266     
267     if (!(f = yaz_path_fopen(data1_get_tabpath(dh), file, "r")))
268     {
269         yaz_log(LOG_WARN|LOG_ERRNO, "%s", file);
270         return 0;
271     }
272     
273     res->num_elementSetNames = 0;
274     res->elementSetNames = 0;
275     res->defaultVariantSetId = 0;
276     res->defaultVariantRequest = 0;
277     res->defaultTagType = 0;
278     res->num_elements = 0;
279     res->elements = 0;
280     
281     while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
282         if (!strcmp(argv[0], "elementsetnames"))
283         {
284             int nnames = argc-1, i;
285             
286             if (!nnames)
287             {
288                 yaz_log(LOG_WARN, "%s:%d: Empty elementsetnames directive",
289                         file, lineno);
290                 continue;
291             }
292             
293             res->elementSetNames =
294                 (char **)nmem_malloc(nmem, sizeof(char**)*nnames);
295             for (i = 0; i < nnames; i++)
296             {
297                 res->elementSetNames[i] = (char *)
298                     nmem_malloc(nmem, strlen(argv[i+1])+1);
299                 strcpy(res->elementSetNames[i], argv[i+1]);
300             }
301             res->num_elementSetNames = nnames;
302         }
303         else if (!strcmp(argv[0], "defaultvariantsetid"))
304         {
305             if (argc != 2)
306             {
307                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
308                         file, lineno, argv[0]);
309                 continue;
310             }
311             if (!(res->defaultVariantSetId =
312                   odr_getoidbystr_nmem(nmem, argv[1])))
313             {
314                 yaz_log(LOG_WARN, "%s:%d: Bad defaultvariantsetid",
315                         file, lineno);
316                 continue;
317             }
318         }
319         else if (!strcmp(argv[0], "defaulttagtype"))
320         {
321             if (argc != 2)
322             {
323                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
324                         file, lineno, argv[0]);
325                 continue;
326             }
327             res->defaultTagType = (int *)nmem_malloc(nmem, sizeof(int));
328             *res->defaultTagType = atoi(argv[1]);
329         }
330         else if (!strcmp(argv[0], "defaultvariantrequest"))
331         {
332             if (!(res->defaultVariantRequest =
333                   read_variant(argc-1, argv+1, nmem, file, lineno)))
334             {
335                 yaz_log(LOG_WARN, "%s:%d: Bad defaultvariantrequest",
336                         file, lineno);
337                 continue;
338             }
339         }
340         else if (!strcmp(argv[0], "simpleelement"))
341         {
342             Z_ElementRequest *er;
343             Z_SimpleElement *se;
344             Z_ETagPath *tp;
345             char *path = argv[1];
346             char *ep;
347             int num, i = 0;
348             
349             if (!res->elements)
350                 res->elements = (Z_ElementRequest **)
351                     nmem_malloc(nmem, size_esn = 24*sizeof(er));
352             else if (res->num_elements >= (int) (size_esn/sizeof(er)))
353             {
354                 Z_ElementRequest **oe = res->elements;
355                 size_esn *= 2;
356                 res->elements = (Z_ElementRequest **)
357                     nmem_malloc (nmem, size_esn*sizeof(er));
358                 memcpy (res->elements, oe, size_esn/2);
359             }
360             if (argc < 2)
361             {
362                 yaz_log(LOG_WARN, "%s:%d: Bad # of args for %s",
363                         file, lineno, argv[0]);
364                 continue;
365             }
366             
367             res->elements[res->num_elements++] = er =
368                 (Z_ElementRequest *)nmem_malloc(nmem, sizeof(*er));
369             er->which = Z_ERequest_simpleElement;
370             er->u.simpleElement = se = (Z_SimpleElement *)
371                 nmem_malloc(nmem, sizeof(*se));
372             se->variantRequest = 0;
373             se->path = tp = (Z_ETagPath *)nmem_malloc(nmem, sizeof(*tp));
374             tp->num_tags = 0;
375             /*
376              * Parse the element selector.
377              */
378             for (num = 1, ep = path; (ep = strchr(ep, '/')); num++, ep++)
379                 ;
380             tp->tags = (Z_ETagUnit **)
381                 nmem_malloc(nmem, sizeof(Z_ETagUnit*)*num);
382             
383             for ((ep = strchr(path, '/')) ; path ;
384                  (void)((path = ep) && (ep = strchr(path, '/'))))
385             {
386                 if (ep)
387                     ep++;
388                 
389                 assert(i<num);
390                 tp->tags[tp->num_tags++] =
391                     read_tagunit(path, nmem, file, lineno);
392             }
393             
394             if (argc > 2 && !strcmp(argv[2], "variant"))
395                 se->variantRequest=
396                     read_variant(argc-3, argv+3, nmem, file, lineno);
397         }
398         else
399             yaz_log(LOG_WARN, "%s:%d: Unknown directive '%s'",
400                     file, lineno, argv[0]);
401     fclose (f);
402     return res;
403 }