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