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