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