945c7055264b0d9b851fdf888a63c6d5c26dabcc
[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.39 2002-04-15 09:07:10 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);
676         res->parent = parent;
677         res->which = DATA1N_data;
678         res->u.data.what = DATA1I_text;
679         res->u.data.len = 0;
680         res->u.data.formatted_text = formatted_text;
681 #if 0
682         if (elen > DATA1_LOCALDATA)
683             res->u.data.data = nmem_malloc (spec->m, elen);
684         else
685             res->u.data.data = res->lbuf;
686         memcpy (res->u.data.data, ebuf, elen);
687 #else
688         res->u.data.data = 0;
689 #endif
690         res->root = parent->root;
691         
692         parent->last_child = res;
693         if (spec->d1_stack[spec->d1_level])
694             spec->d1_stack[spec->d1_level]->next = res;
695         else
696             parent->child = res;
697         spec->d1_stack[spec->d1_level] = res;
698     }
699     if (org_len + elen >= spec->concatBuf[spec->d1_level].max)
700     {
701         char *old_buf, *new_buf;
702
703         spec->concatBuf[spec->d1_level].max = org_len + elen + 256;
704         new_buf = (char *) xmalloc (spec->concatBuf[spec->d1_level].max);
705         if ((old_buf = spec->concatBuf[spec->d1_level].buf))
706         {
707             memcpy (new_buf, old_buf, org_len);
708             xfree (old_buf);
709         }
710         spec->concatBuf[spec->d1_level].buf = new_buf;
711     }
712     memcpy (spec->concatBuf[spec->d1_level].buf + org_len, ebuf, elen);
713     res->u.data.len += elen;
714 }
715
716 static void execDataP (struct lexSpec *spec,
717                        const char *ebuf, int elen, int formatted_text)
718 {
719     execData (spec, ebuf, elen, formatted_text);
720 }
721
722 static void tagDataRelease (struct lexSpec *spec)
723 {
724     data1_node *res;
725     
726     if ((res = spec->d1_stack[spec->d1_level]) &&
727         res->which == DATA1N_data && 
728         res->u.data.what == DATA1I_text)
729     {
730         assert (!res->u.data.data);
731         assert (res->u.data.len > 0);
732         if (res->u.data.len > DATA1_LOCALDATA)
733             res->u.data.data = (char *) nmem_malloc (spec->m, res->u.data.len);
734         else
735             res->u.data.data = res->lbuf;
736         memcpy (res->u.data.data, spec->concatBuf[spec->d1_level].buf,
737                 res->u.data.len);
738     }
739 }
740
741 static void variantBegin (struct lexSpec *spec, 
742                           const char *class_str, int class_len,
743                           const char *type_str, int type_len,
744                           const char *value_str, int value_len)
745 {
746     struct data1_node *parent = spec->d1_stack[spec->d1_level -1];
747     char tclass[DATA1_MAX_SYMBOL], ttype[DATA1_MAX_SYMBOL];
748     data1_vartype *tp;
749     int i;
750     data1_node *res;
751
752     if (spec->d1_level == 0)
753     {
754         logf (LOG_WARN, "in variant begin. No record type defined");
755         return ;
756     }
757     if (class_len >= DATA1_MAX_SYMBOL)
758         class_len = DATA1_MAX_SYMBOL-1;
759     memcpy (tclass, class_str, class_len);
760     tclass[class_len] = '\0';
761
762     if (type_len >= DATA1_MAX_SYMBOL)
763         type_len = DATA1_MAX_SYMBOL-1;
764     memcpy (ttype, type_str, type_len);
765     ttype[type_len] = '\0';
766
767 #if REGX_DEBUG 
768     logf (LOG_LOG, "variant begin %s %s (%d)", tclass, ttype,
769           spec->d1_level);
770 #endif
771
772     if (!(tp =
773           data1_getvartypebyct(spec->dh, parent->root->u.root.absyn->varset,
774                                tclass, ttype)))
775         return;
776     
777     if (parent->which != DATA1N_variant)
778     {
779         res = data1_mk_node (spec->dh, spec->m);
780         res->parent = parent;
781         res->which = DATA1N_variant;
782         res->u.variant.type = 0;
783         res->u.variant.value = 0;
784         res->root = parent->root;
785
786         parent->last_child = res;
787         if (spec->d1_stack[spec->d1_level])
788         {
789             tagDataRelease (spec);
790             spec->d1_stack[spec->d1_level]->next = res;
791         }
792         else
793             parent->child = res;
794         spec->d1_stack[spec->d1_level] = res;
795         spec->d1_stack[++(spec->d1_level)] = NULL;
796     }
797     for (i = spec->d1_level-1; spec->d1_stack[i]->which == DATA1N_variant; i--)
798         if (spec->d1_stack[i]->u.variant.type == tp)
799         {
800             spec->d1_level = i;
801             break;
802         }
803
804 #if REGX_DEBUG 
805     logf (LOG_LOG, "variant node (%d)", spec->d1_level);
806 #endif
807     parent = spec->d1_stack[spec->d1_level-1];
808     res = data1_mk_node (spec->dh, spec->m);
809     res->parent = parent;
810     res->which = DATA1N_variant;
811     res->root = parent->root;
812     res->u.variant.type = tp;
813
814     if (value_len >= DATA1_LOCALDATA)
815         value_len =DATA1_LOCALDATA-1;
816     memcpy (res->lbuf, value_str, value_len);
817     res->lbuf[value_len] = '\0';
818
819     res->u.variant.value = res->lbuf;
820     
821     parent->last_child = res;
822     if (spec->d1_stack[spec->d1_level])
823     {
824         tagDataRelease (spec);
825         spec->d1_stack[spec->d1_level]->next = res;
826     }
827     else
828         parent->child = res;
829     spec->d1_stack[spec->d1_level] = res;
830     spec->d1_stack[++(spec->d1_level)] = NULL;
831 }
832
833 static void tagStrip (const char **tag, int *len)
834 {
835     int i;
836
837     for (i = *len; i > 0 && isspace((*tag)[i-1]); --i)
838         ;
839     *len = i;
840     for (i = 0; i < *len && isspace((*tag)[i]); i++)
841         ;
842     *tag += i;
843     *len -= i;
844 }
845
846 static void tagBegin (struct lexSpec *spec, 
847                       const char *tag, int len)
848 {
849     struct data1_node *parent;
850     data1_element *elem = NULL;
851     data1_node *partag;
852     data1_node *res;
853     data1_element *e = NULL;
854     int localtag = 0;
855
856     if (spec->d1_level == 0)
857     {
858         logf (LOG_WARN, "in element begin. No record type defined");
859         return ;
860     }
861     tagStrip (&tag, &len);
862
863     parent = spec->d1_stack[spec->d1_level -1];
864     partag = get_parent_tag(spec->dh, parent);
865    
866     res = data1_mk_node_type (spec->dh, spec->m, DATA1N_tag);
867     res->parent = parent;
868
869     if (len >= DATA1_LOCALDATA)
870         res->u.tag.tag = (char *) nmem_malloc (spec->m, len+1);
871     else
872         res->u.tag.tag = res->lbuf;
873
874     memcpy (res->u.tag.tag, tag, len);
875     res->u.tag.tag[len] = '\0';
876    
877 #if REGX_DEBUG 
878     logf (LOG_LOG, "begin tag %s (%d)", res->u.tag.tag, spec->d1_level);
879 #endif
880     if (parent->which == DATA1N_variant)
881         return ;
882     if (partag)
883         if (!(e = partag->u.tag.element))
884             localtag = 1;
885     
886     elem = data1_getelementbytagname (spec->dh,
887                                       spec->d1_stack[0]->u.root.absyn,
888                                       e, res->u.tag.tag);
889     res->u.tag.element = elem;
890     res->root = parent->root;
891
892     parent->last_child = res;
893     if (spec->d1_stack[spec->d1_level])
894     {
895         tagDataRelease (spec);
896         spec->d1_stack[spec->d1_level]->next = res;
897     }
898     else
899         parent->child = res;
900     spec->d1_stack[spec->d1_level] = res;
901     spec->d1_stack[++(spec->d1_level)] = NULL;
902 }
903
904 static void tagEnd (struct lexSpec *spec, int min_level,
905                     const char *tag, int len)
906 {
907     tagStrip (&tag, &len);
908     while (spec->d1_level > min_level)
909     {
910         tagDataRelease (spec);
911         (spec->d1_level)--;
912         if (spec->d1_level == 0)
913             break;
914         if ((spec->d1_stack[spec->d1_level]->which == DATA1N_tag) &&
915             (!tag ||
916              (strlen(spec->d1_stack[spec->d1_level]->u.tag.tag) ==
917               (size_t) len &&
918               !memcmp (spec->d1_stack[spec->d1_level]->u.tag.tag, tag, len))))
919             break;
920     }
921 #if REGX_DEBUG
922     logf (LOG_LOG, "end tag (%d)", spec->d1_level);
923 #endif
924 }
925
926
927 static int tryMatch (struct lexSpec *spec, int *pptr, int *mptr,
928                      struct DFA *dfa)
929 {
930     struct DFA_state *state = dfa->states[0];
931     struct DFA_tran *t;
932     unsigned char c;
933     unsigned char c_prev = 0;
934     int ptr = *pptr;          /* current pointer */
935     int start_ptr = *pptr;    /* first char of match */
936     int last_ptr = 0;         /* last char of match */
937     int last_rule = 0;        /* rule number of current match */
938     int i;
939
940     while (1)
941     {
942         c = f_win_advance (spec, &ptr);
943         if (ptr == F_WIN_EOF)
944         {
945             if (last_rule)
946             {
947                 *mptr = start_ptr;
948                 *pptr = last_ptr;
949                 return 1;
950             }
951             break;
952         }
953         t = state->trans;
954         i = state->tran_no;
955         while (1)
956             if (--i < 0)
957             {
958                 if (last_rule)
959                 {
960                     *mptr = start_ptr;     /* match starts here */
961                     *pptr = last_ptr;      /* match end here (+1) */
962                     return 1;
963                 }
964                 state = dfa->states[0];
965                 start_ptr = ptr;
966                 c_prev = c;
967                 break;
968             }
969             else if (c >= t->ch[0] && c <= t->ch[1])
970             {
971                 state = dfa->states[t->to];
972                 if (state->rule_no)
973                 {
974                     if (c_prev == '\n')
975                     {
976                         last_rule = state->rule_no;
977                         last_ptr = ptr;
978                     }
979                     else
980                     {
981                         last_rule = state->rule_nno;
982                         last_ptr = ptr;
983                     }
984                 }
985                 break;
986             }
987             else
988                 t++;
989     }
990     return 0;
991 }
992
993 static int execTok (struct lexSpec *spec, const char **src,
994                     const char **tokBuf, int *tokLen)
995 {
996     const char *s = *src;
997
998     while (*s == ' ' || *s == '\t')
999         s++;
1000     if (!*s)
1001         return 0;
1002     if (*s == '$' && s[1] >= '0' && s[1] <= '9')
1003     {
1004         int n = 0;
1005         s++;
1006         while (*s >= '0' && *s <= '9')
1007             n = n*10 + (*s++ -'0');
1008         if (spec->arg_no == 0)
1009         {
1010             *tokBuf = "";
1011             *tokLen = 0;
1012         }
1013         else
1014         {
1015             if (n >= spec->arg_no)
1016                 n = spec->arg_no-1;
1017             *tokBuf = f_win_get (spec, spec->arg_start[n], spec->arg_end[n],
1018                                  tokLen);
1019         }
1020     }
1021     else if (*s == '\"')
1022     {
1023         *tokBuf = ++s;
1024         while (*s && *s != '\"')
1025             s++;
1026         *tokLen = s - *tokBuf;
1027         if (*s)
1028             s++;
1029         *src = s;
1030     }
1031     else if (*s == '\n' || *s == ';')
1032     {
1033         *src = s+1;
1034         return 1;
1035     }
1036     else if (*s == '-')
1037     {
1038         *tokBuf = s++;
1039         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' &&
1040                *s != ';')
1041             s++;
1042         *tokLen = s - *tokBuf;
1043         *src = s;
1044         return 3;
1045     }
1046     else
1047     {
1048         *tokBuf = s++;
1049         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' &&
1050                *s != ';')
1051             s++;
1052         *tokLen = s - *tokBuf;
1053     }
1054     *src = s;
1055     return 2;
1056 }
1057
1058 static char *regxStrz (const char *src, int len, char *str)
1059 {
1060     if (len > 63)
1061         len = 63;
1062     memcpy (str, src, len);
1063     str[len] = '\0';
1064     return str;
1065 }
1066
1067 #if HAVE_TCL_H
1068 static int cmd_tcl_begin (ClientData clientData, Tcl_Interp *interp,
1069                           int argc, char **argv)
1070 {
1071     struct lexSpec *spec = (struct lexSpec *) clientData;
1072     if (argc < 2)
1073         return TCL_ERROR;
1074     if (!strcmp(argv[1], "record") && argc == 3)
1075     {
1076         char *absynName = argv[2];
1077         data1_absyn *absyn;
1078         data1_node *res;
1079
1080 #if REGX_DEBUG
1081         logf (LOG_LOG, "begin record %s", absynName);
1082 #endif
1083         absyn = data1_get_absyn (spec->dh, absynName);
1084         
1085         res = data1_mk_node (spec->dh, spec->m);
1086         res->which = DATA1N_root;
1087         res->u.root.type =
1088             data1_insert_string(spec->dh, res, spec->m, absynName);
1089         res->u.root.absyn = absyn;
1090         res->root = res;
1091         
1092         spec->d1_stack[spec->d1_level] = res;
1093         spec->d1_stack[++(spec->d1_level)] = NULL;
1094     }
1095     else if (!strcmp(argv[1], "element") && argc == 3)
1096     {
1097         tagBegin (spec, argv[2], strlen(argv[2]));
1098     }
1099     else if (!strcmp (argv[1], "variant") && argc == 5)
1100     {
1101         variantBegin (spec, argv[2], strlen(argv[2]),
1102                       argv[3], strlen(argv[3]),
1103                       argv[4], strlen(argv[4]));
1104     }
1105     else if (!strcmp (argv[1], "context") && argc == 3)
1106     {
1107         struct lexContext *lc = spec->context;
1108 #if REGX_DEBUG
1109         logf (LOG_LOG, "begin context %s",argv[2]);
1110 #endif
1111         while (lc && strcmp (argv[2], lc->name))
1112             lc = lc->next;
1113         if (lc)
1114         {
1115             spec->context_stack[++(spec->context_stack_top)] = lc;
1116         }
1117         else
1118             logf (LOG_WARN, "unknown context %s", argv[2]);
1119     }
1120     else
1121         return TCL_ERROR;
1122     return TCL_OK;
1123 }
1124
1125 static int cmd_tcl_end (ClientData clientData, Tcl_Interp *interp,
1126                         int argc, char **argv)
1127 {
1128     struct lexSpec *spec = (struct lexSpec *) clientData;
1129     if (argc < 2)
1130         return TCL_ERROR;
1131     
1132     if (!strcmp (argv[1], "record"))
1133     {
1134         while (spec->d1_level)
1135         {
1136             tagDataRelease (spec);
1137             (spec->d1_level)--;
1138         }
1139 #if REGX_DEBUG
1140         logf (LOG_LOG, "end record");
1141 #endif
1142         spec->stop_flag = 1;
1143     }
1144     else if (!strcmp (argv[1], "element"))
1145     {
1146         int min_level = 1;
1147         char *element = 0;
1148         if (argc >= 3 && !strcmp(argv[2], "-record"))
1149         {
1150             min_level = 0;
1151             if (argc == 4)
1152                 element = argv[3];
1153         }
1154         else
1155             if (argc == 3)
1156                 element = argv[2];
1157         tagEnd (spec, min_level, element, (element ? strlen(element) : 0));
1158         if (spec->d1_level == 0)
1159         {
1160 #if REGX_DEBUG
1161             logf (LOG_LOG, "end element end records");
1162 #endif
1163             spec->stop_flag = 1;
1164         }
1165     }
1166     else if (!strcmp (argv[1], "context"))
1167     {
1168 #if REGX_DEBUG
1169         logf (LOG_LOG, "end context");
1170 #endif
1171         if (spec->context_stack_top)
1172             (spec->context_stack_top)--;
1173     }
1174     else
1175         return TCL_ERROR;
1176     return TCL_OK;
1177 }
1178
1179 static int cmd_tcl_data (ClientData clientData, Tcl_Interp *interp,
1180                          int argc, char **argv)
1181 {
1182     int argi = 1;
1183     int textFlag = 0;
1184     const char *element = 0;
1185     struct lexSpec *spec = (struct lexSpec *) clientData;
1186     
1187     while (argi < argc)
1188     {
1189         if (!strcmp("-text", argv[argi]))
1190         {
1191             textFlag = 1;
1192             argi++;
1193         }
1194         else if (!strcmp("-element", argv[argi]))
1195         {
1196             argi++;
1197             if (argi < argc)
1198                 element = argv[argi++];
1199         }
1200         else
1201             break;
1202     }
1203     if (element)
1204         tagBegin (spec, element, strlen(element));
1205
1206     while (argi < argc)
1207     {
1208 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0)
1209         Tcl_DString ds;
1210         char *native = Tcl_UtfToExternalDString(0, argv[argi], -1, &ds);
1211         execData (spec, native, strlen(native), textFlag);
1212         Tcl_DStringFree (&ds);
1213 #else
1214         execData (spec, argv[argi], strlen(argv[argi]), textFlag);
1215 #endif
1216         argi++;
1217     }
1218     if (element)
1219         tagEnd (spec, 1, NULL, 0);
1220     return TCL_OK;
1221 }
1222
1223 static int cmd_tcl_unread (ClientData clientData, Tcl_Interp *interp,
1224                            int argc, char **argv)
1225 {
1226     struct lexSpec *spec = (struct lexSpec *) clientData;
1227     int argi = 1;
1228     int offset = 0;
1229     int no;
1230     
1231     while (argi < argc)
1232     {
1233         if (!strcmp("-offset", argv[argi]))
1234         {
1235             argi++;
1236             if (argi < argc)
1237             {
1238                 offset = atoi(argv[argi]);
1239                 argi++;
1240             }
1241         }
1242         else
1243             break;
1244     }
1245     if (argi != argc-1)
1246         return TCL_ERROR;
1247     no = atoi(argv[argi]);
1248     if (no >= spec->arg_no)
1249         no = spec->arg_no - 1;
1250     spec->ptr = spec->arg_start[no] + offset;
1251     return TCL_OK;
1252 }
1253
1254 static void execTcl (struct lexSpec *spec, struct regxCode *code)
1255 {   
1256     int i;
1257     int ret;
1258     for (i = 0; i < spec->arg_no; i++)
1259     {
1260         char var_name[10], *var_buf;
1261         int var_len, ch;
1262         
1263         sprintf (var_name, "%d", i);
1264         var_buf = f_win_get (spec, spec->arg_start[i], spec->arg_end[i],
1265                              &var_len); 
1266         if (var_buf)
1267         {
1268             ch = var_buf[var_len];
1269             var_buf[var_len] = '\0';
1270             Tcl_SetVar (spec->tcl_interp, var_name, var_buf, 0);
1271             var_buf[var_len] = ch;
1272         }
1273     }
1274 #if HAVE_TCL_OBJECTS
1275     ret = Tcl_GlobalEvalObj(spec->tcl_interp, code->tcl_obj);
1276 #else
1277     ret = Tcl_GlobalEval (spec->tcl_interp, code->str);
1278 #endif
1279     if (ret != TCL_OK)
1280     {
1281         const char *err = Tcl_GetVar(spec->tcl_interp, "errorInfo", 0);
1282         logf(LOG_FATAL, "Tcl error, line=%d, \"%s\"\n%s", 
1283             spec->tcl_interp->errorLine,
1284             spec->tcl_interp->result,
1285             err ? err : "[NO ERRORINFO]");
1286     }
1287 }
1288 /* HAVE_TCL_H */
1289 #endif
1290
1291 static void execCode (struct lexSpec *spec, struct regxCode *code)
1292 {
1293     const char *s = code->str;
1294     int cmd_len, r;
1295     const char *cmd_str;
1296     
1297     r = execTok (spec, &s, &cmd_str, &cmd_len);
1298     while (r)
1299     {
1300         char *p, ptmp[64];
1301         
1302         if (r == 1)
1303         {
1304             r = execTok (spec, &s, &cmd_str, &cmd_len);
1305             continue;
1306         }
1307         p = regxStrz (cmd_str, cmd_len, ptmp);
1308         if (!strcmp (p, "begin"))
1309         {
1310             r = execTok (spec, &s, &cmd_str, &cmd_len);
1311             if (r < 2)
1312             {
1313                 logf (LOG_WARN, "missing keyword after 'begin'");
1314                 continue;
1315             }
1316             p = regxStrz (cmd_str, cmd_len, ptmp);
1317             if (!strcmp (p, "record"))
1318             {
1319                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1320                 if (r < 2)
1321                     continue;
1322                 if (spec->d1_level == 0)
1323                 {
1324                     static char absynName[64];
1325                     data1_absyn *absyn;
1326                     data1_node *res;
1327
1328                     if (cmd_len > 63)
1329                         cmd_len = 63;
1330                     memcpy (absynName, cmd_str, cmd_len);
1331                     absynName[cmd_len] = '\0';
1332
1333 #if REGX_DEBUG
1334                     logf (LOG_LOG, "begin record %s", absynName);
1335 #endif
1336                     absyn = data1_get_absyn (spec->dh, absynName);
1337
1338                     res = data1_mk_node (spec->dh, spec->m);
1339                     res->which = DATA1N_root;
1340                     res->u.root.type = absynName;
1341                     res->u.root.absyn = absyn;
1342                     res->root = res;
1343                     
1344                     spec->d1_stack[spec->d1_level] = res;
1345                     spec->d1_stack[++(spec->d1_level)] = NULL;
1346                 }
1347                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1348             }
1349             else if (!strcmp (p, "element"))
1350             {
1351                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1352                 if (r < 2)
1353                     continue;
1354                 tagBegin (spec, cmd_str, cmd_len);
1355                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1356             } 
1357             else if (!strcmp (p, "variant"))
1358             {
1359                 int class_len;
1360                 const char *class_str = NULL;
1361                 int type_len;
1362                 const char *type_str = NULL;
1363                 int value_len;
1364                 const char *value_str = NULL;
1365                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1366                 if (r < 2)
1367                     continue;
1368                 class_str = cmd_str;
1369                 class_len = cmd_len;
1370                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1371                 if (r < 2)
1372                     continue;
1373                 type_str = cmd_str;
1374                 type_len = cmd_len;
1375
1376                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1377                 if (r < 2)
1378                     continue;
1379                 value_str = cmd_str;
1380                 value_len = cmd_len;
1381
1382                 variantBegin (spec, class_str, class_len,
1383                               type_str, type_len, value_str, value_len);
1384                 
1385                 
1386                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1387             }
1388             else if (!strcmp (p, "context"))
1389             {
1390                 if (r > 1)
1391                 {
1392                     struct lexContext *lc = spec->context;
1393                     r = execTok (spec, &s, &cmd_str, &cmd_len);
1394                     p = regxStrz (cmd_str, cmd_len, ptmp);
1395 #if REGX_DEBUG
1396                     logf (LOG_LOG, "begin context %s", p);
1397 #endif
1398                     while (lc && strcmp (p, lc->name))
1399                         lc = lc->next;
1400                     if (lc)
1401                         spec->context_stack[++(spec->context_stack_top)] = lc;
1402                     else
1403                         logf (LOG_WARN, "unknown context %s", p);
1404                     
1405                 }
1406                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1407             }
1408             else
1409             {
1410                 logf (LOG_WARN, "bad keyword '%s' after begin", p);
1411             }
1412         }
1413         else if (!strcmp (p, "end"))
1414         {
1415             r = execTok (spec, &s, &cmd_str, &cmd_len);
1416             if (r < 2)
1417             {
1418                 logf (LOG_WARN, "missing keyword after 'end'");
1419                 continue;
1420             }
1421             p = regxStrz (cmd_str, cmd_len, ptmp);
1422             if (!strcmp (p, "record"))
1423             {
1424                 while (spec->d1_level)
1425                 {
1426                     tagDataRelease (spec);
1427                     (spec->d1_level)--;
1428                 }
1429                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1430 #if REGX_DEBUG
1431                 logf (LOG_LOG, "end record");
1432 #endif
1433                 spec->stop_flag = 1;
1434             }
1435             else if (!strcmp (p, "element"))
1436             {
1437                 int min_level = 1;
1438                 while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1439                 {
1440                     if (cmd_len==7 && !memcmp ("-record", cmd_str, cmd_len))
1441                         min_level = 0;
1442                 }
1443                 if (r > 2)
1444                 {
1445                     tagEnd (spec, min_level, cmd_str, cmd_len);
1446                     r = execTok (spec, &s, &cmd_str, &cmd_len);
1447                 }
1448                 else
1449                     tagEnd (spec, min_level, NULL, 0);
1450                 if (spec->d1_level == 0)
1451                 {
1452 #if REGX_DEBUG
1453                     logf (LOG_LOG, "end element end records");
1454 #endif
1455                     spec->stop_flag = 1;
1456                 }
1457
1458             }
1459             else if (!strcmp (p, "context"))
1460             {
1461 #if REGX_DEBUG
1462                 logf (LOG_LOG, "end context");
1463 #endif
1464                 if (spec->context_stack_top)
1465                     (spec->context_stack_top)--;
1466                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1467             }       
1468             else
1469                 logf (LOG_WARN, "bad keyword '%s' after end", p);
1470         }
1471         else if (!strcmp (p, "data"))
1472         {
1473             int textFlag = 0;
1474             int element_len;
1475             const char *element_str = NULL;
1476             
1477             while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1478             {
1479                 if (cmd_len==5 && !memcmp ("-text", cmd_str, cmd_len))
1480                     textFlag = 1;
1481                 else if (cmd_len==8 && !memcmp ("-element", cmd_str, cmd_len))
1482                 {
1483                     r = execTok (spec, &s, &element_str, &element_len);
1484                     if (r < 2)
1485                         break;
1486                 }
1487                 else 
1488                     logf (LOG_WARN, "bad data option: %.*s",
1489                           cmd_len, cmd_str);
1490             }
1491             if (r != 2)
1492             {
1493                 logf (LOG_WARN, "missing data item after data");
1494                 continue;
1495             }
1496             if (element_str)
1497                 tagBegin (spec, element_str, element_len);
1498             do
1499             {
1500                 execData (spec, cmd_str, cmd_len,textFlag);
1501                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1502             } while (r > 1);
1503             if (element_str)
1504                 tagEnd (spec, 1, NULL, 0);
1505         }
1506         else if (!strcmp (p, "unread"))
1507         {
1508             int no, offset;
1509             r = execTok (spec, &s, &cmd_str, &cmd_len);
1510             if (r==3 && cmd_len == 7 && !memcmp ("-offset", cmd_str, cmd_len))
1511             {
1512                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1513                 if (r < 2)
1514                 {
1515                     logf (LOG_WARN, "missing number after -offset");
1516                     continue;
1517                 }
1518                 p = regxStrz (cmd_str, cmd_len, ptmp);
1519                 offset = atoi (p);
1520                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1521             }
1522             else
1523                 offset = 0;
1524             if (r < 2)
1525             {
1526                 logf (LOG_WARN, "missing index after unread command");
1527                 continue;
1528             }
1529             if (cmd_len != 1 || *cmd_str < '0' || *cmd_str > '9')
1530             {
1531                 logf (LOG_WARN, "bad index after unread command");
1532                 continue;
1533             }
1534             else
1535             {
1536                 no = *cmd_str - '0';
1537                 if (no >= spec->arg_no)
1538                     no = spec->arg_no - 1;
1539                 spec->ptr = spec->arg_start[no] + offset;
1540             }
1541             r = execTok (spec, &s, &cmd_str, &cmd_len);
1542         }
1543         else if (!strcmp (p, "context"))
1544         {
1545             if (r > 1)
1546             {
1547                 struct lexContext *lc = spec->context;
1548                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1549                 p = regxStrz (cmd_str, cmd_len, ptmp);
1550                 
1551                 while (lc && strcmp (p, lc->name))
1552                     lc = lc->next;
1553                 if (lc)
1554                     spec->context_stack[spec->context_stack_top] = lc;
1555                 else
1556                     logf (LOG_WARN, "unknown context %s", p);
1557
1558             }
1559             r = execTok (spec, &s, &cmd_str, &cmd_len);
1560         }
1561         else
1562         {
1563             logf (LOG_WARN, "unknown code command '%.*s'", cmd_len, cmd_str);
1564             r = execTok (spec, &s, &cmd_str, &cmd_len);
1565             continue;
1566         }
1567         if (r > 1)
1568         {
1569             logf (LOG_WARN, "ignoring token %.*s", cmd_len, cmd_str);
1570             do {
1571                 r = execTok (spec, &s, &cmd_str, &cmd_len);
1572             } while (r > 1);
1573         }
1574     }
1575 }
1576
1577
1578 static int execAction (struct lexSpec *spec, struct lexRuleAction *ap,
1579                        int start_ptr, int *pptr)
1580 {
1581     int sptr;
1582     int arg_start[20];
1583     int arg_end[20];
1584     int arg_no = 1;
1585
1586     if (!ap)
1587         return 1;
1588     arg_start[0] = start_ptr;
1589     arg_end[0] = *pptr;
1590     spec->arg_start = arg_start;
1591     spec->arg_end = arg_end;
1592
1593     while (ap)
1594     {
1595         switch (ap->which)
1596         {
1597         case REGX_PATTERN:
1598             if (ap->u.pattern.body)
1599             {
1600                 arg_start[arg_no] = *pptr;
1601                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1602                 {
1603                     arg_end[arg_no] = F_WIN_EOF;
1604                     arg_no++;
1605                     arg_start[arg_no] = F_WIN_EOF;
1606                     arg_end[arg_no] = F_WIN_EOF;
1607 /* return 1*/
1608                 }
1609                 else
1610                 {
1611                     arg_end[arg_no] = sptr;
1612                     arg_no++;
1613                     arg_start[arg_no] = sptr;
1614                     arg_end[arg_no] = *pptr;
1615                 }
1616             }
1617             else
1618             {
1619                 arg_start[arg_no] = *pptr;
1620                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1621                     return 1;
1622                 if (sptr != arg_start[arg_no])
1623                     return 1;
1624                 arg_end[arg_no] = *pptr;
1625             }
1626             arg_no++;
1627             break;
1628         case REGX_CODE:
1629             spec->arg_no = arg_no;
1630             spec->ptr = *pptr;
1631 #if HAVE_TCL_H
1632             if (spec->tcl_interp)
1633                 execTcl(spec, ap->u.code);
1634             else
1635                 execCode (spec, ap->u.code);
1636 #else
1637             execCode (spec, ap->u.code);
1638 #endif
1639             *pptr = spec->ptr;
1640             if (spec->stop_flag)
1641                 return 0;
1642             break;
1643         case REGX_END:
1644             arg_start[arg_no] = *pptr;
1645             arg_end[arg_no] = F_WIN_EOF;
1646             arg_no++;
1647             *pptr = F_WIN_EOF;
1648         }
1649         ap = ap->next;
1650     }
1651     return 1;
1652 }
1653
1654 static int execRule (struct lexSpec *spec, struct lexContext *context,
1655                      int ruleNo, int start_ptr, int *pptr)
1656 {
1657 #if REGX_DEBUG
1658     logf (LOG_LOG, "exec rule %d", ruleNo);
1659 #endif
1660     return execAction (spec, context->fastRule[ruleNo]->actionList,
1661                        start_ptr, pptr);
1662 }
1663
1664 data1_node *lexNode (struct lexSpec *spec, int *ptr)
1665 {
1666     struct lexContext *context = spec->context_stack[spec->context_stack_top];
1667     struct DFA_state *state = context->dfa->states[0];
1668     struct DFA_tran *t;
1669     unsigned char c;
1670     unsigned char c_prev = '\n';
1671     int i;
1672     int last_rule = 0;        /* rule number of current match */
1673     int last_ptr = *ptr;      /* last char of match */
1674     int start_ptr = *ptr;     /* first char of match */
1675     int skip_ptr = *ptr;      /* first char of run */
1676
1677     while (1)
1678     {
1679         c = f_win_advance (spec, ptr);
1680         if (*ptr == F_WIN_EOF)
1681         {
1682             /* end of file met */
1683             if (last_rule)
1684             {
1685                 /* there was a match */
1686                 if (skip_ptr < start_ptr)
1687                 {
1688                     /* deal with chars that didn't match */
1689                     int size;
1690                     char *buf;
1691                     buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1692                     execDataP (spec, buf, size, 0);
1693                 }
1694                 /* restore pointer */
1695                 *ptr = last_ptr;
1696                 /* execute rule */
1697                 if (!execRule (spec, context, last_rule, start_ptr, ptr))
1698                     break;
1699                 /* restore skip pointer */
1700                 skip_ptr = *ptr;
1701                 last_rule = 0;
1702             }
1703             else if (skip_ptr < *ptr)
1704             {
1705                 /* deal with chars that didn't match */
1706                 int size;
1707                 char *buf;
1708                 buf = f_win_get (spec, skip_ptr, *ptr, &size);
1709                 execDataP (spec, buf, size, 0);
1710             }
1711             if (*ptr == F_WIN_EOF)
1712                 break;
1713         }
1714         t = state->trans;
1715         i = state->tran_no;
1716         while (1)
1717             if (--i < 0)
1718             {   /* no transition for character c ... */
1719                 if (last_rule)
1720                 {
1721                     if (skip_ptr < start_ptr)
1722                     {
1723                         /* deal with chars that didn't match */
1724                         int size;
1725                         char *buf;
1726                         buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1727                         execDataP (spec, buf, size, 0);
1728                     }
1729                     /* restore pointer */
1730                     *ptr = last_ptr;
1731                     if (!execRule (spec, context, last_rule, start_ptr, ptr))
1732                     {
1733                         if (spec->f_win_ef && *ptr != F_WIN_EOF)
1734                         {
1735 #if REGX_DEBUG
1736                             logf (LOG_LOG, "regx: endf ptr=%d", *ptr);
1737 #endif
1738                             (*spec->f_win_ef)(spec->f_win_fh, *ptr);
1739                         }
1740                         return NULL;
1741                     }
1742                     context = spec->context_stack[spec->context_stack_top];
1743                     skip_ptr = *ptr;
1744                     last_rule = 0;
1745                     last_ptr = start_ptr = *ptr;
1746                     if (start_ptr > 0)
1747                     {
1748                         --start_ptr;
1749                         c_prev = f_win_advance (spec, &start_ptr);
1750                     }
1751                 }
1752                 else
1753                 {
1754                     c_prev = f_win_advance (spec, &start_ptr);
1755                     *ptr = start_ptr;
1756                 }
1757                 state = context->dfa->states[0];
1758                 break;
1759             }
1760             else if (c >= t->ch[0] && c <= t->ch[1])
1761             {   /* transition ... */
1762                 state = context->dfa->states[t->to];
1763                 if (state->rule_no)
1764                 {
1765                     if (c_prev == '\n')
1766                     {
1767                         last_rule = state->rule_no;
1768                         last_ptr = *ptr;
1769                     } 
1770                     else if (state->rule_nno)
1771                     {
1772                         last_rule = state->rule_nno;
1773                         last_ptr = *ptr;
1774                     }
1775                 }
1776                 break;
1777             }
1778             else
1779                 t++;
1780     }
1781     return NULL;
1782 }
1783
1784 static data1_node *lexRoot (struct lexSpec *spec, off_t offset,
1785                             const char *context_name)
1786 {
1787     struct lexContext *lt = spec->context;
1788     int ptr = offset;
1789
1790     spec->stop_flag = 0;
1791     spec->d1_level = 0;
1792     spec->context_stack_top = 0;    
1793     while (lt)
1794     {
1795         if (!strcmp (lt->name, context_name))
1796             break;
1797         lt = lt->next;
1798     }
1799     if (!lt)
1800     {
1801         logf (LOG_WARN, "cannot find context %s", context_name);
1802         return NULL;
1803     }
1804     spec->context_stack[spec->context_stack_top] = lt;
1805     spec->d1_stack[spec->d1_level] = NULL;
1806 #if 1
1807     if (!lt->initFlag)
1808     {
1809         lt->initFlag = 1;
1810         execAction (spec, lt->initActionList, ptr, &ptr);
1811     }
1812 #endif
1813     execAction (spec, lt->beginActionList, ptr, &ptr);
1814     lexNode (spec, &ptr);
1815     while (spec->d1_level)
1816     {
1817         tagDataRelease (spec);
1818         (spec->d1_level)--;
1819     }
1820     execAction (spec, lt->endActionList, ptr, &ptr);
1821     return spec->d1_stack[0];
1822 }
1823
1824 void grs_destroy(void *clientData)
1825 {
1826     struct lexSpecs *specs = (struct lexSpecs *) clientData;
1827     if (specs->spec)
1828     {
1829         lexSpecDestroy(&specs->spec);
1830     }
1831     xfree (specs);
1832 }
1833
1834 void *grs_init(void)
1835 {
1836     struct lexSpecs *specs = (struct lexSpecs *) xmalloc (sizeof(*specs));
1837     specs->spec = 0;
1838     return specs;
1839 }
1840
1841 data1_node *grs_read_regx (struct grs_read_info *p)
1842 {
1843     int res;
1844     struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1845     struct lexSpec **curLexSpec = &specs->spec;
1846
1847 #if REGX_DEBUG
1848     logf (LOG_LOG, "grs_read_regx");
1849 #endif
1850     if (!*curLexSpec || strcmp ((*curLexSpec)->name, p->type))
1851     {
1852         if (*curLexSpec)
1853             lexSpecDestroy (curLexSpec);
1854         *curLexSpec = lexSpecCreate (p->type, p->dh);
1855         res = readFileSpec (*curLexSpec);
1856         if (res)
1857         {
1858             lexSpecDestroy (curLexSpec);
1859             return NULL;
1860         }
1861     }
1862     (*curLexSpec)->dh = p->dh;
1863     if (!p->offset)
1864     {
1865         (*curLexSpec)->f_win_start = 0;
1866         (*curLexSpec)->f_win_end = 0;
1867         (*curLexSpec)->f_win_rf = p->readf;
1868         (*curLexSpec)->f_win_sf = p->seekf;
1869         (*curLexSpec)->f_win_fh = p->fh;
1870         (*curLexSpec)->f_win_ef = p->endf;
1871         (*curLexSpec)->f_win_size = 500000;
1872     }
1873     (*curLexSpec)->m = p->mem;
1874     return lexRoot (*curLexSpec, p->offset, "main");
1875 }
1876
1877 static struct recTypeGrs regx_type = {
1878     "regx",
1879     grs_init,
1880     grs_destroy,
1881     grs_read_regx
1882 };
1883
1884 RecTypeGrs recTypeGrs_regx = &regx_type;
1885
1886 #if HAVE_TCL_H
1887 data1_node *grs_read_tcl (struct grs_read_info *p)
1888 {
1889     int res;
1890     struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1891     struct lexSpec **curLexSpec = &specs->spec;
1892
1893 #if REGX_DEBUG
1894     logf (LOG_LOG, "grs_read_tcl");
1895 #endif
1896     if (!*curLexSpec || strcmp ((*curLexSpec)->name, p->type))
1897     {
1898         Tcl_Interp *tcl_interp;
1899         if (*curLexSpec)
1900             lexSpecDestroy (curLexSpec);
1901         *curLexSpec = lexSpecCreate (p->type, p->dh);
1902         Tcl_FindExecutable("");
1903         tcl_interp = (*curLexSpec)->tcl_interp = Tcl_CreateInterp();
1904         Tcl_Init(tcl_interp);
1905         Tcl_CreateCommand (tcl_interp, "begin", cmd_tcl_begin, *curLexSpec, 0);
1906         Tcl_CreateCommand (tcl_interp, "end", cmd_tcl_end, *curLexSpec, 0);
1907         Tcl_CreateCommand (tcl_interp, "data", cmd_tcl_data, *curLexSpec, 0);
1908         Tcl_CreateCommand (tcl_interp, "unread", cmd_tcl_unread,
1909                            *curLexSpec, 0);
1910         res = readFileSpec (*curLexSpec);
1911         if (res)
1912         {
1913             lexSpecDestroy (curLexSpec);
1914             return NULL;
1915         }
1916     }
1917     (*curLexSpec)->dh = p->dh;
1918     if (!p->offset)
1919     {
1920         (*curLexSpec)->f_win_start = 0;
1921         (*curLexSpec)->f_win_end = 0;
1922         (*curLexSpec)->f_win_rf = p->readf;
1923         (*curLexSpec)->f_win_sf = p->seekf;
1924         (*curLexSpec)->f_win_fh = p->fh;
1925         (*curLexSpec)->f_win_ef = p->endf;
1926         (*curLexSpec)->f_win_size = 500000;
1927     }
1928     (*curLexSpec)->m = p->mem;
1929     return lexRoot (*curLexSpec, p->offset, "main");
1930 }
1931
1932 static struct recTypeGrs tcl_type = {
1933     "tcl",
1934     grs_init,
1935     grs_destroy,
1936     grs_read_tcl
1937 };
1938
1939 RecTypeGrs recTypeGrs_tcl = &tcl_type;
1940 #endif