using yaz/log.h again
[idzebra-moved-to-github.git] / recctrl / marcomp.c
1 /*
2     $Id: marcomp.c,v 1.4 2004-12-13 20:51:32 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(*(c->data+c->offset)) || *(c->data+c->offset) == '\n')
92             {
93                 c->crrtok = NOP;
94             }
95             else
96             {
97                 c->crrtok = REGULAR;
98                 c->crrval = *(c->data+c->offset);
99             }
100     }
101 #ifdef DEBUG
102     fprintf(stderr, "gettoken(): offset: %d", c->offset);
103     if (c->crrtok == REGULAR)
104         fprintf(stderr, "<%c>", c->crrval);
105     fprintf(stderr, "\n");
106 #endif
107     c->offset++;
108     return c->crrtok;
109 }
110 void mc_ungettoken(mc_context *c)
111 {
112     if (c->offset > 0)
113         c->offset--;
114 }
115 int mc_getval(mc_context *c)
116 {
117     return c->crrval;
118 }
119 int mc_getdata(mc_context *c, char *s, int sz)
120 {
121     int i;
122     
123     for (i=0; i<sz; i++)
124     {
125         if (mc_gettoken(c)!=REGULAR)
126         {
127             mc_ungettoken(c);
128             break;
129         }
130         s[i] = mc_getval(c);
131     }
132     s[i] = '\0';
133     
134     return i;
135 }
136 void mc_getinterval(mc_context *c, int *start, int *end)
137 {
138     char buf[6+1];
139     int start_pos, end_pos;
140     
141     start_pos = end_pos = -1;
142        
143     if (mc_gettoken(c) == LINTERVAL)
144     {
145         int i;
146         
147         for (i=0;i<6;i++)
148         {
149             mc_token tok = mc_gettoken(c);
150             
151             if (tok == RINTERVAL || tok == NOP)
152                 break;
153                 
154             buf[i] = mc_getval(c);
155         }
156         
157         buf[i] = '\0';
158         i = sscanf(buf, "%d-%d", &start_pos, &end_pos);
159         
160         if (i == 1)
161             end_pos = start_pos;
162         else if ( i == 0)
163         {
164             start_pos = 0;
165         }
166     }
167     *start = start_pos;
168     *end = end_pos;
169 }
170 mc_field *mc_mk_field(void)
171 {
172     mc_field *p = (mc_field *)xmalloc(sizeof(*p));
173
174     if (p)
175     {
176         memset(p, 0, sizeof(*p));
177         p->name = (char *)xmalloc(SZ_FNAME+1);
178         *p->name = '\0';
179         p->ind1 = (char *)xmalloc(SZ_IND+1);
180         *p->ind1 = '\0';
181         p->ind2 = (char *)xmalloc(SZ_IND+1);
182         *p->ind2 = '\0';
183         p->interval.start = p->interval.end = -1;
184     }
185     return p;
186 }    
187 void mc_destroy_field(mc_field *p)
188 {
189     if (!p)
190         return;
191     if (p->name) xfree(p->name);     
192     if (p->ind1) xfree(p->ind1);     
193     if (p->ind2) xfree(p->ind2);
194     if (p->list) mc_destroy_subfields_recursive(p->list);
195     xfree(p);
196 }
197 mc_field *mc_getfield(mc_context *c)
198 {
199     mc_field *pf;
200
201     pf = mc_mk_field();
202     
203     if (!pf)
204     {
205         c->errcode = EMCNOMEM;
206         return 0;
207     }
208
209     if (mc_getdata(c, pf->name, SZ_FNAME) == SZ_FNAME)
210     {
211         mc_token nexttok = mc_gettoken(c);
212         
213         mc_ungettoken(c);
214         
215         if (nexttok == LINTERVAL)
216         {
217             mc_getinterval(c, &pf->interval.start, &pf->interval.end);
218 #ifdef DEBUG
219             fprintf(stderr, "ineterval (%d)-(%d)\n", pf->interval.start,
220                 pf->interval.end);
221 #endif
222         }
223         
224         if ((mc_getdata(c, pf->ind1, SZ_IND) == SZ_IND) &&
225             (mc_getdata(c, pf->ind2, SZ_IND) == SZ_IND))
226         {
227             pf->list = mc_getsubfields(c, 0);
228         }
229     }
230     else
231     {
232         c->errcode = EMCF;
233         mc_destroy_field(pf);
234         return 0;
235     }
236         
237     return pf;
238 }
239 mc_subfield *mc_mk_subfield(mc_subfield *parent)
240 {
241     mc_subfield *p = (mc_subfield*)xmalloc(sizeof(*p));
242
243     if (p)
244     {
245         memset(p, 0, sizeof(*p));
246         p->which = MC_SF;
247         p->name = (char *)xmalloc(SZ_SFNAME+1);
248         *p->name = '\0';
249         p->prefix = (char *)xmalloc(SZ_PREFIX+1);
250         *p->prefix = '\0';
251         p->suffix = (char *)xmalloc(SZ_SUFFIX+1);
252         *p->suffix = '\0';
253         p->parent = parent;
254         p->interval.start = p->interval.end = -1;
255     }
256     return p;
257 }
258 void mc_destroy_subfield(mc_subfield *p)
259 {
260     if (!p)
261         return;
262     
263     if (p->which == MC_SFGROUP || p->which == MC_SFVARIANT)
264     {
265         if (p->u.child)
266             mc_destroy_subfields_recursive(p->u.child);
267     }
268     else if (p->which == MC_SF)
269     {
270         if (p->u.in_line)
271             mc_destroy_field(p->u.in_line);
272     }
273     if (p->name) xfree(p->name);     
274     if (p->prefix) xfree(p->prefix);     
275     if (p->suffix) xfree(p->suffix);
276     if (p->parent) p->parent->next = p->next;
277     xfree(p);
278 }
279 void mc_destroy_subfields_recursive(mc_subfield *p)
280 {
281     if (!p)
282         return;
283
284     mc_destroy_subfields_recursive(p->next);
285         
286     if (p->which == MC_SFGROUP || p->which == MC_SFVARIANT)
287     {
288         if (p->u.child)
289             mc_destroy_subfields_recursive(p->u.child);
290     }
291     else if (p->which == MC_SF)
292     {
293         if (p->u.in_line)
294             mc_destroy_field(p->u.in_line);
295     }
296         
297     if (p->name) xfree(p->name);
298     if (p->prefix) xfree(p->prefix);
299     if (p->suffix) xfree(p->suffix);
300     if (p->parent) p->parent->next = 0;
301     xfree(p);
302 }
303 mc_subfield *mc_getsubfields(mc_context *c, mc_subfield *parent)
304 {
305     mc_subfield *psf=0;
306     mc_token tok = mc_gettoken(c);
307     
308     if (tok == NOP)
309         return 0;
310         
311     if (tok == LGROUP)
312     {
313         if (!(psf = mc_mk_subfield(parent)))
314         {
315             c->errcode = EMCNOMEM;
316             return 0;
317         }
318
319         psf->which = MC_SFGROUP;
320         psf->u.child = mc_getsubfields(c, psf);
321         
322         if (mc_gettoken(c) == RGROUP)
323             psf->next = mc_getsubfields(c, psf);
324         else
325         {
326             c->errcode = EMCSFGROUP;
327             mc_destroy_subfield(psf);
328             return 0;
329         }
330     }
331     else if (tok == LVARIANT)
332     {
333         if (!(psf = mc_mk_subfield(parent)))
334         {
335             c->errcode = EMCNOMEM;
336             return 0;
337         }
338
339         psf->which = MC_SFVARIANT;
340         psf->u.child = mc_getsubfields(c, psf);
341         
342         if (mc_gettoken(c) == RVARIANT)
343             psf->next = mc_getsubfields(c, psf);
344         else
345         {
346             c->errcode = EMCSFVAR;
347             mc_destroy_subfield(psf);
348             return 0;
349         }
350     }
351     else if (tok == RGROUP || tok == RVARIANT || tok == RINLINE)
352     {
353         mc_ungettoken(c);
354         return 0;
355     }
356     else if (tok == REGULAR)
357     {
358         if (!(psf = mc_mk_subfield(parent)))
359         {
360             c->errcode = EMCNOMEM;
361             return 0;
362         }
363
364         mc_ungettoken(c);
365
366         if((mc_getdata(c, psf->prefix, SZ_PREFIX) == SZ_PREFIX) &&
367             (mc_gettoken(c) == SUBFIELD) &&
368                 (mc_getdata(c, psf->name, SZ_SFNAME) == SZ_SFNAME))
369         {
370             mc_token tok = mc_gettoken(c);
371
372             mc_ungettoken(c);
373             
374             if (tok == LINTERVAL)
375             {
376                 mc_getinterval(c, &psf->interval.start, &psf->interval.end);
377             }
378             else if (tok == LINLINE)
379             {
380                 mc_gettoken(c);
381                 psf->u.in_line = mc_getfield(c);
382                 if (mc_gettoken(c) != RINLINE)
383                 {
384                     c->errcode = EMCSFINLINE;
385                     mc_destroy_subfield(psf);
386                     return 0;
387                 }
388             }
389         
390             if (mc_getdata(c, psf->suffix, SZ_SUFFIX) == SZ_SUFFIX)
391             {
392                 psf->which = MC_SF;
393                 psf->next = mc_getsubfields(c, psf);
394             }
395             else
396             {
397                 c->errcode = EMCSF;
398                 mc_destroy_subfield(psf);
399                 return 0;
400             }
401         }
402     }     
403     return psf;
404 }