82721d9b1e3a27839a0c38a9fa793f1774b5207c
[idzebra-moved-to-github.git] / data1 / d1_espec.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1995-2008 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <stdlib.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <ctype.h>
24
25 #include <yaz/log.h>
26 #include <yaz/odr.h>
27 #include <yaz/proto.h>
28 #include <idzebra/data1.h>
29 #include <yaz/oid_db.h>
30
31 static Z_Variant *read_variant(int argc, char **argv, NMEM nmem,
32                                const char *file, int lineno)
33 {
34     Z_Variant *r = (Z_Variant *)nmem_malloc(nmem, sizeof(*r));
35     int i;
36
37     r->globalVariantSetId = odr_oiddup_nmem(nmem, yaz_oid_varset_variant_1);
38     if (argc)
39         r->triples = (Z_Triple **)nmem_malloc(nmem, sizeof(Z_Triple*) * argc);
40     else
41         r->triples = 0;
42     r->num_triples = argc;
43     for (i = 0; i < argc; i++)
44     {
45         int zclass, type;
46         char value[512];
47         Z_Triple *t;
48
49         if (sscanf(argv[i], "(%d,%d,%511[^)])", &zclass, &type, value) < 3)
50         {
51             yaz_log(YLOG_WARN, "%s:%d: Syntax error in variant component '%s'",
52                     file, lineno, argv[i]);
53             return 0;
54         }
55         t = r->triples[i] = (Z_Triple *)nmem_malloc(nmem, sizeof(Z_Triple));
56         t->variantSetId = 0;
57         t->zclass = nmem_intdup(nmem, zclass);
58         t->type = nmem_intdup(nmem, type);
59         /*
60          * This is wrong.. we gotta look up the correct type for the
61          * variant, I guess... damn this stuff.
62          */
63         if (*value == '@')
64         {
65             t->which = Z_Triple_null;
66             t->value.null = odr_nullval();
67         }
68         else if (d1_isdigit(*value))
69         {
70             t->which = Z_Triple_integer;
71             t->value.integer = nmem_intdup(nmem, atoi(value));
72         }
73         else
74         {
75             t->which = Z_Triple_internationalString;
76             t->value.internationalString = nmem_strdup(nmem, value);
77         }
78     }
79     return r;
80 }
81
82 static Z_Occurrences *read_occurrences(char *occ, NMEM nmem,
83                                        const char *file, int lineno)
84 {
85     Z_Occurrences *op = (Z_Occurrences *)nmem_malloc(nmem, sizeof(*op));
86     char *p;
87     
88     if (!occ)
89     {
90         op->which = Z_Occurrences_values;
91         op->u.values = (Z_OccurValues *)
92             nmem_malloc(nmem, sizeof(Z_OccurValues));
93         op->u.values->start = nmem_intdup(nmem, 1);
94         op->u.values->howMany = 0;
95     }
96     else if (!strcmp(occ, "all"))
97     {
98         op->which = Z_Occurrences_all;
99         op->u.all = odr_nullval();
100     }
101     else if (!strcmp(occ, "last"))
102     {
103         op->which = Z_Occurrences_last;
104         op->u.all = odr_nullval();
105     }
106     else
107     {
108         Z_OccurValues *ov = (Z_OccurValues *)nmem_malloc(nmem, sizeof(*ov));
109     
110         if (!d1_isdigit(*occ))
111         {
112             yaz_log(YLOG_WARN, "%s:%d: Bad occurrences-spec %s",
113                     file, lineno, occ);
114             return 0;
115         }
116         op->which = Z_Occurrences_values;
117         op->u.values = ov;
118         ov->start = nmem_intdup(nmem, atoi(occ));
119         if ((p = strchr(occ, '+')))
120             ov->howMany = nmem_intdup(nmem, atoi(p + 1));
121         else
122             ov->howMany = 0;
123     }
124     return op;
125 }
126
127
128 static Z_ETagUnit *read_tagunit(char *buf, NMEM nmem,
129                                 const char *file, int lineno)
130 {
131     Z_ETagUnit *u = (Z_ETagUnit *)nmem_malloc(nmem, sizeof(*u));
132     int terms;
133     int type;
134     char value[512], occ[512];
135     
136     if (*buf == '*')
137     {
138         u->which = Z_ETagUnit_wildPath;
139         u->u.wildPath = odr_nullval();
140     }
141     else if (*buf == '?')
142     {
143         u->which = Z_ETagUnit_wildThing;
144         if (buf[1] == ':')
145             u->u.wildThing = read_occurrences(buf+2, nmem, file, lineno);
146         else
147             u->u.wildThing = read_occurrences(0, nmem, file, lineno);
148     }
149     else if ((terms = sscanf(buf, "(%d,%511[^)]):%511[a-zA-Z0-9+]",
150                              &type, value, occ)) >= 2)
151     {
152         int numval;
153         Z_SpecificTag *t;
154         char *valp = value;
155         int force_string = 0;
156         
157         if (*valp == '\'')
158         {
159             valp++;
160             force_string = 1;
161             if (*valp && valp[strlen(valp)-1] == '\'')
162                 *valp = '\0';
163         }
164         u->which = Z_ETagUnit_specificTag;
165         u->u.specificTag = t = (Z_SpecificTag *)nmem_malloc(nmem, sizeof(*t));
166         t->tagType = nmem_intdup(nmem, type);
167         t->tagValue = (Z_StringOrNumeric *)
168             nmem_malloc(nmem, sizeof(*t->tagValue));
169         if (!force_string && isdigit(*(unsigned char *)valp))
170         {
171             numval = atoi(valp);
172             t->tagValue->which = Z_StringOrNumeric_numeric;
173             t->tagValue->u.numeric = nmem_intdup(nmem, numval);
174         }
175         else
176         {
177             t->tagValue->which = Z_StringOrNumeric_string;
178             t->tagValue->u.string = nmem_strdup(nmem, valp);
179         }
180         if (terms > 2) /* an occurrences-spec exists */
181             t->occurrences = read_occurrences(occ, nmem, file, lineno);
182         else
183             t->occurrences = 0;
184     }
185     else if ((terms = sscanf(buf, "%511[^)]", value)) >= 1)
186     {
187         Z_SpecificTag *t;
188         char *valp = value;
189
190         u->which = Z_ETagUnit_specificTag;
191         u->u.specificTag = t = (Z_SpecificTag *)nmem_malloc(nmem, sizeof(*t));
192         t->tagType = nmem_intdup(nmem, 3);
193         t->tagValue = (Z_StringOrNumeric *)
194             nmem_malloc(nmem, sizeof(*t->tagValue));
195         t->tagValue->which = Z_StringOrNumeric_string;
196         t->tagValue->u.string = nmem_strdup(nmem, valp);
197         t->occurrences = read_occurrences("all", nmem, file, lineno);
198     }
199     else
200     {
201         return 0;
202     }
203     return u;
204 }
205
206 /*
207  * Read an element-set specification from a file.
208  * NOTE: If !o, memory is allocated directly from the heap by nmem_malloc().
209  */
210 Z_Espec1 *data1_read_espec1 (data1_handle dh, const char *file)
211 {
212     FILE *f;
213     NMEM nmem = data1_nmem_get (dh);
214     int lineno = 0;
215     int argc, size_esn = 0;
216     char *argv[50], line[512];
217     Z_Espec1 *res = (Z_Espec1 *)nmem_malloc(nmem, sizeof(*res));
218     
219     if (!(f = data1_path_fopen(dh, file, "r")))
220         return 0;
221     
222     res->num_elementSetNames = 0;
223     res->elementSetNames = 0;
224     res->defaultVariantSetId = 0;
225     res->defaultVariantRequest = 0;
226     res->defaultTagType = 0;
227     res->num_elements = 0;
228     res->elements = 0;
229     
230     while ((argc = readconf_line(f, &lineno, line, 512, argv, 50)))
231         if (!strcmp(argv[0], "elementsetnames"))
232         {
233             int nnames = argc-1, i;
234             
235             if (!nnames)
236             {
237                 yaz_log(YLOG_WARN, "%s:%d: Empty elementsetnames directive",
238                         file, lineno);
239                 continue;
240             }
241             
242             res->elementSetNames =
243                 (char **)nmem_malloc(nmem, sizeof(char**)*nnames);
244             for (i = 0; i < nnames; i++)
245             {
246                 res->elementSetNames[i] = nmem_strdup(nmem, argv[i+1]);
247             }
248             res->num_elementSetNames = nnames;
249         }
250         else if (!strcmp(argv[0], "defaultvariantsetid"))
251         {
252             if (argc != 2)
253             {
254                 yaz_log(YLOG_WARN, "%s:%d: Bad # of args for %s",
255                         file, lineno, argv[0]);
256                 continue;
257             }
258             if (!(res->defaultVariantSetId =
259                   odr_getoidbystr_nmem(nmem, argv[1])))
260             {
261                 yaz_log(YLOG_WARN, "%s:%d: Bad defaultvariantsetid",
262                         file, lineno);
263                 continue;
264             }
265         }
266         else if (!strcmp(argv[0], "defaulttagtype"))
267         {
268             if (argc != 2)
269             {
270                 yaz_log(YLOG_WARN, "%s:%d: Bad # of args for %s",
271                         file, lineno, argv[0]);
272                 continue;
273             }
274             res->defaultTagType = nmem_intdup(nmem, atoi(argv[1]));
275         }
276         else if (!strcmp(argv[0], "defaultvariantrequest"))
277         {
278             if (!(res->defaultVariantRequest =
279                   read_variant(argc-1, argv+1, nmem, file, lineno)))
280             {
281                 yaz_log(YLOG_WARN, "%s:%d: Bad defaultvariantrequest",
282                         file, lineno);
283                 continue;
284             }
285         }
286         else if (!strcmp(argv[0], "simpleelement"))
287         {
288             Z_ElementRequest *er;
289             Z_SimpleElement *se;
290             Z_ETagPath *tp;
291             char *path = argv[1];
292             char *ep;
293             int num, i = 0;
294             
295             if (!res->elements)
296                 res->elements = (Z_ElementRequest **)
297                     nmem_malloc(nmem, size_esn = 24*sizeof(er));
298             else if (res->num_elements >= (int) (size_esn/sizeof(er)))
299             {
300                 Z_ElementRequest **oe = res->elements;
301                 size_esn *= 2;
302                 res->elements = (Z_ElementRequest **)
303                     nmem_malloc (nmem, size_esn*sizeof(er));
304                 memcpy (res->elements, oe, size_esn/2);
305             }
306             if (argc < 2)
307             {
308                 yaz_log(YLOG_WARN, "%s:%d: Bad # of args for %s",
309                         file, lineno, argv[0]);
310                 continue;
311             }
312             
313             res->elements[res->num_elements++] = er =
314                 (Z_ElementRequest *)nmem_malloc(nmem, sizeof(*er));
315             er->which = Z_ERequest_simpleElement;
316             er->u.simpleElement = se = (Z_SimpleElement *)
317                 nmem_malloc(nmem, sizeof(*se));
318             se->variantRequest = 0;
319             se->path = tp = (Z_ETagPath *)nmem_malloc(nmem, sizeof(*tp));
320             tp->num_tags = 0;
321             /*
322              * Parse the element selector.
323              */
324             for (num = 1, ep = path; (ep = strchr(ep, '/')); num++, ep++)
325                 ;
326             tp->tags = (Z_ETagUnit **)
327                 nmem_malloc(nmem, sizeof(Z_ETagUnit*)*num);
328             
329             for ((ep = strchr(path, '/')) ; path ;
330                  (void)((path = ep) && (ep = strchr(path, '/'))))
331             {
332                 Z_ETagUnit *tagunit;
333                 if (ep)
334                     ep++;
335                 
336                 assert(i<num);
337                 tagunit = read_tagunit(path, nmem, file, lineno);
338                 if (!tagunit)
339                 {
340                     yaz_log (YLOG_WARN, "%s%d: Bad tag unit at %s",
341                              file, lineno, path);
342                     break;
343                 }
344                 tp->tags[tp->num_tags++] = tagunit;
345             }
346             
347             if (argc > 2 && !strcmp(argv[2], "variant"))
348                 se->variantRequest=
349                     read_variant(argc-3, argv+3, nmem, file, lineno);
350         }
351         else
352             yaz_log(YLOG_WARN, "%s:%d: Unknown directive '%s'",
353                     file, lineno, argv[0]);
354     fclose (f);
355     return res;
356 }
357 /*
358  * Local variables:
359  * c-basic-offset: 4
360  * indent-tabs-mode: nil
361  * End:
362  * vim: shiftwidth=4 tabstop=8 expandtab
363  */
364