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