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