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