data1 cleanup
[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.40 2002-05-03 13:50:25 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_node (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_node (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_node (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_node (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_absyn *absyn;
1035         data1_node *res;
1036
1037 #if REGX_DEBUG
1038         logf (LOG_LOG, "begin record %s", absynName);
1039 #endif
1040         absyn = data1_get_absyn (spec->dh, absynName);
1041         
1042         res = data1_mk_node (spec->dh, spec->m);
1043         res->which = DATA1N_root;
1044         res->u.root.type =
1045             data1_insert_string(spec->dh, res, spec->m, absynName);
1046         res->u.root.absyn = absyn;
1047         res->root = res;
1048         
1049         spec->d1_stack[spec->d1_level] = res;
1050         spec->d1_stack[++(spec->d1_level)] = NULL;
1051     }
1052     else if (!strcmp(argv[1], "element") && argc == 3)
1053     {
1054         tagBegin (spec, argv[2], strlen(argv[2]));
1055     }
1056     else if (!strcmp (argv[1], "variant") && argc == 5)
1057     {
1058         variantBegin (spec, argv[2], strlen(argv[2]),
1059                       argv[3], strlen(argv[3]),
1060                       argv[4], strlen(argv[4]));
1061     }
1062     else if (!strcmp (argv[1], "context") && argc == 3)
1063     {
1064         struct lexContext *lc = spec->context;
1065 #if REGX_DEBUG
1066         logf (LOG_LOG, "begin context %s",argv[2]);
1067 #endif
1068         while (lc && strcmp (argv[2], lc->name))
1069             lc = lc->next;
1070         if (lc)
1071         {
1072             spec->context_stack[++(spec->context_stack_top)] = lc;
1073         }
1074         else
1075             logf (LOG_WARN, "unknown context %s", argv[2]);
1076     }
1077     else
1078         return TCL_ERROR;
1079     return TCL_OK;
1080 }
1081
1082 static int cmd_tcl_end (ClientData clientData, Tcl_Interp *interp,
1083                         int argc, char **argv)
1084 {
1085     struct lexSpec *spec = (struct lexSpec *) clientData;
1086     if (argc < 2)
1087         return TCL_ERROR;
1088     
1089     if (!strcmp (argv[1], "record"))
1090     {
1091         while (spec->d1_level)
1092         {
1093             tagDataRelease (spec);
1094             (spec->d1_level)--;
1095         }
1096 #if REGX_DEBUG
1097         logf (LOG_LOG, "end record");
1098 #endif
1099         spec->stop_flag = 1;
1100     }
1101     else if (!strcmp (argv[1], "element"))
1102     {
1103         int min_level = 1;
1104         char *element = 0;
1105         if (argc >= 3 && !strcmp(argv[2], "-record"))
1106         {
1107             min_level = 0;
1108             if (argc == 4)
1109                 element = argv[3];
1110         }
1111         else
1112             if (argc == 3)
1113                 element = argv[2];
1114         tagEnd (spec, min_level, element, (element ? strlen(element) : 0));
1115         if (spec->d1_level == 0)
1116         {
1117 #if REGX_DEBUG
1118             logf (LOG_LOG, "end element end records");
1119 #endif
1120             spec->stop_flag = 1;
1121         }
1122     }
1123     else if (!strcmp (argv[1], "context"))
1124     {
1125 #if REGX_DEBUG
1126         logf (LOG_LOG, "end context");
1127 #endif
1128         if (spec->context_stack_top)
1129             (spec->context_stack_top)--;
1130     }
1131     else
1132         return TCL_ERROR;
1133     return TCL_OK;
1134 }
1135
1136 static int cmd_tcl_data (ClientData clientData, Tcl_Interp *interp,
1137                          int argc, char **argv)
1138 {
1139     int argi = 1;
1140     int textFlag = 0;
1141     const char *element = 0;
1142     struct lexSpec *spec = (struct lexSpec *) clientData;
1143     
1144     while (argi < argc)
1145     {
1146         if (!strcmp("-text", argv[argi]))
1147         {
1148             textFlag = 1;
1149             argi++;
1150         }
1151         else if (!strcmp("-element", argv[argi]))
1152         {
1153             argi++;
1154             if (argi < argc)
1155                 element = argv[argi++];
1156         }
1157         else
1158             break;
1159     }
1160     if (element)
1161         tagBegin (spec, element, strlen(element));
1162
1163     while (argi < argc)
1164     {
1165 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0)
1166         Tcl_DString ds;
1167         char *native = Tcl_UtfToExternalDString(0, argv[argi], -1, &ds);
1168         execData (spec, native, strlen(native), textFlag);
1169         Tcl_DStringFree (&ds);
1170 #else
1171         execData (spec, argv[argi], strlen(argv[argi]), textFlag);
1172 #endif
1173         argi++;
1174     }
1175     if (element)
1176         tagEnd (spec, 1, NULL, 0);
1177     return TCL_OK;
1178 }
1179
1180 static int cmd_tcl_unread (ClientData clientData, Tcl_Interp *interp,
1181                            int argc, char **argv)
1182 {
1183     struct lexSpec *spec = (struct lexSpec *) clientData;
1184     int argi = 1;
1185     int offset = 0;
1186     int no;
1187     
1188     while (argi < argc)
1189     {
1190         if (!strcmp("-offset", argv[argi]))
1191         {
1192             argi++;
1193             if (argi < argc)
1194             {
1195                 offset = atoi(argv[argi]);
1196                 argi++;
1197             }
1198         }
1199         else
1200             break;
1201     }
1202     if (argi != argc-1)
1203         return TCL_ERROR;
1204     no = atoi(argv[argi]);
1205     if (no >= spec->arg_no)
1206         no = spec->arg_no - 1;
1207     spec->ptr = spec->arg_start[no] + offset;
1208     return TCL_OK;
1209 }
1210
1211 static void execTcl (struct lexSpec *spec, struct regxCode *code)
1212 {   
1213     int i;
1214     int ret;
1215     for (i = 0; i < spec->arg_no; i++)
1216     {
1217         char var_name[10], *var_buf;
1218         int var_len, ch;
1219         
1220         sprintf (var_name, "%d", i);
1221         var_buf = f_win_get (spec, spec->arg_start[i], spec->arg_end[i],
1222                              &var_len); 
1223         if (var_buf)
1224         {
1225             ch = var_buf[var_len];
1226             var_buf[var_len] = '\0';
1227             Tcl_SetVar (spec->tcl_interp, var_name, var_buf, 0);
1228             var_buf[var_len] = ch;
1229         }
1230     }
1231 #if HAVE_TCL_OBJECTS
1232     ret = Tcl_GlobalEvalObj(spec->tcl_interp, code->tcl_obj);
1233 #else
1234     ret = Tcl_GlobalEval (spec->tcl_interp, code->str);
1235 #endif
1236     if (ret != TCL_OK)
1237     {
1238         const char *err = Tcl_GetVar(spec->tcl_interp, "errorInfo", 0);
1239         logf(LOG_FATAL, "Tcl error, line=%d, \"%s\"\n%s", 
1240             spec->tcl_interp->errorLine,
1241             spec->tcl_interp->result,
1242             err ? err : "[NO ERRORINFO]");
1243     }
1244 }
1245 /* HAVE_TCL_H */
1246 #endif
1247
1248 static void execCode (struct lexSpec *spec, struct regxCode *code)
1249 {
1250     const char *s = code->str;
1251     int cmd_len, r;
1252     const char *cmd_str;
1253     
1254     r = execTok (spec, &s, &cmd_str, &cmd_len);
1255     while (r)
1256     {
1257         char *p, ptmp[64];
1258         
1259         if (r == 1)
1260         {
1261             r = execTok (spec, &s, &cmd_str, &cmd_len);
1262             continue;
1263         }
1264         p = regxStrz (cmd_str, cmd_len, ptmp);
1265         if (!strcmp (p, "begin"))
1266         {
1267             r = execTok (spec, &s, &cmd_str, &cmd_len);
1268             if (r < 2)
1269             {
1270                 logf (LOG_WARN, "missing keyword after 'begin'");
1271                 continue;
1272             }
1273             p = regxStrz (cmd_str, cmd_len, ptmp);
1274             if (!strcmp (p, "record"))
1275             {
1276                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1277                 if (r < 2)
1278                     continue;
1279                 if (spec->d1_level == 0)
1280                 {
1281                     static char absynName[64];
1282                     data1_absyn *absyn;
1283                     data1_node *res;
1284
1285                     if (cmd_len > 63)
1286                         cmd_len = 63;
1287                     memcpy (absynName, cmd_str, cmd_len);
1288                     absynName[cmd_len] = '\0';
1289
1290 #if REGX_DEBUG
1291                     logf (LOG_LOG, "begin record %s", absynName);
1292 #endif
1293                     absyn = data1_get_absyn (spec->dh, absynName);
1294
1295                     res = data1_mk_node (spec->dh, spec->m, DATA1N_root, 0);
1296                     res->u.root.type = absynName;
1297                     res->u.root.absyn = absyn;
1298                     
1299                     spec->d1_stack[spec->d1_level] = res;
1300                     spec->d1_stack[++(spec->d1_level)] = NULL;
1301                 }
1302                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1303             }
1304             else if (!strcmp (p, "element"))
1305             {
1306                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1307                 if (r < 2)
1308                     continue;
1309                 tagBegin (spec, cmd_str, cmd_len);
1310                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1311             } 
1312             else if (!strcmp (p, "variant"))
1313             {
1314                 int class_len;
1315                 const char *class_str = NULL;
1316                 int type_len;
1317                 const char *type_str = NULL;
1318                 int value_len;
1319                 const char *value_str = NULL;
1320                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1321                 if (r < 2)
1322                     continue;
1323                 class_str = cmd_str;
1324                 class_len = cmd_len;
1325                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1326                 if (r < 2)
1327                     continue;
1328                 type_str = cmd_str;
1329                 type_len = cmd_len;
1330
1331                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1332                 if (r < 2)
1333                     continue;
1334                 value_str = cmd_str;
1335                 value_len = cmd_len;
1336
1337                 variantBegin (spec, class_str, class_len,
1338                               type_str, type_len, value_str, value_len);
1339                 
1340                 
1341                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1342             }
1343             else if (!strcmp (p, "context"))
1344             {
1345                 if (r > 1)
1346                 {
1347                     struct lexContext *lc = spec->context;
1348                     r = execTok (spec, &s, &cmd_str, &cmd_len);
1349                     p = regxStrz (cmd_str, cmd_len, ptmp);
1350 #if REGX_DEBUG
1351                     logf (LOG_LOG, "begin context %s", p);
1352 #endif
1353                     while (lc && strcmp (p, lc->name))
1354                         lc = lc->next;
1355                     if (lc)
1356                         spec->context_stack[++(spec->context_stack_top)] = lc;
1357                     else
1358                         logf (LOG_WARN, "unknown context %s", p);
1359                     
1360                 }
1361                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1362             }
1363             else
1364             {
1365                 logf (LOG_WARN, "bad keyword '%s' after begin", p);
1366             }
1367         }
1368         else if (!strcmp (p, "end"))
1369         {
1370             r = execTok (spec, &s, &cmd_str, &cmd_len);
1371             if (r < 2)
1372             {
1373                 logf (LOG_WARN, "missing keyword after 'end'");
1374                 continue;
1375             }
1376             p = regxStrz (cmd_str, cmd_len, ptmp);
1377             if (!strcmp (p, "record"))
1378             {
1379                 while (spec->d1_level)
1380                 {
1381                     tagDataRelease (spec);
1382                     (spec->d1_level)--;
1383                 }
1384                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1385 #if REGX_DEBUG
1386                 logf (LOG_LOG, "end record");
1387 #endif
1388                 spec->stop_flag = 1;
1389             }
1390             else if (!strcmp (p, "element"))
1391             {
1392                 int min_level = 1;
1393                 while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1394                 {
1395                     if (cmd_len==7 && !memcmp ("-record", cmd_str, cmd_len))
1396                         min_level = 0;
1397                 }
1398                 if (r > 2)
1399                 {
1400                     tagEnd (spec, min_level, cmd_str, cmd_len);
1401                     r = execTok (spec, &s, &cmd_str, &cmd_len);
1402                 }
1403                 else
1404                     tagEnd (spec, min_level, NULL, 0);
1405                 if (spec->d1_level == 0)
1406                 {
1407 #if REGX_DEBUG
1408                     logf (LOG_LOG, "end element end records");
1409 #endif
1410                     spec->stop_flag = 1;
1411                 }
1412
1413             }
1414             else if (!strcmp (p, "context"))
1415             {
1416 #if REGX_DEBUG
1417                 logf (LOG_LOG, "end context");
1418 #endif
1419                 if (spec->context_stack_top)
1420                     (spec->context_stack_top)--;
1421                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1422             }       
1423             else
1424                 logf (LOG_WARN, "bad keyword '%s' after end", p);
1425         }
1426         else if (!strcmp (p, "data"))
1427         {
1428             int textFlag = 0;
1429             int element_len;
1430             const char *element_str = NULL;
1431             
1432             while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1433             {
1434                 if (cmd_len==5 && !memcmp ("-text", cmd_str, cmd_len))
1435                     textFlag = 1;
1436                 else if (cmd_len==8 && !memcmp ("-element", cmd_str, cmd_len))
1437                 {
1438                     r = execTok (spec, &s, &element_str, &element_len);
1439                     if (r < 2)
1440                         break;
1441                 }
1442                 else 
1443                     logf (LOG_WARN, "bad data option: %.*s",
1444                           cmd_len, cmd_str);
1445             }
1446             if (r != 2)
1447             {
1448                 logf (LOG_WARN, "missing data item after data");
1449                 continue;
1450             }
1451             if (element_str)
1452                 tagBegin (spec, element_str, element_len);
1453             do
1454             {
1455                 execData (spec, cmd_str, cmd_len,textFlag);
1456                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1457             } while (r > 1);
1458             if (element_str)
1459                 tagEnd (spec, 1, NULL, 0);
1460         }
1461         else if (!strcmp (p, "unread"))
1462         {
1463             int no, offset;
1464             r = execTok (spec, &s, &cmd_str, &cmd_len);
1465             if (r==3 && cmd_len == 7 && !memcmp ("-offset", cmd_str, cmd_len))
1466             {
1467                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1468                 if (r < 2)
1469                 {
1470                     logf (LOG_WARN, "missing number after -offset");
1471                     continue;
1472                 }
1473                 p = regxStrz (cmd_str, cmd_len, ptmp);
1474                 offset = atoi (p);
1475                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1476             }
1477             else
1478                 offset = 0;
1479             if (r < 2)
1480             {
1481                 logf (LOG_WARN, "missing index after unread command");
1482                 continue;
1483             }
1484             if (cmd_len != 1 || *cmd_str < '0' || *cmd_str > '9')
1485             {
1486                 logf (LOG_WARN, "bad index after unread command");
1487                 continue;
1488             }
1489             else
1490             {
1491                 no = *cmd_str - '0';
1492                 if (no >= spec->arg_no)
1493                     no = spec->arg_no - 1;
1494                 spec->ptr = spec->arg_start[no] + offset;
1495             }
1496             r = execTok (spec, &s, &cmd_str, &cmd_len);
1497         }
1498         else if (!strcmp (p, "context"))
1499         {
1500             if (r > 1)
1501             {
1502                 struct lexContext *lc = spec->context;
1503                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1504                 p = regxStrz (cmd_str, cmd_len, ptmp);
1505                 
1506                 while (lc && strcmp (p, lc->name))
1507                     lc = lc->next;
1508                 if (lc)
1509                     spec->context_stack[spec->context_stack_top] = lc;
1510                 else
1511                     logf (LOG_WARN, "unknown context %s", p);
1512
1513             }
1514             r = execTok (spec, &s, &cmd_str, &cmd_len);
1515         }
1516         else
1517         {
1518             logf (LOG_WARN, "unknown code command '%.*s'", cmd_len, cmd_str);
1519             r = execTok (spec, &s, &cmd_str, &cmd_len);
1520             continue;
1521         }
1522         if (r > 1)
1523         {
1524             logf (LOG_WARN, "ignoring token %.*s", cmd_len, cmd_str);
1525             do {
1526                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1527             } while (r > 1);
1528         }
1529     }
1530 }
1531
1532
1533 static int execAction (struct lexSpec *spec, struct lexRuleAction *ap,
1534                        int start_ptr, int *pptr)
1535 {
1536     int sptr;
1537     int arg_start[20];
1538     int arg_end[20];
1539     int arg_no = 1;
1540
1541     if (!ap)
1542         return 1;
1543     arg_start[0] = start_ptr;
1544     arg_end[0] = *pptr;
1545     spec->arg_start = arg_start;
1546     spec->arg_end = arg_end;
1547
1548     while (ap)
1549     {
1550         switch (ap->which)
1551         {
1552         case REGX_PATTERN:
1553             if (ap->u.pattern.body)
1554             {
1555                 arg_start[arg_no] = *pptr;
1556                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1557                 {
1558                     arg_end[arg_no] = F_WIN_EOF;
1559                     arg_no++;
1560                     arg_start[arg_no] = F_WIN_EOF;
1561                     arg_end[arg_no] = F_WIN_EOF;
1562 /* return 1*/
1563                 }
1564                 else
1565                 {
1566                     arg_end[arg_no] = sptr;
1567                     arg_no++;
1568                     arg_start[arg_no] = sptr;
1569                     arg_end[arg_no] = *pptr;
1570                 }
1571             }
1572             else
1573             {
1574                 arg_start[arg_no] = *pptr;
1575                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1576                     return 1;
1577                 if (sptr != arg_start[arg_no])
1578                     return 1;
1579                 arg_end[arg_no] = *pptr;
1580             }
1581             arg_no++;
1582             break;
1583         case REGX_CODE:
1584             spec->arg_no = arg_no;
1585             spec->ptr = *pptr;
1586 #if HAVE_TCL_H
1587             if (spec->tcl_interp)
1588                 execTcl(spec, ap->u.code);
1589             else
1590                 execCode (spec, ap->u.code);
1591 #else
1592             execCode (spec, ap->u.code);
1593 #endif
1594             *pptr = spec->ptr;
1595             if (spec->stop_flag)
1596                 return 0;
1597             break;
1598         case REGX_END:
1599             arg_start[arg_no] = *pptr;
1600             arg_end[arg_no] = F_WIN_EOF;
1601             arg_no++;
1602             *pptr = F_WIN_EOF;
1603         }
1604         ap = ap->next;
1605     }
1606     return 1;
1607 }
1608
1609 static int execRule (struct lexSpec *spec, struct lexContext *context,
1610                      int ruleNo, int start_ptr, int *pptr)
1611 {
1612 #if REGX_DEBUG
1613     logf (LOG_LOG, "exec rule %d", ruleNo);
1614 #endif
1615     return execAction (spec, context->fastRule[ruleNo]->actionList,
1616                        start_ptr, pptr);
1617 }
1618
1619 data1_node *lexNode (struct lexSpec *spec, int *ptr)
1620 {
1621     struct lexContext *context = spec->context_stack[spec->context_stack_top];
1622     struct DFA_state *state = context->dfa->states[0];
1623     struct DFA_tran *t;
1624     unsigned char c;
1625     unsigned char c_prev = '\n';
1626     int i;
1627     int last_rule = 0;        /* rule number of current match */
1628     int last_ptr = *ptr;      /* last char of match */
1629     int start_ptr = *ptr;     /* first char of match */
1630     int skip_ptr = *ptr;      /* first char of run */
1631
1632     while (1)
1633     {
1634         c = f_win_advance (spec, ptr);
1635         if (*ptr == F_WIN_EOF)
1636         {
1637             /* end of file met */
1638             if (last_rule)
1639             {
1640                 /* there was a match */
1641                 if (skip_ptr < start_ptr)
1642                 {
1643                     /* deal with chars that didn't match */
1644                     int size;
1645                     char *buf;
1646                     buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1647                     execDataP (spec, buf, size, 0);
1648                 }
1649                 /* restore pointer */
1650                 *ptr = last_ptr;
1651                 /* execute rule */
1652                 if (!execRule (spec, context, last_rule, start_ptr, ptr))
1653                     break;
1654                 /* restore skip pointer */
1655                 skip_ptr = *ptr;
1656                 last_rule = 0;
1657             }
1658             else if (skip_ptr < *ptr)
1659             {
1660                 /* deal with chars that didn't match */
1661                 int size;
1662                 char *buf;
1663                 buf = f_win_get (spec, skip_ptr, *ptr, &size);
1664                 execDataP (spec, buf, size, 0);
1665             }
1666             if (*ptr == F_WIN_EOF)
1667                 break;
1668         }
1669         t = state->trans;
1670         i = state->tran_no;
1671         while (1)
1672             if (--i < 0)
1673             {   /* no transition for character c ... */
1674                 if (last_rule)
1675                 {
1676                     if (skip_ptr < start_ptr)
1677                     {
1678                         /* deal with chars that didn't match */
1679                         int size;
1680                         char *buf;
1681                         buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1682                         execDataP (spec, buf, size, 0);
1683                     }
1684                     /* restore pointer */
1685                     *ptr = last_ptr;
1686                     if (!execRule (spec, context, last_rule, start_ptr, ptr))
1687                     {
1688                         if (spec->f_win_ef && *ptr != F_WIN_EOF)
1689                         {
1690 #if REGX_DEBUG
1691                             logf (LOG_LOG, "regx: endf ptr=%d", *ptr);
1692 #endif
1693                             (*spec->f_win_ef)(spec->f_win_fh, *ptr);
1694                         }
1695                         return NULL;
1696                     }
1697                     context = spec->context_stack[spec->context_stack_top];
1698                     skip_ptr = *ptr;
1699                     last_rule = 0;
1700                     last_ptr = start_ptr = *ptr;
1701                     if (start_ptr > 0)
1702                     {
1703                         --start_ptr;
1704                         c_prev = f_win_advance (spec, &start_ptr);
1705                     }
1706                 }
1707                 else
1708                 {
1709                     c_prev = f_win_advance (spec, &start_ptr);
1710                     *ptr = start_ptr;
1711                 }
1712                 state = context->dfa->states[0];
1713                 break;
1714             }
1715             else if (c >= t->ch[0] && c <= t->ch[1])
1716             {   /* transition ... */
1717                 state = context->dfa->states[t->to];
1718                 if (state->rule_no)
1719                 {
1720                     if (c_prev == '\n')
1721                     {
1722                         last_rule = state->rule_no;
1723                         last_ptr = *ptr;
1724                     } 
1725                     else if (state->rule_nno)
1726                     {
1727                         last_rule = state->rule_nno;
1728                         last_ptr = *ptr;
1729                     }
1730                 }
1731                 break;
1732             }
1733             else
1734                 t++;
1735     }
1736     return NULL;
1737 }
1738
1739 static data1_node *lexRoot (struct lexSpec *spec, off_t offset,
1740                             const char *context_name)
1741 {
1742     struct lexContext *lt = spec->context;
1743     int ptr = offset;
1744
1745     spec->stop_flag = 0;
1746     spec->d1_level = 0;
1747     spec->context_stack_top = 0;    
1748     while (lt)
1749     {
1750         if (!strcmp (lt->name, context_name))
1751             break;
1752         lt = lt->next;
1753     }
1754     if (!lt)
1755     {
1756         logf (LOG_WARN, "cannot find context %s", context_name);
1757         return NULL;
1758     }
1759     spec->context_stack[spec->context_stack_top] = lt;
1760     spec->d1_stack[spec->d1_level] = NULL;
1761 #if 1
1762     if (!lt->initFlag)
1763     {
1764         lt->initFlag = 1;
1765         execAction (spec, lt->initActionList, ptr, &ptr);
1766     }
1767 #endif
1768     execAction (spec, lt->beginActionList, ptr, &ptr);
1769     lexNode (spec, &ptr);
1770     while (spec->d1_level)
1771     {
1772         tagDataRelease (spec);
1773         (spec->d1_level)--;
1774     }
1775     execAction (spec, lt->endActionList, ptr, &ptr);
1776     return spec->d1_stack[0];
1777 }
1778
1779 void grs_destroy(void *clientData)
1780 {
1781     struct lexSpecs *specs = (struct lexSpecs *) clientData;
1782     if (specs->spec)
1783     {
1784         lexSpecDestroy(&specs->spec);
1785     }
1786     xfree (specs);
1787 }
1788
1789 void *grs_init(void)
1790 {
1791     struct lexSpecs *specs = (struct lexSpecs *) xmalloc (sizeof(*specs));
1792     specs->spec = 0;
1793     return specs;
1794 }
1795
1796 data1_node *grs_read_regx (struct grs_read_info *p)
1797 {
1798     int res;
1799     struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1800     struct lexSpec **curLexSpec = &specs->spec;
1801
1802 #if REGX_DEBUG
1803     logf (LOG_LOG, "grs_read_regx");
1804 #endif
1805     if (!*curLexSpec || strcmp ((*curLexSpec)->name, p->type))
1806     {
1807         if (*curLexSpec)
1808             lexSpecDestroy (curLexSpec);
1809         *curLexSpec = lexSpecCreate (p->type, p->dh);
1810         res = readFileSpec (*curLexSpec);
1811         if (res)
1812         {
1813             lexSpecDestroy (curLexSpec);
1814             return NULL;
1815         }
1816     }
1817     (*curLexSpec)->dh = p->dh;
1818     if (!p->offset)
1819     {
1820         (*curLexSpec)->f_win_start = 0;
1821         (*curLexSpec)->f_win_end = 0;
1822         (*curLexSpec)->f_win_rf = p->readf;
1823         (*curLexSpec)->f_win_sf = p->seekf;
1824         (*curLexSpec)->f_win_fh = p->fh;
1825         (*curLexSpec)->f_win_ef = p->endf;
1826         (*curLexSpec)->f_win_size = 500000;
1827     }
1828     (*curLexSpec)->m = p->mem;
1829     return lexRoot (*curLexSpec, p->offset, "main");
1830 }
1831
1832 static struct recTypeGrs regx_type = {
1833     "regx",
1834     grs_init,
1835     grs_destroy,
1836     grs_read_regx
1837 };
1838
1839 RecTypeGrs recTypeGrs_regx = &regx_type;
1840
1841 #if HAVE_TCL_H
1842 data1_node *grs_read_tcl (struct grs_read_info *p)
1843 {
1844     int res;
1845     struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1846     struct lexSpec **curLexSpec = &specs->spec;
1847
1848 #if REGX_DEBUG
1849     logf (LOG_LOG, "grs_read_tcl");
1850 #endif
1851     if (!*curLexSpec || strcmp ((*curLexSpec)->name, p->type))
1852     {
1853         Tcl_Interp *tcl_interp;
1854         if (*curLexSpec)
1855             lexSpecDestroy (curLexSpec);
1856         *curLexSpec = lexSpecCreate (p->type, p->dh);
1857         Tcl_FindExecutable("");
1858         tcl_interp = (*curLexSpec)->tcl_interp = Tcl_CreateInterp();
1859         Tcl_Init(tcl_interp);
1860         Tcl_CreateCommand (tcl_interp, "begin", cmd_tcl_begin, *curLexSpec, 0);
1861         Tcl_CreateCommand (tcl_interp, "end", cmd_tcl_end, *curLexSpec, 0);
1862         Tcl_CreateCommand (tcl_interp, "data", cmd_tcl_data, *curLexSpec, 0);
1863         Tcl_CreateCommand (tcl_interp, "unread", cmd_tcl_unread,
1864                            *curLexSpec, 0);
1865         res = readFileSpec (*curLexSpec);
1866         if (res)
1867         {
1868             lexSpecDestroy (curLexSpec);
1869             return NULL;
1870         }
1871     }
1872     (*curLexSpec)->dh = p->dh;
1873     if (!p->offset)
1874     {
1875         (*curLexSpec)->f_win_start = 0;
1876         (*curLexSpec)->f_win_end = 0;
1877         (*curLexSpec)->f_win_rf = p->readf;
1878         (*curLexSpec)->f_win_sf = p->seekf;
1879         (*curLexSpec)->f_win_fh = p->fh;
1880         (*curLexSpec)->f_win_ef = p->endf;
1881         (*curLexSpec)->f_win_size = 500000;
1882     }
1883     (*curLexSpec)->m = p->mem;
1884     return lexRoot (*curLexSpec, p->offset, "main");
1885 }
1886
1887 static struct recTypeGrs tcl_type = {
1888     "tcl",
1889     grs_init,
1890     grs_destroy,
1891     grs_read_tcl
1892 };
1893
1894 RecTypeGrs recTypeGrs_tcl = &tcl_type;
1895 #endif