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