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