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