Doesn't use the global data1_tabpath (from YAZ). Instead the function
[idzebra-moved-to-github.git] / recctrl / regxread.c
1 /*
2  * Copyright (C) 1994-1996, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: regxread.c,v $
7  * Revision 1.2  1996-10-29 14:02:09  adam
8  * Doesn't use the global data1_tabpath (from YAZ). Instead the function
9  * data1_get_tabpath is used.
10  *
11  * Revision 1.1  1996/10/11 10:57:30  adam
12  * New module recctrl. Used to manage records (extract/retrieval).
13  *
14  * Revision 1.24  1996/06/17 14:25:31  adam
15  * Removed LOG_DEBUG logs; can still be enabled by setting REGX_DEBUG.
16  *
17  * Revision 1.23  1996/06/04 10:19:00  adam
18  * Minor changes - removed include of ctype.h.
19  *
20  * Revision 1.22  1996/06/03  15:23:13  adam
21  * Bug fix: /../ BODY /../ - pattern didn't match EOF.
22  *
23  * Revision 1.21  1996/05/14  16:58:38  adam
24  * Minor change.
25  *
26  * Revision 1.20  1996/05/01  13:46:36  adam
27  * First work on multiple records in one file.
28  * New option, -offset, to the "unread" command in the filter module.
29  *
30  * Revision 1.19  1996/02/12  16:18:20  adam
31  * Yet another bug fix in implementation of unread command.
32  *
33  * Revision 1.18  1996/02/12  16:07:54  adam
34  * Bug fix in new unread command.
35  *
36  * Revision 1.17  1996/02/12  15:56:11  adam
37  * New code command: unread.
38  *
39  * Revision 1.16  1996/01/17  14:57:51  adam
40  * Prototype changed for reader functions in extract/retrieve. File
41  *  is identified by 'void *' instead of 'int.
42  *
43  * Revision 1.15  1996/01/08  19:15:47  adam
44  * New input filter that works!
45  *
46  * Revision 1.14  1996/01/08  09:10:38  adam
47  * Yet another complete rework on this module.
48  *
49  * Revision 1.13  1995/12/15  17:21:50  adam
50  * This version is able to set data.formatted_text in data1-nodes.
51  *
52  * Revision 1.12  1995/12/15  16:20:10  adam
53  * The filter files (*.flt) are read from the path given by data1_tabpath.
54  *
55  * Revision 1.11  1995/12/15  12:35:16  adam
56  * Better logging.
57  *
58  * Revision 1.10  1995/12/15  10:35:36  adam
59  * Misc. bug fixes.
60  *
61  * Revision 1.9  1995/12/14  16:38:48  adam
62  * Completely new attempt to make regular expression parsing.
63  *
64  * Revision 1.8  1995/12/13  17:16:59  adam
65  * Small changes.
66  *
67  * Revision 1.7  1995/12/13  16:51:58  adam
68  * Modified to set last_child in data1_nodes.
69  * Uses destroy handler to free up data text nodes.
70  *
71  * Revision 1.6  1995/12/13  13:45:37  quinn
72  * Changed data1 to use nmem.
73  *
74  * Revision 1.5  1995/12/11  09:12:52  adam
75  * The rec_get function returns NULL if record doesn't exist - will
76  * happen in the server if the result set records have been deleted since
77  * the creation of the set (i.e. the search).
78  * The server saves a result temporarily if it is 'volatile', i.e. the
79  * set is register dependent.
80  *
81  * Revision 1.4  1995/12/05  16:57:40  adam
82  * More work on regular patterns.
83  *
84  * Revision 1.3  1995/12/05  09:37:09  adam
85  * One malloc was renamed to xmalloc.
86  *
87  * Revision 1.2  1995/12/04  17:59:24  adam
88  * More work on regular expression conversion.
89  *
90  * Revision 1.1  1995/12/04  14:25:30  adam
91  * Started work on regular expression parsed input to structured records.
92  *
93  */
94 #include <stdio.h>
95 #include <assert.h>
96 #include <string.h>
97
98 #include <tpath.h>
99 #include <zebrautl.h>
100 #include <dfa.h>
101 #include "grsread.h"
102
103 #define REGX_DEBUG 0
104
105 #define F_WIN_EOF 2000000000
106 #define F_WIN_READ 1
107
108 #define REGX_EOF     0
109 #define REGX_PATTERN 1
110 #define REGX_BODY    2
111 #define REGX_BEGIN   3
112 #define REGX_END     4
113 #define REGX_CODE    5
114
115 struct regxCode {
116     char *str;
117 };
118
119 struct lexRuleAction {
120     int which; 
121     union {
122         struct {
123             struct DFA *dfa;        /* REGX_PATTERN */
124             int body;
125         } pattern;
126         struct regxCode *code;  /* REGX_CODE */
127     } u;
128     struct lexRuleAction *next;
129 };
130
131 struct lexRuleInfo {
132     int no;
133     struct lexRuleAction *actionList;
134 };
135
136 struct lexRule {
137     struct lexRuleInfo info;
138     struct lexRule *next;
139 };
140
141 struct lexTrans {
142     struct DFA *dfa;
143     struct lexRule *rules;
144     struct lexRuleInfo **fastRule;
145     int ruleNo;
146 };
147
148 struct lexSpec {
149     char *name;
150     struct lexTrans trans;
151     int lineNo;
152     NMEM m;
153     void *f_win_fh;
154     void (*f_win_ef)(void *, off_t);
155 #if F_WIN_READ
156     int f_win_start;
157     int f_win_end;
158     int f_win_size;
159     char *f_win_buf;
160     int (*f_win_rf)(void *, char *, size_t);
161     off_t (*f_win_sf)(void *, off_t);
162 #else
163     char *scan_buf;
164     int scan_size;
165 #endif
166     struct lexRuleAction *beginActionList;
167     struct lexRuleAction *endActionList;
168 };
169
170 #if F_WIN_READ
171 static char *f_win_get (struct lexSpec *spec, off_t start_pos, off_t end_pos,
172                         int *size)
173 {
174     int i, r, off;
175
176     if (start_pos < spec->f_win_start || start_pos >= spec->f_win_end)
177     {
178         (*spec->f_win_sf)(spec->f_win_fh, start_pos);
179         spec->f_win_start = start_pos;
180
181         if (!spec->f_win_buf)
182             spec->f_win_buf = xmalloc (spec->f_win_size);
183         *size = (*spec->f_win_rf)(spec->f_win_fh, spec->f_win_buf,
184                                   spec->f_win_size);
185         spec->f_win_end = spec->f_win_start + *size;
186
187         if (*size > end_pos - start_pos)
188             *size = end_pos - start_pos;
189         return spec->f_win_buf;
190     }
191     if (end_pos <= spec->f_win_end)
192     {
193         *size = end_pos - start_pos;
194         return spec->f_win_buf + (start_pos - spec->f_win_start);
195     }
196     off = start_pos - spec->f_win_start;
197     for (i = 0; i<spec->f_win_end - start_pos; i++)
198         spec->f_win_buf[i] = spec->f_win_buf[i + off];
199     r = (*spec->f_win_rf)(spec->f_win_fh,
200                           spec->f_win_buf + i,
201                           spec->f_win_size - i);
202     spec->f_win_start = start_pos;
203     spec->f_win_end += r;
204     *size = i + r;
205     if (*size > end_pos - start_pos)
206         *size = end_pos - start_pos;
207     return spec->f_win_buf;
208 }
209
210 static int f_win_advance (struct lexSpec *spec, int *pos)
211 {
212     int size;
213     char *buf;
214     
215     if (*pos >= spec->f_win_start && *pos < spec->f_win_end)
216         return spec->f_win_buf[(*pos)++ - spec->f_win_start];
217     if (*pos == F_WIN_EOF)
218         return 0;
219     buf = f_win_get (spec, *pos, *pos+1, &size);
220     if (size == 1)
221     {
222         (*pos)++;
223         return *buf;
224     }
225     *pos = F_WIN_EOF;
226     return 0;
227 }
228 #endif
229
230 static void regxCodeDel (struct regxCode **pp)
231 {
232     struct regxCode *p = *pp;
233     if (p)
234     {
235         xfree (p->str); 
236         xfree (p);
237         *pp = NULL;
238     }
239 }
240
241 static void regxCodeMk (struct regxCode **pp, const char *buf, int len)
242 {
243     struct regxCode *p;
244
245     p = xmalloc (sizeof(*p));
246     p->str = xmalloc (len+1);
247     memcpy (p->str, buf, len);
248     p->str[len] = '\0';
249     *pp = p;
250 }
251
252 static struct DFA *lexSpecDFA (void)
253 {
254     struct DFA *dfa;
255
256     dfa = dfa_init ();
257     dfa_parse_cmap_del (dfa, ' ');
258     dfa_parse_cmap_del (dfa, '\t');
259     dfa_parse_cmap_add (dfa, '/', 0);
260     return dfa;
261 }
262
263 static struct lexSpec *lexSpecMk (const char *name)
264 {
265     struct lexSpec *p;
266
267     p = xmalloc (sizeof(*p));
268     p->name = xmalloc (strlen(name)+1);
269     strcpy (p->name, name);
270     p->trans.dfa = lexSpecDFA ();
271     p->trans.rules = NULL;
272     p->trans.fastRule = NULL;
273     p->beginActionList = NULL;
274     p->endActionList = NULL;
275 #if F_WIN_READ
276     p->f_win_buf = NULL;
277 #endif
278     return p;
279 }
280
281 static void actionListDel (struct lexRuleAction **rap)
282 {
283     struct lexRuleAction *ra1, *ra;
284
285     for (ra = *rap; ra; ra = ra1)
286     {
287         ra1 = ra->next;
288         switch (ra->which)
289         {
290         case REGX_PATTERN:
291             dfa_delete (&ra->u.pattern.dfa);
292             break;
293         case REGX_CODE:
294             regxCodeDel (&ra->u.code);
295             break;
296         }
297         xfree (ra);
298     }
299     *rap = NULL;
300 }
301
302 static void lexSpecDel (struct lexSpec **pp)
303 {
304     struct lexSpec *p;
305     struct lexRule *rp, *rp1;
306
307     assert (pp);
308     p = *pp;
309     if (!p)
310         return ;
311     dfa_delete (&p->trans.dfa);
312     xfree (p->name);
313     xfree (p->trans.fastRule);
314     for (rp = p->trans.rules; rp; rp = rp1)
315     {
316         actionListDel (&rp->info.actionList);
317         xfree (rp);
318     }
319     actionListDel (&p->beginActionList);
320     actionListDel (&p->endActionList);
321 #if F_WIN_READ
322     xfree (p->f_win_buf);
323 #endif
324     xfree (p);
325     *pp = NULL;
326 }
327
328 static int readParseToken (const char **cpp, int *len)
329 {
330     const char *cp = *cpp;
331     char cmd[32];
332     int i, level;
333
334     while (*cp == ' ' || *cp == '\t' || *cp == '\n')
335         cp++;
336     switch (*cp)
337     {
338     case '\0':
339         return 0;
340     case '/':
341         *cpp = cp+1;
342         return REGX_PATTERN;
343     case '{':
344         *cpp = cp+1;
345         level = 1;
346         while (*++cp)
347         {
348             if (*cp == '{')
349                 level++;
350             else if (*cp == '}')
351             {
352                 level--;
353                 if (level == 0)
354                     break;
355             }
356         }
357         *len = cp - *cpp;
358         return REGX_CODE;
359     default:
360         i = 0;
361         while (1)
362         {
363             if (*cp >= 'a' && *cp <= 'z')
364                 cmd[i] = *cp;
365             else if (*cp >= 'A' && *cp <= 'Z')
366                 cmd[i] = *cp + 'a' - 'A';
367             else
368                 break;
369             if (i > sizeof(cmd)-2)
370                 break;
371             i++;
372             cp++;
373         }
374         cmd[i] = '\0';
375         if (i == 0)
376         {
377             logf (LOG_WARN, "Bad character %d %c", *cp, *cp);
378             cp++;
379             while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
380                 cp++;
381             *cpp = cp;
382             return 0;
383         }
384         *cpp = cp;
385         if (!strcmp (cmd, "begin"))
386             return REGX_BEGIN;
387         else if (!strcmp (cmd, "end"))
388             return REGX_END;
389         else if (!strcmp (cmd, "body"))
390             return REGX_BODY;
391         else
392         {
393             logf (LOG_WARN, "Bad command %s", cmd);
394             return 0;
395         }
396     }
397 }
398
399 static int actionListMk (struct lexSpec *spec, const char *s,
400                          struct lexRuleAction **ap)
401 {
402     int r, tok, len;
403     int bodyMark = 0;
404
405     while ((tok = readParseToken (&s, &len)))
406     {
407         switch (tok)
408         {
409         case REGX_BODY:
410             bodyMark = 1;
411             continue;
412         case REGX_CODE:
413             *ap = xmalloc (sizeof(**ap));
414             (*ap)->which = tok;
415             regxCodeMk (&(*ap)->u.code, s, len);
416             s += len+1;
417             break;
418         case REGX_PATTERN:
419             *ap = xmalloc (sizeof(**ap));
420             (*ap)->which = tok;
421             (*ap)->u.pattern.body = bodyMark;
422             bodyMark = 0;
423             (*ap)->u.pattern.dfa = lexSpecDFA ();
424             r = dfa_parse ((*ap)->u.pattern.dfa, &s);
425             if (r || *s != '/')
426             {
427                 xfree (*ap);
428                 *ap = NULL;
429                 logf (LOG_WARN, "Regular expression error. r=%d", r);
430                 return -1;
431             }
432             dfa_mkstate ((*ap)->u.pattern.dfa);
433             s++;
434             break;
435         case REGX_BEGIN:
436             logf (LOG_WARN, "Cannot use begin here");
437             continue;
438         case REGX_END:
439             *ap = xmalloc (sizeof(**ap));
440             (*ap)->which = tok;
441             break;
442         }
443         ap = &(*ap)->next;
444     }
445     *ap = NULL;
446     return 0;
447 }
448
449 int readOneSpec (struct lexSpec *spec, const char *s)
450 {
451     int tok, len;
452
453     tok = readParseToken (&s, &len);
454     if (tok == REGX_BEGIN)
455     {
456         actionListDel (&spec->beginActionList);
457         actionListMk (spec, s, &spec->beginActionList);
458     }
459     else if (tok == REGX_END)
460     {
461         actionListDel (&spec->endActionList);
462         actionListMk (spec, s, &spec->endActionList);
463     }
464     else if (tok == REGX_PATTERN)
465     {
466         int r;
467         struct lexRule *rp;
468         r = dfa_parse (spec->trans.dfa, &s);
469         if (r)
470         {
471             logf (LOG_WARN, "Regular expression error. r=%d", r);
472             return -1;
473         }
474         if (*s != '/')
475         {
476             logf (LOG_WARN, "Expects / at end of pattern. got %c", *s);
477             return -1;
478         }
479         s++;
480         rp = xmalloc (sizeof(*rp));
481         rp->info.no = spec->trans.ruleNo++;
482         rp->next = spec->trans.rules;
483         spec->trans.rules = rp;
484         actionListMk (spec, s, &rp->info.actionList);
485     }
486     return 0;
487 }
488
489 int readFileSpec (struct lexSpec *spec)
490 {
491     char *lineBuf;
492     int lineSize = 512;
493     struct lexRule *rp;
494     int c, i, errors = 0;
495     FILE *spec_inf;
496
497     lineBuf = xmalloc (1+lineSize);
498     logf (LOG_LOG, "Reading spec %s", spec->name);
499     sprintf (lineBuf, "%s.flt", spec->name);
500     if (!(spec_inf = yaz_path_fopen (data1_get_tabpath(), lineBuf, "r")))
501     {
502         logf (LOG_ERRNO|LOG_WARN, "Cannot read spec file %s", spec->name);
503         xfree (lineBuf);
504         return -1;
505     }
506     spec->lineNo = 0;
507     spec->trans.ruleNo = 1;
508     c = getc (spec_inf);
509     while (c != EOF)
510     {
511         int off = 0;
512         if (c == '#' || c == '\n' || c == ' ' || c == '\t')
513         {
514             while (c != '\n' && c != EOF)
515                 c = getc (spec_inf);
516             spec->lineNo++;
517             if (c == '\n')
518                 c = getc (spec_inf);
519         }
520         else
521         {
522             int addLine = 0;
523
524             lineBuf[off++] = c;
525             while (1)
526             {
527                 int c1 = c;
528                 c = getc (spec_inf);
529                 if (c == EOF)
530                     break;
531                 if (c1 == '\n')
532                 {
533                     if (c != ' ' && c != '\t')
534                         break;
535                     addLine++;
536                 }
537                 lineBuf[off] = c;
538                 if (off < lineSize)
539                     off++;
540             }
541             lineBuf[off] = '\0';
542             readOneSpec (spec, lineBuf);
543             spec->lineNo += addLine;
544         }
545     }
546     fclose (spec_inf);
547     xfree (lineBuf);
548     spec->trans.fastRule = xmalloc (sizeof(*spec->trans.fastRule) *
549                                    spec->trans.ruleNo);
550     for (i = 0; i<spec->trans.ruleNo; i++)
551         spec->trans.fastRule[i] = NULL;
552     for (rp = spec->trans.rules; rp; rp = rp->next)
553         spec->trans.fastRule[rp->info.no] = &rp->info;
554     if (errors)
555         return -1;
556 #if 0
557     debug_dfa_trav = 1;
558     debug_dfa_tran = 1;
559     debug_dfa_followpos = 1;
560     dfa_verbose = 1;
561 #endif
562     dfa_mkstate (spec->trans.dfa);
563     return 0;
564 }
565
566 static struct lexSpec *curLexSpec = NULL;
567
568 static void destroy_data (struct data1_node *n)
569 {
570     assert (n->which == DATA1N_data);
571     xfree (n->u.data.data);
572 }
573
574 static void execData (struct lexSpec *spec,
575                       data1_node **d1_stack, int *d1_level,
576                       const char *ebuf, int elen, int formatted_text)
577 {
578     struct data1_node *res, *parent;
579
580 #if REGX_DEBUG
581     if (elen > 40)
582         logf (LOG_DEBUG, "execData %.15s ... %.*s", ebuf, 15, ebuf + elen-15);
583     else if (elen > 0)
584         logf (LOG_DEBUG, "execData %.*s", elen, ebuf);
585     else 
586         logf (LOG_DEBUG, "execData len=%d", elen);
587 #endif
588         
589         if (*d1_level <= 1)
590         return;
591
592     parent = d1_stack[*d1_level -1];
593     assert (parent);
594     if ((res=d1_stack[*d1_level]) && res->which == DATA1N_data)
595     {
596         if (elen + res->u.data.len <= DATA1_LOCALDATA)
597             memcpy (res->u.data.data + res->u.data.len, ebuf, elen);
598         else
599         {
600             char *nb = xmalloc (elen + res->u.data.len);
601             memcpy (nb, res->u.data.data, res->u.data.len);
602             memcpy (nb + res->u.data.len, ebuf, elen);
603             if (res->u.data.len > DATA1_LOCALDATA)
604                 xfree (res->u.data.data);
605             res->u.data.data = nb;
606             res->destroy = destroy_data;
607         }
608         res->u.data.len += elen;
609     }
610     else
611     {
612         res = data1_mk_node (spec->m);
613         res->parent = parent;
614         res->which = DATA1N_data;
615         res->u.data.what = DATA1I_text;
616         res->u.data.len = elen;
617         res->u.data.formatted_text = formatted_text;
618         if (elen > DATA1_LOCALDATA)
619         {
620             res->u.data.data = xmalloc (elen);
621             res->destroy = destroy_data;
622         }
623         else
624             res->u.data.data = res->lbuf;
625         memcpy (res->u.data.data, ebuf, elen);
626         res->root = parent->root;
627         
628         parent->num_children++;
629         parent->last_child = res;
630         if (d1_stack[*d1_level])
631             d1_stack[*d1_level]->next = res;
632         else
633             parent->child = res;
634         d1_stack[*d1_level] = res;
635     }
636 }
637
638 static void execDataP (struct lexSpec *spec,
639                        data1_node **d1_stack, int *d1_level,
640                        const char *ebuf, int elen, int formatted_text)
641 {
642     execData (spec, d1_stack, d1_level, ebuf, elen, formatted_text);
643 }
644
645
646 static void tagBegin (struct lexSpec *spec, 
647                       data1_node **d1_stack, int *d1_level,
648                       const char *tag, int len)
649 {
650     struct data1_node *parent = d1_stack[*d1_level -1];
651     data1_element *elem = NULL;
652     data1_node *partag = get_parent_tag(parent);
653     data1_node *res;
654     data1_element *e = NULL;
655     int localtag = 0;
656
657     if (*d1_level == 0)
658     {
659         logf (LOG_WARN, "In element begin. No record type defined");
660         return ;
661     }
662     
663     res = data1_mk_node (spec->m);
664     res->parent = parent;
665     res->which = DATA1N_tag;
666     res->u.tag.tag = res->lbuf;
667
668     if (len >= DATA1_LOCALDATA)
669         len = DATA1_LOCALDATA-1;
670
671     memcpy (res->u.tag.tag, tag, len);
672     res->u.tag.tag[len] = '\0';
673    
674 #if REGX_DEBUG 
675     logf (LOG_DEBUG, "Tag begin %s (%d)", res->u.tag.tag, *d1_level);
676 #endif
677     if (parent->which == DATA1N_variant)
678         return ;
679     if (partag)
680         if (!(e = partag->u.tag.element))
681             localtag = 1;
682     
683     elem = data1_getelementbytagname (d1_stack[0]->u.root.absyn, e,
684                                       res->u.tag.tag);
685     
686     res->u.tag.element = elem;
687     res->u.tag.node_selected = 0;
688     res->u.tag.make_variantlist = 0;
689     res->u.tag.no_data_requested = 0;
690     res->root = parent->root;
691     parent->num_children++;
692     parent->last_child = res;
693     if (d1_stack[*d1_level])
694         d1_stack[*d1_level]->next = res;
695     else
696         parent->child = res;
697     d1_stack[*d1_level] = res;
698     d1_stack[++(*d1_level)] = NULL;
699 }
700
701 static void tagEnd (struct lexSpec *spec, 
702                     data1_node **d1_stack, int *d1_level,
703                     const char *tag, int len)
704 {
705     while (*d1_level > 1)
706     {
707         (*d1_level)--;
708         if (!tag ||
709             (strlen(d1_stack[*d1_level]->u.tag.tag) == len &&
710              !memcmp (d1_stack[*d1_level]->u.tag.tag, tag, len)))
711             break;
712     }
713 #if REGX_DEBUG
714     logf (LOG_DEBUG, "Tag end (%d)", *d1_level);
715 #endif
716 }
717
718
719 static int tryMatch (struct lexSpec *spec, int *pptr, int *mptr,
720                      struct DFA *dfa)
721 {
722     struct DFA_state *state = dfa->states[0];
723     struct DFA_tran *t;
724     unsigned char c;
725 #if F_WIN_READ
726     unsigned char c_prev = 0;
727 #endif
728     int ptr = *pptr;
729     int start_ptr = *pptr;
730     int last_rule = 0;
731     int last_ptr = 0;
732     int i;
733
734     while (1)
735     {
736 #if F_WIN_READ
737         c = f_win_advance (spec, &ptr);
738         if (ptr == F_WIN_EOF)
739         {
740             if (last_rule)
741             {
742                 *mptr = start_ptr;
743                 *pptr = last_ptr;
744                 return 1;
745             }
746             break;
747         }
748 #else
749         if (ptr == spec->scan_size)
750         {
751             if (last_rule)
752             {
753                 *mptr = start_ptr;
754                 *pptr = last_ptr;
755                 return 1;
756             }
757             break;
758         }
759         c = spec->scan_buf[ptr++];
760 #endif
761         t = state->trans;
762         i = state->tran_no;
763         while (1)
764             if (--i < 0)
765             {
766                 if (last_rule)
767                 {
768                     *mptr = start_ptr;     /* match starts here */
769                     *pptr = last_ptr;      /* match end here (+1) */
770                     return 1;
771                 }
772                 state = dfa->states[0];
773                 start_ptr = ptr;
774 #if F_WIN_READ
775                 c_prev = c;
776 #endif
777                 break;
778             }
779             else if (c >= t->ch[0] && c <= t->ch[1])
780             {
781                 state = dfa->states[t->to];
782                 if (state->rule_no)
783                 {
784 #if F_WIN_READ
785                     if (c_prev == '\n')
786                     {
787                         last_rule = state->rule_no;
788                         last_ptr = ptr;
789                     }
790                     else
791                     {
792                         last_rule = state->rule_nno;
793                         last_ptr = ptr;
794                     }
795 #else
796                     last_rule = state->rule_no;
797                     last_ptr = ptr;
798 #endif
799                 }
800                 break;
801             }
802             else
803                 t++;
804     }
805     return 0;
806 }
807
808 static int execTok (struct lexSpec *spec, const char **src,
809                     int arg_no, int *arg_start, int *arg_end,
810                     const char **tokBuf, int *tokLen)
811 {
812     const char *s = *src;
813
814     while (*s == ' ' || *s == '\t')
815         s++;
816     if (!*s)
817         return 0;
818     if (*s == '$' && s[1] >= '0' && s[1] <= '9')
819     {
820         int n = 0;
821         s++;
822         while (*s >= '0' && *s <= '9')
823             n = n*10 + (*s++ -'0');
824         if (arg_no == 0)
825         {
826             *tokBuf = "";
827             *tokLen = 0;
828         }
829         else
830         {
831             if (n >= arg_no)
832                 n = arg_no-1;
833 #if F_WIN_READ
834             *tokBuf = f_win_get (spec, arg_start[n], arg_end[n], tokLen);
835 #else
836             *tokBuf = spec->scan_buf + arg_start[n];
837             *tokLen = arg_end[n] - arg_start[n];
838 #endif
839         }
840     }
841     else if (*s == '\"')
842     {
843         *tokBuf = ++s;
844         while (*s && *s != '\"')
845             s++;
846         *tokLen = s - *tokBuf;
847         if (*s)
848             s++;
849         *src = s;
850     }
851     else if (*s == '\n' || *s == ';')
852     {
853         *src = s+1;
854         return 1;
855     }
856     else if (*s == '-')
857     {
858         *tokBuf = s++;
859         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != ';')
860             s++;
861         *tokLen = s - *tokBuf;
862         *src = s;
863         return 3;
864     }
865     else
866     {
867         *tokBuf = s++;
868         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != ';')
869             s++;
870         *tokLen = s - *tokBuf;
871     }
872     *src = s;
873     return 2;
874 }
875
876 static char *regxStrz (const char *src, int len)
877 {
878     static char str[64];
879     
880     if (len > 63)
881         len = 63;
882     memcpy (str, src, len);
883     str[len] = '\0';
884     return str;
885 }
886
887 static int execCode (struct lexSpec *spec,
888                      int arg_no, int *arg_start, int *arg_end, int *pptr,
889                      struct regxCode *code,
890                      data1_node **d1_stack, int *d1_level)
891 {
892     const char *s = code->str;
893     int cmd_len, r;
894     int returnCode = 1;
895     const char *cmd_str;
896     
897     r = execTok (spec, &s, arg_no, arg_start, arg_end, &cmd_str, &cmd_len);
898     while (r)
899     {
900         char *p;
901         
902         if (r == 1)
903         {
904             r = execTok (spec, &s, arg_no, arg_start, arg_end,
905                          &cmd_str, &cmd_len);
906             continue;
907         }
908         p = regxStrz (cmd_str, cmd_len);
909         if (!strcmp (p, "begin"))
910         {
911             r = execTok (spec, &s, arg_no, arg_start, arg_end,
912                          &cmd_str, &cmd_len);
913             if (r < 2)
914                 continue;
915             p = regxStrz (cmd_str, cmd_len);
916             if (!strcmp (p, "record"))
917             {
918                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
919                              &cmd_str, &cmd_len);
920                 if (r < 2)
921                     continue;
922                 if (*d1_level == 0)
923                 {
924                     static char absynName[64];
925                     data1_absyn *absyn;
926
927                     if (cmd_len > 63)
928                         cmd_len = 63;
929                     memcpy (absynName, cmd_str, cmd_len);
930                     absynName[cmd_len] = '\0';
931
932 #if REGX_DEBUG
933                     logf (LOG_DEBUG, "begin record %s", absynName);
934 #endif
935                     if (!(absyn = data1_get_absyn (absynName)))
936                         logf (LOG_WARN, "Unknown tagset: %s", absynName);
937                     else
938                     {
939                         data1_node *res;
940
941                         res = data1_mk_node (spec->m);
942                         res->which = DATA1N_root;
943                         res->u.root.type = absynName;
944                         res->u.root.absyn = absyn;
945                         res->root = res;
946                         
947                         d1_stack[*d1_level] = res;
948                         d1_stack[++(*d1_level)] = NULL;
949                     }
950                 }
951                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
952                              &cmd_str, &cmd_len);
953             }
954             else if (!strcmp (p, "element"))
955             {
956                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
957                              &cmd_str, &cmd_len);
958                 if (r < 2)
959                     continue;
960                 tagBegin (spec, d1_stack, d1_level, cmd_str, cmd_len);
961                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
962                              &cmd_str, &cmd_len);
963             }
964         }
965         else if (!strcmp (p, "end"))
966         {
967             r = execTok (spec, &s, arg_no, arg_start, arg_end,
968                          &cmd_str, &cmd_len);
969             if (r > 1)
970             {
971                 p = regxStrz (cmd_str, cmd_len);
972                 if (!strcmp (p, "record"))
973                 {
974                     *d1_level = 0;
975                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
976                                  &cmd_str, &cmd_len);
977 #if REGX_DEBUG
978                     logf (LOG_DEBUG, "end record");
979 #endif
980                     returnCode = 0;
981                 }
982                 else if (!strcmp (p, "element"))
983                 {
984                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
985                                  &cmd_str, &cmd_len);
986                     if (r > 2)
987                     {
988                         tagEnd (spec, d1_stack, d1_level, cmd_str, cmd_len);
989                         r = execTok (spec, &s, arg_no, arg_start, arg_end,
990                                      &cmd_str, &cmd_len);
991                     }
992                     else
993                         tagEnd (spec, d1_stack, d1_level, NULL, 0);
994                 }
995                 else
996                     logf (LOG_WARN, "Missing record/element/variant");
997             }
998             else
999                 logf (LOG_WARN, "Missing record/element/variant");
1000         }
1001         else if (!strcmp (p, "data"))
1002         {
1003             int textFlag = 0;
1004             int element_len;
1005             const char *element_str = NULL;
1006             
1007             while ((r = execTok (spec, &s, arg_no, arg_start, arg_end,
1008                                  &cmd_str, &cmd_len)) == 3)
1009             {
1010                 if (cmd_len==5 && !memcmp ("-text", cmd_str, cmd_len))
1011                     textFlag = 1;
1012                 else if (cmd_len==8 && !memcmp ("-element", cmd_str, cmd_len))
1013                 {
1014                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
1015                                  &element_str, &element_len);
1016                     if (r < 2)
1017                         break;
1018                 }
1019                 else 
1020                     logf (LOG_WARN, "Bad data option: %.*s",
1021                           cmd_len, cmd_str);
1022             }
1023             if (r != 2)
1024             {
1025                 logf (LOG_WARN, "Missing data item after data");
1026                 continue;
1027             }
1028             if (element_str)
1029                 tagBegin (spec, d1_stack, d1_level, element_str, element_len);
1030             do
1031             {
1032                 execData (spec, d1_stack, d1_level, cmd_str, cmd_len,
1033                           textFlag);
1034                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1035                          &cmd_str, &cmd_len);
1036             } while (r > 1);
1037             if (element_str)
1038                 tagEnd (spec, d1_stack, d1_level, NULL, 0);
1039         }
1040         else if (!strcmp (p, "unread"))
1041         {
1042             int no, offset;
1043             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1044                          &cmd_str, &cmd_len);
1045             if (r==3 && cmd_len == 7 && !memcmp ("-offset", cmd_str, cmd_len))
1046             {
1047                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1048                              &cmd_str, &cmd_len);
1049                 if (r < 2)
1050                 {
1051                     logf (LOG_WARN, "Missing number after -offset");
1052                     continue;
1053                 }
1054                 p = regxStrz (cmd_str, cmd_len);
1055                 offset = atoi (p);
1056                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1057                              &cmd_str, &cmd_len);
1058             }
1059             else
1060                 offset = 0;
1061             if (r < 2)
1062             {
1063                 logf (LOG_WARN, "Missing index after unread command");
1064                 continue;
1065             }
1066             if (cmd_len != 1 || *cmd_str < '0' || *cmd_str > '9')
1067             {
1068                 logf (LOG_WARN, "Bad index after unread command");
1069                 continue;
1070             }
1071             else
1072             {
1073                 no = *cmd_str - '0';
1074                 if (no >= arg_no)
1075                     no = arg_no - 1;
1076                 *pptr = arg_start[no] + offset;
1077             }
1078             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1079                          &cmd_str, &cmd_len);
1080         }
1081         else
1082         {
1083             logf (LOG_WARN, "Unknown code command: %.*s", cmd_len, cmd_str);
1084             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1085                          &cmd_str, &cmd_len);
1086             continue;
1087         }
1088         if (r > 1)
1089         {
1090             logf (LOG_WARN, "Ignoring token %.*s", cmd_len, cmd_str);
1091             do {
1092                 r = execTok (spec, &s, arg_no, arg_start, arg_end, &cmd_str,
1093                              &cmd_len);
1094             } while (r > 1);
1095         }
1096     }
1097     return returnCode;
1098 }
1099
1100
1101 static int execAction (struct lexSpec *spec, struct lexRuleAction *ap,
1102                        data1_node **d1_stack, int *d1_level,
1103                        int start_ptr, int *pptr)
1104 {
1105     int sptr;
1106     int arg_start[20];
1107     int arg_end[20];
1108     int arg_no = 1;
1109
1110     arg_start[0] = start_ptr;
1111     arg_end[0] = *pptr;
1112
1113     while (ap)
1114     {
1115         switch (ap->which)
1116         {
1117         case REGX_PATTERN:
1118             if (ap->u.pattern.body)
1119             {
1120                 arg_start[arg_no] = *pptr;
1121                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1122                 {
1123                     arg_end[arg_no] = F_WIN_EOF;
1124                     arg_no++;
1125                     arg_start[arg_no] = F_WIN_EOF;
1126                     arg_end[arg_no] = F_WIN_EOF;
1127 /* return 1*/
1128                 }
1129                 else
1130                 {
1131                     arg_end[arg_no] = sptr;
1132                     arg_no++;
1133                     arg_start[arg_no] = sptr;
1134                     arg_end[arg_no] = *pptr;
1135                 }
1136             }
1137             else
1138             {
1139                 arg_start[arg_no] = *pptr;
1140                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1141                     return 1;
1142                 if (sptr != arg_start[arg_no])
1143                     return 1;
1144                 arg_end[arg_no] = *pptr;
1145             }
1146             arg_no++;
1147             break;
1148         case REGX_CODE:
1149             if (!execCode (spec, arg_no, arg_start, arg_end, pptr,
1150                            ap->u.code, d1_stack, d1_level))
1151                 return 0;
1152             break;
1153         case REGX_END:
1154             arg_start[arg_no] = *pptr;
1155 #if F_WIN_READ
1156             arg_end[arg_no] = F_WIN_EOF;
1157 #else
1158             arg_end[arg_no] = spec->scan_size;
1159 #endif
1160             arg_no++;
1161 #if F_WIN_READ
1162             *pptr = F_WIN_EOF;
1163 #else
1164             *pptr = spec->scan_size;
1165 #endif
1166         }
1167         ap = ap->next;
1168     }
1169     return 1;
1170 }
1171
1172 static int execRule (struct lexSpec *spec, struct lexTrans *trans,
1173                      data1_node **d1_stack, int *d1_level,
1174                      int ruleNo, int start_ptr, int *pptr)
1175 {
1176 #if REGX_DEBUG
1177     logf (LOG_DEBUG, "execRule %d", ruleNo);
1178 #endif
1179     return execAction (spec, trans->fastRule[ruleNo]->actionList,
1180                        d1_stack, d1_level, start_ptr, pptr);
1181 }
1182
1183 data1_node *lexNode (struct lexSpec *spec, struct lexTrans *trans,
1184                      data1_node **d1_stack, int *d1_level,
1185                      int *ptr)
1186 {
1187     struct DFA_state *state = trans->dfa->states[0];
1188     struct DFA_tran *t;
1189     unsigned char c;
1190 #if F_WIN_READ
1191     unsigned char c_prev = '\n';
1192 #endif
1193     int i;
1194     int last_rule = 0;
1195     int last_ptr = *ptr;
1196     int start_ptr = *ptr;
1197     int skip_ptr = *ptr;
1198
1199     while (1)
1200     {
1201 #if F_WIN_READ
1202         c = f_win_advance (spec, ptr);
1203         if (*ptr == F_WIN_EOF)
1204         {
1205             if (last_rule)
1206             {
1207                 if (skip_ptr < start_ptr)
1208                 {
1209                     int size;
1210                     char *buf;
1211                     buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1212                     execDataP (spec, d1_stack, d1_level, buf, size, 0);
1213                 }
1214                 *ptr = last_ptr;
1215                 if (!execRule (spec, trans, d1_stack, d1_level, last_rule,
1216                                start_ptr, ptr))
1217                     break;
1218                 skip_ptr = *ptr;
1219                 last_rule = 0;
1220             }
1221             else if (skip_ptr < *ptr)
1222             {
1223                 int size;
1224                 char *buf;
1225                 buf = f_win_get (spec, skip_ptr, *ptr, &size);
1226                 execDataP (spec, d1_stack, d1_level, buf, size, 0);
1227             }
1228             if (*ptr == F_WIN_EOF)
1229                 break;
1230         }
1231 #else
1232         if (*ptr == spec->scan_size)
1233         {
1234             if (last_rule)
1235             {
1236                 if (skip_ptr < start_ptr)
1237                 {
1238                     execDataP (spec, d1_stack, d1_level,
1239                               spec->scan_buf + skip_ptr, start_ptr - skip_ptr,
1240                               0);
1241                 }
1242                 *ptr = last_ptr;
1243                 execRule (spec, trans, d1_stack, d1_level, last_rule,
1244                           start_ptr, ptr);
1245                 skip_ptr = *ptr;
1246                 last_rule = 0;
1247             }
1248             else if (skip_ptr < *ptr)
1249             {
1250                 execDataP (spec, d1_stack, d1_level,
1251                           spec->scan_buf + skip_ptr, *ptr - skip_ptr, 0);
1252             }
1253             if (*ptr == spec->scan_size)
1254                 break;
1255         }
1256         c = spec->scan_buf[(*ptr)++];
1257 #endif
1258         t = state->trans;
1259         i = state->tran_no;
1260         while (1)
1261             if (--i < 0)
1262             {   /* no transition for character c ... */
1263                 if (last_rule)
1264                 {
1265                     if (skip_ptr < start_ptr)
1266                     {
1267 #if F_WIN_READ
1268                         int size;
1269                         char *buf;
1270                         buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1271                         execDataP (spec, d1_stack, d1_level, buf, size, 0);
1272 #else                        
1273                         execDataP (spec, d1_stack, d1_level,
1274                                   spec->scan_buf + skip_ptr,
1275                                   start_ptr - skip_ptr, 0);
1276 #endif
1277                     }
1278                     *ptr = last_ptr;
1279                     if (!execRule (spec, trans, d1_stack, d1_level, last_rule,
1280                                    start_ptr, ptr))
1281                     {
1282                         if (spec->f_win_ef && *ptr != F_WIN_EOF)
1283                             (*spec->f_win_ef)(spec->f_win_fh, *ptr);
1284                         return NULL;
1285                     }
1286                     skip_ptr = *ptr;
1287                     last_rule = 0;
1288                     start_ptr = *ptr;
1289 #if F_WIN_READ
1290                     if (start_ptr > 0)
1291                     {
1292                         --start_ptr;
1293                         c_prev = f_win_advance (spec, &start_ptr);
1294                     }
1295 #endif
1296                 }
1297                 else
1298                 {
1299 #if F_WIN_READ
1300                     c_prev = f_win_advance (spec, &start_ptr);
1301                     *ptr = start_ptr;
1302 #else
1303                     *ptr = ++start_ptr;
1304 #endif
1305                 }
1306                 state = trans->dfa->states[0];
1307                 break;
1308             }
1309             else if (c >= t->ch[0] && c <= t->ch[1])
1310             {   /* transition ... */
1311                 state = trans->dfa->states[t->to];
1312                 if (state->rule_no)
1313                 {
1314 #if F_WIN_READ
1315                     if (c_prev == '\n')
1316                     {
1317                         last_rule = state->rule_no;
1318                         last_ptr = *ptr;
1319                     } 
1320                     else if (state->rule_nno)
1321                     {
1322                         last_rule = state->rule_nno;
1323                         last_ptr = *ptr;
1324                     }
1325 #else
1326                     if (!start_ptr || spec->scan_buf[start_ptr-1] == '\n')
1327                     {
1328                         last_rule = state->rule_no;
1329                         last_ptr = *ptr;
1330                     } 
1331                     else if (state->rule_nno)
1332                     {
1333                         last_rule = state->rule_nno;
1334                         last_ptr = *ptr;
1335                     }
1336 #endif
1337                 }
1338                 break;
1339             }
1340             else
1341                 t++;
1342     }
1343     return NULL;
1344 }
1345
1346 static data1_node *lexRoot (struct lexSpec *spec, off_t offset)
1347 {
1348     data1_node *d1_stack[512];
1349     int d1_level = 0;
1350     int ptr = offset;
1351
1352     d1_stack[d1_level] = NULL;
1353     if (spec->beginActionList)
1354         execAction (spec, spec->beginActionList,
1355                     d1_stack, &d1_level, 0, &ptr);
1356     lexNode (spec, &spec->trans, d1_stack, &d1_level, &ptr);
1357     if (spec->endActionList)
1358         execAction (spec, spec->endActionList,
1359                     d1_stack, &d1_level, ptr, &ptr);
1360     return *d1_stack;
1361 }
1362
1363 data1_node *grs_read_regx (struct grs_read_info *p)
1364 /*
1365                              int (*rf)(void *, char *, size_t),
1366                              off_t (*sf)(void *, off_t),
1367                              void (*ef)(void *, off_t),
1368                              void *fh,
1369                              off_t offset,
1370                              const char *name, NMEM m
1371 */
1372 {
1373     int res;
1374 #if !F_WIN_READ
1375     static int size;
1376     int rd = 0;
1377 #endif
1378     data1_node *n;
1379
1380 #if REGX_DEBUG
1381     logf (LOG_DEBUG, "data1_read_regx, offset=%ld type=%s",(long) offset,
1382           name);
1383 #endif
1384     if (!curLexSpec || strcmp (curLexSpec->name, p->type))
1385     {
1386         if (curLexSpec)
1387             lexSpecDel (&curLexSpec);
1388         curLexSpec = lexSpecMk (p->type);
1389         res = readFileSpec (curLexSpec);
1390         if (res)
1391         {
1392             lexSpecDel (&curLexSpec);
1393             return NULL;
1394         }
1395     }
1396 #if F_WIN_READ
1397     if (!p->offset)
1398     {
1399         curLexSpec->f_win_start = 0;
1400         curLexSpec->f_win_end = 0;
1401         curLexSpec->f_win_rf = p->readf;
1402         curLexSpec->f_win_sf = p->seekf;
1403         curLexSpec->f_win_fh = p->fh;
1404         curLexSpec->f_win_ef = p->endf;
1405         curLexSpec->f_win_size = 500000;
1406     }
1407 #else
1408     if (!(curLexSpec->scan_buf = xmalloc (size = 4096)))
1409         abort();
1410     do
1411     {
1412         if (rd+4096 > size && !(curLexSpec->scan_buf
1413                                 = xrealloc (curLexSpec->scan_buf, size *= 2)))
1414             abort();
1415         if ((res = (*rf)(fh, curLexSpec->scan_buf + rd, 4096)) < 0)
1416             return NULL;
1417         rd += res;
1418     } while (res); 
1419     curLexSpec->scan_size = rd;
1420 #endif
1421     curLexSpec->m = p->mem;
1422     n = lexRoot (curLexSpec, p->offset);
1423 #if !F_WIN_READ
1424     xfree (curLexSpec->scan_buf);
1425 #endif
1426     return n;
1427 }