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