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