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