dom: accept type="adelete" (accept bad deletes)
[idzebra-moved-to-github.git] / index / marcomp.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 2004-2013 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 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #include <yaz/yaz-util.h>
29
30 #include "marcomp.h"
31
32 static mc_token mc_gettoken(mc_context *c);
33 static void mc_ungettoken(mc_context *c);
34 static int mc_getval(mc_context *c);
35 static int mc_getdata(mc_context *c, char *s, int sz);
36 static void mc_getinterval(mc_context *c, int *start, int *end);
37
38 static mc_subfield *mc_mk_subfield(mc_subfield *parent);
39 static mc_field *mc_mk_field(void);
40
41 static struct mc_errmsg
42 {
43     mc_errcode code;
44     const char *msg;
45 } mc_errmsg[] = {
46 {EMCOK, "OK"},
47 {EMCNOMEM, "NO mem"},
48 {EMCF, "not complete field"},
49 {EMCSF, "not complete subfield"},
50 {EMCSFGROUP, "not closed GROUP"},
51 {EMCSFVAR, "not closed VARIANT"},
52 {EMCSFINLINE, "not closed IN-LINE"},
53 {EMCEND, "not correct errno"}
54 };
55 mc_errcode mc_errno(mc_context *c)
56 {
57     return c->errcode;
58 }
59 const char *mc_error(mc_errcode no)
60 {
61     if (no >= EMCOK && no<EMCEND)
62         return mc_errmsg[no].msg;
63     else
64         return mc_errmsg[EMCEND].msg;
65 }
66 mc_context *mc_mk_context(const char *s)
67 {
68     mc_context *p=0;
69
70     if (s && strlen(s))
71     {
72         p = (mc_context*) xmalloc(sizeof(*p));
73
74         if (!p)
75             return 0;
76
77         memset(p, 0, sizeof(*p));
78         p->errcode = EMCOK;
79         p->data = s;
80         p->len = strlen(s);
81         p->crrtok = NOP;
82     }
83
84     return p;
85 }
86 void mc_destroy_context(mc_context *c)
87 {
88     if (c) xfree(c);
89 }
90 mc_token mc_gettoken(mc_context *c)
91 {
92     if (c->offset >= c->len)
93         return NOP;
94
95     switch (*(c->data+c->offset))
96     {
97         case '{': c->crrtok = LVARIANT; break;
98         case '}': c->crrtok = RVARIANT; break;
99         case '(': c->crrtok = LGROUP; break;
100         case ')': c->crrtok = RGROUP; break;
101         case '<': c->crrtok = LINLINE; break;
102         case '>': c->crrtok = RINLINE; break;
103         case '$': c->crrtok = SUBFIELD; break;
104         case '[': c->crrtok = LINTERVAL; break;
105         case ']': c->crrtok = RINTERVAL; break;
106         default:
107             if (isspace(*(unsigned char *) (c->data+c->offset))
108                             || *(c->data+c->offset) == '\n')
109             {
110                 c->crrtok = NOP;
111             }
112             else
113             {
114                 c->crrtok = REGULAR;
115                 c->crrval = *(c->data+c->offset);
116             }
117     }
118 #ifdef DEBUG
119     fprintf(stderr, "gettoken(): offset: %d", c->offset);
120     if (c->crrtok == REGULAR)
121         fprintf(stderr, "<%c>", c->crrval);
122     fprintf(stderr, "\n");
123 #endif
124     c->offset++;
125     return c->crrtok;
126 }
127 void mc_ungettoken(mc_context *c)
128 {
129     if (c->offset > 0)
130         c->offset--;
131 }
132 int mc_getval(mc_context *c)
133 {
134     return c->crrval;
135 }
136 int mc_getdata(mc_context *c, char *s, int sz)
137 {
138     int i;
139
140     for (i=0; i<sz; i++)
141     {
142         if (mc_gettoken(c)!=REGULAR)
143         {
144             mc_ungettoken(c);
145             break;
146         }
147         s[i] = mc_getval(c);
148     }
149     s[i] = '\0';
150
151     return i;
152 }
153 void mc_getinterval(mc_context *c, int *start, int *end)
154 {
155     char buf[6+1];
156     int start_pos, end_pos;
157
158     start_pos = end_pos = -1;
159
160     if (mc_gettoken(c) == LINTERVAL)
161     {
162         int i;
163
164         for (i=0;i<6;i++)
165         {
166             mc_token tok = mc_gettoken(c);
167
168             if (tok == RINTERVAL || tok == NOP)
169                 break;
170
171             buf[i] = mc_getval(c);
172         }
173
174         buf[i] = '\0';
175         i = sscanf(buf, "%d-%d", &start_pos, &end_pos);
176
177         if (i == 1)
178             end_pos = start_pos;
179         else if ( i == 0)
180         {
181             start_pos = 0;
182         }
183     }
184     *start = start_pos;
185     *end = end_pos;
186 }
187 mc_field *mc_mk_field(void)
188 {
189     mc_field *p = (mc_field *)xmalloc(sizeof(*p));
190
191     if (p)
192     {
193         memset(p, 0, sizeof(*p));
194         p->name = (char *)xmalloc(SZ_FNAME+1);
195         *p->name = '\0';
196         p->ind1 = (char *)xmalloc(SZ_IND+1);
197         *p->ind1 = '\0';
198         p->ind2 = (char *)xmalloc(SZ_IND+1);
199         *p->ind2 = '\0';
200         p->interval.start = p->interval.end = -1;
201     }
202     return p;
203 }
204 void mc_destroy_field(mc_field *p)
205 {
206     if (!p)
207         return;
208     if (p->name) xfree(p->name);
209     if (p->ind1) xfree(p->ind1);
210     if (p->ind2) xfree(p->ind2);
211     if (p->list) mc_destroy_subfields_recursive(p->list);
212     xfree(p);
213 }
214 mc_field *mc_getfield(mc_context *c)
215 {
216     mc_field *pf;
217
218     pf = mc_mk_field();
219
220     if (!pf)
221     {
222         c->errcode = EMCNOMEM;
223         return 0;
224     }
225
226     if (mc_getdata(c, pf->name, SZ_FNAME) == SZ_FNAME)
227     {
228         mc_token nexttok = mc_gettoken(c);
229
230         mc_ungettoken(c);
231
232         if (nexttok == LINTERVAL)
233         {
234             mc_getinterval(c, &pf->interval.start, &pf->interval.end);
235 #ifdef DEBUG
236             fprintf(stderr, "ineterval (%d)-(%d)\n", pf->interval.start,
237                 pf->interval.end);
238 #endif
239         }
240
241         if ((mc_getdata(c, pf->ind1, SZ_IND) == SZ_IND) &&
242             (mc_getdata(c, pf->ind2, SZ_IND) == SZ_IND))
243         {
244             pf->list = mc_getsubfields(c, 0);
245         }
246     }
247     else
248     {
249         c->errcode = EMCF;
250         mc_destroy_field(pf);
251         return 0;
252     }
253
254     return pf;
255 }
256 mc_subfield *mc_mk_subfield(mc_subfield *parent)
257 {
258     mc_subfield *p = (mc_subfield*)xmalloc(sizeof(*p));
259
260     if (p)
261     {
262         memset(p, 0, sizeof(*p));
263         p->which = MC_SF;
264         p->name = (char *)xmalloc(SZ_SFNAME+1);
265         *p->name = '\0';
266         p->prefix = (char *)xmalloc(SZ_PREFIX+1);
267         *p->prefix = '\0';
268         p->suffix = (char *)xmalloc(SZ_SUFFIX+1);
269         *p->suffix = '\0';
270         p->parent = parent;
271         p->interval.start = p->interval.end = -1;
272     }
273     return p;
274 }
275 void mc_destroy_subfield(mc_subfield *p)
276 {
277     if (!p)
278         return;
279
280     if (p->which == MC_SFGROUP || p->which == MC_SFVARIANT)
281     {
282         if (p->u.child)
283             mc_destroy_subfields_recursive(p->u.child);
284     }
285     else if (p->which == MC_SF)
286     {
287         if (p->u.in_line)
288             mc_destroy_field(p->u.in_line);
289     }
290     if (p->name) xfree(p->name);
291     if (p->prefix) xfree(p->prefix);
292     if (p->suffix) xfree(p->suffix);
293     if (p->parent) p->parent->next = p->next;
294     xfree(p);
295 }
296 void mc_destroy_subfields_recursive(mc_subfield *p)
297 {
298     if (!p)
299         return;
300
301     mc_destroy_subfields_recursive(p->next);
302
303     if (p->which == MC_SFGROUP || p->which == MC_SFVARIANT)
304     {
305         if (p->u.child)
306             mc_destroy_subfields_recursive(p->u.child);
307     }
308     else if (p->which == MC_SF)
309     {
310         if (p->u.in_line)
311             mc_destroy_field(p->u.in_line);
312     }
313
314     if (p->name) xfree(p->name);
315     if (p->prefix) xfree(p->prefix);
316     if (p->suffix) xfree(p->suffix);
317     if (p->parent) p->parent->next = 0;
318     xfree(p);
319 }
320 mc_subfield *mc_getsubfields(mc_context *c, mc_subfield *parent)
321 {
322     mc_subfield *psf=0;
323     mc_token tok = mc_gettoken(c);
324
325     if (tok == NOP)
326         return 0;
327
328     if (tok == LGROUP)
329     {
330         if (!(psf = mc_mk_subfield(parent)))
331         {
332             c->errcode = EMCNOMEM;
333             return 0;
334         }
335
336         psf->which = MC_SFGROUP;
337         psf->u.child = mc_getsubfields(c, psf);
338
339         if (mc_gettoken(c) == RGROUP)
340             psf->next = mc_getsubfields(c, psf);
341         else
342         {
343             c->errcode = EMCSFGROUP;
344             mc_destroy_subfield(psf);
345             return 0;
346         }
347     }
348     else if (tok == LVARIANT)
349     {
350         if (!(psf = mc_mk_subfield(parent)))
351         {
352             c->errcode = EMCNOMEM;
353             return 0;
354         }
355
356         psf->which = MC_SFVARIANT;
357         psf->u.child = mc_getsubfields(c, psf);
358
359         if (mc_gettoken(c) == RVARIANT)
360             psf->next = mc_getsubfields(c, psf);
361         else
362         {
363             c->errcode = EMCSFVAR;
364             mc_destroy_subfield(psf);
365             return 0;
366         }
367     }
368     else if (tok == RGROUP || tok == RVARIANT || tok == RINLINE)
369     {
370         mc_ungettoken(c);
371         return 0;
372     }
373     else if (tok == REGULAR)
374     {
375         if (!(psf = mc_mk_subfield(parent)))
376         {
377             c->errcode = EMCNOMEM;
378             return 0;
379         }
380
381         mc_ungettoken(c);
382
383         if((mc_getdata(c, psf->prefix, SZ_PREFIX) == SZ_PREFIX) &&
384             (mc_gettoken(c) == SUBFIELD) &&
385                 (mc_getdata(c, psf->name, SZ_SFNAME) == SZ_SFNAME))
386         {
387             mc_token tok = mc_gettoken(c);
388
389             mc_ungettoken(c);
390
391             if (tok == LINTERVAL)
392             {
393                 mc_getinterval(c, &psf->interval.start, &psf->interval.end);
394             }
395             else if (tok == LINLINE)
396             {
397                 mc_gettoken(c);
398                 psf->u.in_line = mc_getfield(c);
399                 if (mc_gettoken(c) != RINLINE)
400                 {
401                     c->errcode = EMCSFINLINE;
402                     mc_destroy_subfield(psf);
403                     return 0;
404                 }
405             }
406
407             if (mc_getdata(c, psf->suffix, SZ_SUFFIX) == SZ_SUFFIX)
408             {
409                 psf->which = MC_SF;
410                 psf->next = mc_getsubfields(c, psf);
411             }
412             else
413             {
414                 c->errcode = EMCSF;
415                 mc_destroy_subfield(psf);
416                 return 0;
417             }
418         }
419     }
420     return psf;
421 }
422 /*
423  * Local variables:
424  * c-basic-offset: 4
425  * c-file-style: "Stroustrup"
426  * indent-tabs-mode: nil
427  * End:
428  * vim: shiftwidth=4 tabstop=8 expandtab
429  */
430