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