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