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