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