Zebra version corresponds to YAZ version 1.4.
[idzebra-moved-to-github.git] / recctrl / regxread.c
1 /*
2  * Copyright (C) 1994-1996, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: regxread.c,v $
7  * Revision 1.8  1997-09-17 12:19:22  adam
8  * Zebra version corresponds to YAZ version 1.4.
9  * Changed Zebra server so that it doesn't depend on global common_resource.
10  *
11  * Revision 1.7  1997/07/15 16:33:07  adam
12  * Check for zero length in execData.
13  *
14  * Revision 1.6  1997/02/24 10:41:51  adam
15  * Cleanup of code and commented out the "end element-end-record" code.
16  *
17  * Revision 1.5  1997/02/19 16:22:33  adam
18  * Fixed "end element" to terminate record in outer-most level.
19  *
20  * Revision 1.4  1997/02/12 20:42:58  adam
21  * Changed some log messages.
22  *
23  * Revision 1.3  1996/11/08 14:05:33  adam
24  * Bug fix: data1 node member u.tag.get_bytes weren't initialized.
25  *
26  * Revision 1.2  1996/10/29  14:02:09  adam
27  * Doesn't use the global data1_tabpath (from YAZ). Instead the function
28  * data1_get_tabpath is used.
29  *
30  * Revision 1.1  1996/10/11 10:57:30  adam
31  * New module recctrl. Used to manage records (extract/retrieval).
32  *
33  * Revision 1.24  1996/06/17 14:25:31  adam
34  * Removed LOG_DEBUG logs; can still be enabled by setting REGX_DEBUG.
35  *
36  * Revision 1.23  1996/06/04 10:19:00  adam
37  * Minor changes - removed include of ctype.h.
38  *
39  * Revision 1.22  1996/06/03  15:23:13  adam
40  * Bug fix: /../ BODY /../ - pattern didn't match EOF.
41  *
42  * Revision 1.21  1996/05/14  16:58:38  adam
43  * Minor change.
44  *
45  * Revision 1.20  1996/05/01  13:46:36  adam
46  * First work on multiple records in one file.
47  * New option, -offset, to the "unread" command in the filter module.
48  *
49  * Revision 1.19  1996/02/12  16:18:20  adam
50  * Yet another bug fix in implementation of unread command.
51  *
52  * Revision 1.18  1996/02/12  16:07:54  adam
53  * Bug fix in new unread command.
54  *
55  * Revision 1.17  1996/02/12  15:56:11  adam
56  * New code command: unread.
57  *
58  * Revision 1.16  1996/01/17  14:57:51  adam
59  * Prototype changed for reader functions in extract/retrieve. File
60  *  is identified by 'void *' instead of 'int.
61  *
62  * Revision 1.15  1996/01/08  19:15:47  adam
63  * New input filter that works!
64  *
65  * Revision 1.14  1996/01/08  09:10:38  adam
66  * Yet another complete rework on this module.
67  *
68  * Revision 1.13  1995/12/15  17:21:50  adam
69  * This version is able to set data.formatted_text in data1-nodes.
70  *
71  * Revision 1.12  1995/12/15  16:20:10  adam
72  * The filter files (*.flt) are read from the path given by data1_tabpath.
73  *
74  * Revision 1.11  1995/12/15  12:35:16  adam
75  * Better logging.
76  *
77  * Revision 1.10  1995/12/15  10:35:36  adam
78  * Misc. bug fixes.
79  *
80  * Revision 1.9  1995/12/14  16:38:48  adam
81  * Completely new attempt to make regular expression parsing.
82  *
83  * Revision 1.8  1995/12/13  17:16:59  adam
84  * Small changes.
85  *
86  * Revision 1.7  1995/12/13  16:51:58  adam
87  * Modified to set last_child in data1_nodes.
88  * Uses destroy handler to free up data text nodes.
89  *
90  * Revision 1.6  1995/12/13  13:45:37  quinn
91  * Changed data1 to use nmem.
92  *
93  * Revision 1.5  1995/12/11  09:12:52  adam
94  * The rec_get function returns NULL if record doesn't exist - will
95  * happen in the server if the result set records have been deleted since
96  * the creation of the set (i.e. the search).
97  * The server saves a result temporarily if it is 'volatile', i.e. the
98  * set is register dependent.
99  *
100  * Revision 1.4  1995/12/05  16:57:40  adam
101  * More work on regular patterns.
102  *
103  * Revision 1.3  1995/12/05  09:37:09  adam
104  * One malloc was renamed to xmalloc.
105  *
106  * Revision 1.2  1995/12/04  17:59:24  adam
107  * More work on regular expression conversion.
108  *
109  * Revision 1.1  1995/12/04  14:25:30  adam
110  * Started work on regular expression parsed input to structured records.
111  *
112  */
113 #include <stdio.h>
114 #include <assert.h>
115 #include <string.h>
116
117 #include <tpath.h>
118 #include <zebrautl.h>
119 #include <dfa.h>
120 #include "grsread.h"
121
122 #define REGX_DEBUG 0
123
124 #define F_WIN_EOF 2000000000
125 #define F_WIN_READ 1
126
127 #define REGX_EOF     0
128 #define REGX_PATTERN 1
129 #define REGX_BODY    2
130 #define REGX_BEGIN   3
131 #define REGX_END     4
132 #define REGX_CODE    5
133
134 struct regxCode {
135     char *str;
136 };
137
138 struct lexRuleAction {
139     int which; 
140     union {
141         struct {
142             struct DFA *dfa;    /* REGX_PATTERN */
143             int body;
144         } pattern;
145         struct regxCode *code;  /* REGX_CODE */
146     } u;
147     struct lexRuleAction *next;
148 };
149
150 struct lexRuleInfo {
151     int no;
152     struct lexRuleAction *actionList;
153 };
154
155 struct lexRule {
156     struct lexRuleInfo info;
157     struct lexRule *next;
158 };
159
160 struct lexTrans {
161     struct DFA *dfa;
162     struct lexRule *rules;
163     struct lexRuleInfo **fastRule;
164     int ruleNo;
165 };
166
167 struct lexSpec {
168     char *name;
169     struct lexTrans trans;
170     int lineNo;
171     NMEM m;
172     data1_handle dh;
173     void *f_win_fh;
174     void (*f_win_ef)(void *, off_t);
175
176     int f_win_start;
177     int f_win_end;
178     int f_win_size;
179     char *f_win_buf;
180     int (*f_win_rf)(void *, char *, size_t);
181     off_t (*f_win_sf)(void *, off_t);
182
183     struct lexRuleAction *beginActionList;
184     struct lexRuleAction *endActionList;
185 };
186
187
188 static char *f_win_get (struct lexSpec *spec, off_t start_pos, off_t end_pos,
189                         int *size)
190 {
191     int i, r, off;
192
193     if (start_pos < spec->f_win_start || start_pos >= spec->f_win_end)
194     {
195         (*spec->f_win_sf)(spec->f_win_fh, start_pos);
196         spec->f_win_start = start_pos;
197
198         if (!spec->f_win_buf)
199             spec->f_win_buf = xmalloc (spec->f_win_size);
200         *size = (*spec->f_win_rf)(spec->f_win_fh, spec->f_win_buf,
201                                   spec->f_win_size);
202         spec->f_win_end = spec->f_win_start + *size;
203
204         if (*size > end_pos - start_pos)
205             *size = end_pos - start_pos;
206         return spec->f_win_buf;
207     }
208     if (end_pos <= spec->f_win_end)
209     {
210         *size = end_pos - start_pos;
211         return spec->f_win_buf + (start_pos - spec->f_win_start);
212     }
213     off = start_pos - spec->f_win_start;
214     for (i = 0; i<spec->f_win_end - start_pos; i++)
215         spec->f_win_buf[i] = spec->f_win_buf[i + off];
216     r = (*spec->f_win_rf)(spec->f_win_fh,
217                           spec->f_win_buf + i,
218                           spec->f_win_size - i);
219     spec->f_win_start = start_pos;
220     spec->f_win_end += r;
221     *size = i + r;
222     if (*size > end_pos - start_pos)
223         *size = end_pos - start_pos;
224     return spec->f_win_buf;
225 }
226
227 static int f_win_advance (struct lexSpec *spec, int *pos)
228 {
229     int size;
230     char *buf;
231     
232     if (*pos >= spec->f_win_start && *pos < spec->f_win_end)
233         return spec->f_win_buf[(*pos)++ - spec->f_win_start];
234     if (*pos == F_WIN_EOF)
235         return 0;
236     buf = f_win_get (spec, *pos, *pos+1, &size);
237     if (size == 1)
238     {
239         (*pos)++;
240         return *buf;
241     }
242     *pos = F_WIN_EOF;
243     return 0;
244 }
245
246 static void regxCodeDel (struct regxCode **pp)
247 {
248     struct regxCode *p = *pp;
249     if (p)
250     {
251         xfree (p->str); 
252         xfree (p);
253         *pp = NULL;
254     }
255 }
256
257 static void regxCodeMk (struct regxCode **pp, const char *buf, int len)
258 {
259     struct regxCode *p;
260
261     p = xmalloc (sizeof(*p));
262     p->str = xmalloc (len+1);
263     memcpy (p->str, buf, len);
264     p->str[len] = '\0';
265     *pp = p;
266 }
267
268 static struct DFA *lexSpecDFA (void)
269 {
270     struct DFA *dfa;
271
272     dfa = dfa_init ();
273     dfa_parse_cmap_del (dfa, ' ');
274     dfa_parse_cmap_del (dfa, '\t');
275     dfa_parse_cmap_add (dfa, '/', 0);
276     return dfa;
277 }
278
279 static struct lexSpec *lexSpecMk (const char *name)
280 {
281     struct lexSpec *p;
282
283     p = xmalloc (sizeof(*p));
284     p->name = xmalloc (strlen(name)+1);
285     strcpy (p->name, name);
286     p->trans.dfa = lexSpecDFA ();
287     p->trans.rules = NULL;
288     p->trans.fastRule = NULL;
289     p->beginActionList = NULL;
290     p->endActionList = NULL;
291     p->f_win_buf = NULL;
292     return p;
293 }
294
295 static void actionListDel (struct lexRuleAction **rap)
296 {
297     struct lexRuleAction *ra1, *ra;
298
299     for (ra = *rap; ra; ra = ra1)
300     {
301         ra1 = ra->next;
302         switch (ra->which)
303         {
304         case REGX_PATTERN:
305             dfa_delete (&ra->u.pattern.dfa);
306             break;
307         case REGX_CODE:
308             regxCodeDel (&ra->u.code);
309             break;
310         }
311         xfree (ra);
312     }
313     *rap = NULL;
314 }
315
316 static void lexSpecDel (struct lexSpec **pp)
317 {
318     struct lexSpec *p;
319     struct lexRule *rp, *rp1;
320
321     assert (pp);
322     p = *pp;
323     if (!p)
324         return ;
325     dfa_delete (&p->trans.dfa);
326     xfree (p->name);
327     xfree (p->trans.fastRule);
328     for (rp = p->trans.rules; rp; rp = rp1)
329     {
330         actionListDel (&rp->info.actionList);
331         xfree (rp);
332     }
333     actionListDel (&p->beginActionList);
334     actionListDel (&p->endActionList);
335     xfree (p->f_win_buf);
336     xfree (p);
337     *pp = NULL;
338 }
339
340 static int readParseToken (const char **cpp, int *len)
341 {
342     const char *cp = *cpp;
343     char cmd[32];
344     int i, level;
345
346     while (*cp == ' ' || *cp == '\t' || *cp == '\n')
347         cp++;
348     switch (*cp)
349     {
350     case '\0':
351         return 0;
352     case '/':
353         *cpp = cp+1;
354         return REGX_PATTERN;
355     case '{':
356         *cpp = cp+1;
357         level = 1;
358         while (*++cp)
359         {
360             if (*cp == '{')
361                 level++;
362             else if (*cp == '}')
363             {
364                 level--;
365                 if (level == 0)
366                     break;
367             }
368         }
369         *len = cp - *cpp;
370         return REGX_CODE;
371     default:
372         i = 0;
373         while (1)
374         {
375             if (*cp >= 'a' && *cp <= 'z')
376                 cmd[i] = *cp;
377             else if (*cp >= 'A' && *cp <= 'Z')
378                 cmd[i] = *cp + 'a' - 'A';
379             else
380                 break;
381             if (i > sizeof(cmd)-2)
382                 break;
383             i++;
384             cp++;
385         }
386         cmd[i] = '\0';
387         if (i == 0)
388         {
389             logf (LOG_WARN, "bad character %d %c", *cp, *cp);
390             cp++;
391             while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
392                 cp++;
393             *cpp = cp;
394             return 0;
395         }
396         *cpp = cp;
397         if (!strcmp (cmd, "begin"))
398             return REGX_BEGIN;
399         else if (!strcmp (cmd, "end"))
400             return REGX_END;
401         else if (!strcmp (cmd, "body"))
402             return REGX_BODY;
403         else
404         {
405             logf (LOG_WARN, "bad command %s", cmd);
406             return 0;
407         }
408     }
409 }
410
411 static int actionListMk (struct lexSpec *spec, const char *s,
412                          struct lexRuleAction **ap)
413 {
414     int r, tok, len;
415     int bodyMark = 0;
416
417     while ((tok = readParseToken (&s, &len)))
418     {
419         switch (tok)
420         {
421         case REGX_BODY:
422             bodyMark = 1;
423             continue;
424         case REGX_CODE:
425             *ap = xmalloc (sizeof(**ap));
426             (*ap)->which = tok;
427             regxCodeMk (&(*ap)->u.code, s, len);
428             s += len+1;
429             break;
430         case REGX_PATTERN:
431             *ap = xmalloc (sizeof(**ap));
432             (*ap)->which = tok;
433             (*ap)->u.pattern.body = bodyMark;
434             bodyMark = 0;
435             (*ap)->u.pattern.dfa = lexSpecDFA ();
436             r = dfa_parse ((*ap)->u.pattern.dfa, &s);
437             if (r || *s != '/')
438             {
439                 xfree (*ap);
440                 *ap = NULL;
441                 logf (LOG_WARN, "regular expression error. r=%d", r);
442                 return -1;
443             }
444             dfa_mkstate ((*ap)->u.pattern.dfa);
445             s++;
446             break;
447         case REGX_BEGIN:
448             logf (LOG_WARN, "cannot use begin here");
449             continue;
450         case REGX_END:
451             *ap = xmalloc (sizeof(**ap));
452             (*ap)->which = tok;
453             break;
454         }
455         ap = &(*ap)->next;
456     }
457     *ap = NULL;
458     return 0;
459 }
460
461 int readOneSpec (struct lexSpec *spec, const char *s)
462 {
463     int tok, len;
464
465     tok = readParseToken (&s, &len);
466     if (tok == REGX_BEGIN)
467     {
468         actionListDel (&spec->beginActionList);
469         actionListMk (spec, s, &spec->beginActionList);
470     }
471     else if (tok == REGX_END)
472     {
473         actionListDel (&spec->endActionList);
474         actionListMk (spec, s, &spec->endActionList);
475     }
476     else if (tok == REGX_PATTERN)
477     {
478         int r;
479         struct lexRule *rp;
480         r = dfa_parse (spec->trans.dfa, &s);
481         if (r)
482         {
483             logf (LOG_WARN, "regular expression error. r=%d", r);
484             return -1;
485         }
486         if (*s != '/')
487         {
488             logf (LOG_WARN, "expects / at end of pattern. got %c", *s);
489             return -1;
490         }
491         s++;
492         rp = xmalloc (sizeof(*rp));
493         rp->info.no = spec->trans.ruleNo++;
494         rp->next = spec->trans.rules;
495         spec->trans.rules = rp;
496         actionListMk (spec, s, &rp->info.actionList);
497     }
498     return 0;
499 }
500
501 int readFileSpec (struct lexSpec *spec)
502 {
503     char *lineBuf;
504     int lineSize = 512;
505     struct lexRule *rp;
506     int c, i, errors = 0;
507     FILE *spec_inf;
508
509     lineBuf = xmalloc (1+lineSize);
510     logf (LOG_LOG, "reading regx filter %s.flt", spec->name);
511     sprintf (lineBuf, "%s.flt", spec->name);
512     if (!(spec_inf = yaz_path_fopen (data1_get_tabpath(spec->dh),
513                                      lineBuf, "r")))
514     {
515         logf (LOG_ERRNO|LOG_WARN, "cannot read spec file %s", spec->name);
516         xfree (lineBuf);
517         return -1;
518     }
519     spec->lineNo = 0;
520     spec->trans.ruleNo = 1;
521     c = getc (spec_inf);
522     while (c != EOF)
523     {
524         int off = 0;
525         if (c == '#' || c == '\n' || c == ' ' || c == '\t')
526         {
527             while (c != '\n' && c != EOF)
528                 c = getc (spec_inf);
529             spec->lineNo++;
530             if (c == '\n')
531                 c = getc (spec_inf);
532         }
533         else
534         {
535             int addLine = 0;
536
537             lineBuf[off++] = c;
538             while (1)
539             {
540                 int c1 = c;
541                 c = getc (spec_inf);
542                 if (c == EOF)
543                     break;
544                 if (c1 == '\n')
545                 {
546                     if (c != ' ' && c != '\t')
547                         break;
548                     addLine++;
549                 }
550                 lineBuf[off] = c;
551                 if (off < lineSize)
552                     off++;
553             }
554             lineBuf[off] = '\0';
555             readOneSpec (spec, lineBuf);
556             spec->lineNo += addLine;
557         }
558     }
559     fclose (spec_inf);
560     xfree (lineBuf);
561     spec->trans.fastRule = xmalloc (sizeof(*spec->trans.fastRule) *
562                                    spec->trans.ruleNo);
563     for (i = 0; i<spec->trans.ruleNo; i++)
564         spec->trans.fastRule[i] = NULL;
565     for (rp = spec->trans.rules; rp; rp = rp->next)
566         spec->trans.fastRule[rp->info.no] = &rp->info;
567     if (errors)
568         return -1;
569 #if 0
570     debug_dfa_trav = 1;
571     debug_dfa_tran = 1;
572     debug_dfa_followpos = 1;
573     dfa_verbose = 1;
574 #endif
575     dfa_mkstate (spec->trans.dfa);
576     return 0;
577 }
578
579 static struct lexSpec *curLexSpec = NULL;
580
581 static void destroy_data (struct data1_node *n)
582 {
583     assert (n->which == DATA1N_data);
584     xfree (n->u.data.data);
585 }
586
587 static void execData (struct lexSpec *spec,
588                       data1_node **d1_stack, int *d1_level,
589                       const char *ebuf, int elen, int formatted_text)
590 {
591     struct data1_node *res, *parent;
592
593     if (elen == 0) /* shouldn't happen, but it does! */
594         return ;
595 #if REGX_DEBUG
596     if (elen > 40)
597         logf (LOG_DEBUG, "execData %.15s ... %.*s", ebuf, 15, ebuf + elen-15);
598     else if (elen > 0)
599         logf (LOG_DEBUG, "execData %.*s", elen, ebuf);
600     else 
601         logf (LOG_DEBUG, "execData len=%d", elen);
602 #endif
603         
604     if (*d1_level <= 1)
605         return;
606
607     parent = d1_stack[*d1_level -1];
608     assert (parent);
609     if ((res=d1_stack[*d1_level]) && res->which == DATA1N_data)
610     {
611         if (elen + res->u.data.len <= DATA1_LOCALDATA)
612             memcpy (res->u.data.data + res->u.data.len, ebuf, elen);
613         else
614         {
615             char *nb = xmalloc (elen + res->u.data.len);
616             memcpy (nb, res->u.data.data, res->u.data.len);
617             memcpy (nb + res->u.data.len, ebuf, elen);
618             if (res->u.data.len > DATA1_LOCALDATA)
619                 xfree (res->u.data.data);
620             res->u.data.data = nb;
621             res->destroy = destroy_data;
622         }
623         res->u.data.len += elen;
624     }
625     else
626     {
627         res = data1_mk_node (spec->dh, spec->m);
628         res->parent = parent;
629         res->which = DATA1N_data;
630         res->u.data.what = DATA1I_text;
631         res->u.data.len = elen;
632         res->u.data.formatted_text = formatted_text;
633         if (elen > DATA1_LOCALDATA)
634         {
635             res->u.data.data = xmalloc (elen);
636             res->destroy = destroy_data;
637         }
638         else
639             res->u.data.data = res->lbuf;
640         memcpy (res->u.data.data, ebuf, elen);
641         res->root = parent->root;
642         
643         parent->num_children++;
644         parent->last_child = res;
645         if (d1_stack[*d1_level])
646             d1_stack[*d1_level]->next = res;
647         else
648             parent->child = res;
649         d1_stack[*d1_level] = res;
650     }
651 }
652
653 static void execDataP (struct lexSpec *spec,
654                        data1_node **d1_stack, int *d1_level,
655                        const char *ebuf, int elen, int formatted_text)
656 {
657     execData (spec, d1_stack, d1_level, ebuf, elen, formatted_text);
658 }
659
660
661 static void tagBegin (struct lexSpec *spec, 
662                       data1_node **d1_stack, int *d1_level,
663                       const char *tag, int len)
664 {
665     struct data1_node *parent = d1_stack[*d1_level -1];
666     data1_element *elem = NULL;
667     data1_node *partag = get_parent_tag(spec->dh, parent);
668     data1_node *res;
669     data1_element *e = NULL;
670     int localtag = 0;
671
672     if (*d1_level == 0)
673     {
674         logf (LOG_WARN, "in element begin. No record type defined");
675         return ;
676     }
677     
678     res = data1_mk_node (spec->dh, spec->m);
679     res->parent = parent;
680     res->which = DATA1N_tag;
681     res->u.tag.tag = res->lbuf;
682     res->u.tag.get_bytes = -1;
683
684     if (len >= DATA1_LOCALDATA)
685         len = DATA1_LOCALDATA-1;
686
687     memcpy (res->u.tag.tag, tag, len);
688     res->u.tag.tag[len] = '\0';
689    
690 #if REGX_DEBUG 
691     logf (LOG_DEBUG, "tag begin %s (%d)", res->u.tag.tag, *d1_level);
692 #endif
693     if (parent->which == DATA1N_variant)
694         return ;
695     if (partag)
696         if (!(e = partag->u.tag.element))
697             localtag = 1;
698     
699     elem = data1_getelementbytagname (spec->dh, d1_stack[0]->u.root.absyn,
700                                       e, res->u.tag.tag);
701     
702     res->u.tag.element = elem;
703     res->u.tag.node_selected = 0;
704     res->u.tag.make_variantlist = 0;
705     res->u.tag.no_data_requested = 0;
706     res->root = parent->root;
707     parent->num_children++;
708     parent->last_child = res;
709     if (d1_stack[*d1_level])
710         d1_stack[*d1_level]->next = res;
711     else
712         parent->child = res;
713     d1_stack[*d1_level] = res;
714     d1_stack[++(*d1_level)] = NULL;
715 }
716
717 static void tagEnd (struct lexSpec *spec, 
718                     data1_node **d1_stack, int *d1_level,
719                     const char *tag, int len)
720 {
721     while (*d1_level > 1)
722     {
723         (*d1_level)--;
724         if (!tag ||
725             (strlen(d1_stack[*d1_level]->u.tag.tag) == len &&
726              !memcmp (d1_stack[*d1_level]->u.tag.tag, tag, len)))
727             break;
728     }
729 #if REGX_DEBUG
730     logf (LOG_DEBUG, "tag end (%d)", *d1_level);
731 #endif
732 }
733
734
735 static int tryMatch (struct lexSpec *spec, int *pptr, int *mptr,
736                      struct DFA *dfa)
737 {
738     struct DFA_state *state = dfa->states[0];
739     struct DFA_tran *t;
740     unsigned char c;
741     unsigned char c_prev = 0;
742     int ptr = *pptr;
743     int start_ptr = *pptr;
744     int last_rule = 0;
745     int last_ptr = 0;
746     int i;
747
748     while (1)
749     {
750         c = f_win_advance (spec, &ptr);
751         if (ptr == F_WIN_EOF)
752         {
753             if (last_rule)
754             {
755                 *mptr = start_ptr;
756                 *pptr = last_ptr;
757                 return 1;
758             }
759             break;
760         }
761         t = state->trans;
762         i = state->tran_no;
763         while (1)
764             if (--i < 0)
765             {
766                 if (last_rule)
767                 {
768                     *mptr = start_ptr;     /* match starts here */
769                     *pptr = last_ptr;      /* match end here (+1) */
770                     return 1;
771                 }
772                 state = dfa->states[0];
773                 start_ptr = ptr;
774                 c_prev = c;
775                 break;
776             }
777             else if (c >= t->ch[0] && c <= t->ch[1])
778             {
779                 state = dfa->states[t->to];
780                 if (state->rule_no)
781                 {
782                     if (c_prev == '\n')
783                     {
784                         last_rule = state->rule_no;
785                         last_ptr = ptr;
786                     }
787                     else
788                     {
789                         last_rule = state->rule_nno;
790                         last_ptr = ptr;
791                     }
792                 }
793                 break;
794             }
795             else
796                 t++;
797     }
798     return 0;
799 }
800
801 static int execTok (struct lexSpec *spec, const char **src,
802                     int arg_no, int *arg_start, int *arg_end,
803                     const char **tokBuf, int *tokLen)
804 {
805     const char *s = *src;
806
807     while (*s == ' ' || *s == '\t')
808         s++;
809     if (!*s)
810         return 0;
811     if (*s == '$' && s[1] >= '0' && s[1] <= '9')
812     {
813         int n = 0;
814         s++;
815         while (*s >= '0' && *s <= '9')
816             n = n*10 + (*s++ -'0');
817         if (arg_no == 0)
818         {
819             *tokBuf = "";
820             *tokLen = 0;
821         }
822         else
823         {
824             if (n >= arg_no)
825                 n = arg_no-1;
826             *tokBuf = f_win_get (spec, arg_start[n], arg_end[n], tokLen);
827         }
828     }
829     else if (*s == '\"')
830     {
831         *tokBuf = ++s;
832         while (*s && *s != '\"')
833             s++;
834         *tokLen = s - *tokBuf;
835         if (*s)
836             s++;
837         *src = s;
838     }
839     else if (*s == '\n' || *s == ';')
840     {
841         *src = s+1;
842         return 1;
843     }
844     else if (*s == '-')
845     {
846         *tokBuf = s++;
847         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != ';')
848             s++;
849         *tokLen = s - *tokBuf;
850         *src = s;
851         return 3;
852     }
853     else
854     {
855         *tokBuf = s++;
856         while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != ';')
857             s++;
858         *tokLen = s - *tokBuf;
859     }
860     *src = s;
861     return 2;
862 }
863
864 static char *regxStrz (const char *src, int len)
865 {
866     static char str[64];
867     
868     if (len > 63)
869         len = 63;
870     memcpy (str, src, len);
871     str[len] = '\0';
872     return str;
873 }
874
875 static int execCode (struct lexSpec *spec,
876                      int arg_no, int *arg_start, int *arg_end, int *pptr,
877                      struct regxCode *code,
878                      data1_node **d1_stack, int *d1_level)
879 {
880     const char *s = code->str;
881     int cmd_len, r;
882     int returnCode = 1;
883     const char *cmd_str;
884     
885     r = execTok (spec, &s, arg_no, arg_start, arg_end, &cmd_str, &cmd_len);
886     while (r)
887     {
888         char *p;
889         
890         if (r == 1)
891         {
892             r = execTok (spec, &s, arg_no, arg_start, arg_end,
893                          &cmd_str, &cmd_len);
894             continue;
895         }
896         p = regxStrz (cmd_str, cmd_len);
897         if (!strcmp (p, "begin"))
898         {
899             r = execTok (spec, &s, arg_no, arg_start, arg_end,
900                          &cmd_str, &cmd_len);
901             if (r < 2)
902                 continue;
903             p = regxStrz (cmd_str, cmd_len);
904             if (!strcmp (p, "record"))
905             {
906                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
907                              &cmd_str, &cmd_len);
908                 if (r < 2)
909                     continue;
910                 if (*d1_level == 0)
911                 {
912                     static char absynName[64];
913                     data1_absyn *absyn;
914
915                     if (cmd_len > 63)
916                         cmd_len = 63;
917                     memcpy (absynName, cmd_str, cmd_len);
918                     absynName[cmd_len] = '\0';
919
920 #if REGX_DEBUG
921                     logf (LOG_DEBUG, "begin record %s", absynName);
922 #endif
923                     if (!(absyn = data1_get_absyn (spec->dh, absynName)))
924                         logf (LOG_WARN, "Unknown tagset: %s", absynName);
925                     else
926                     {
927                         data1_node *res;
928
929                         res = data1_mk_node (spec->dh, spec->m);
930                         res->which = DATA1N_root;
931                         res->u.root.type = absynName;
932                         res->u.root.absyn = absyn;
933                         res->root = res;
934                         
935                         d1_stack[*d1_level] = res;
936                         d1_stack[++(*d1_level)] = NULL;
937                     }
938                 }
939                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
940                              &cmd_str, &cmd_len);
941             }
942             else if (!strcmp (p, "element"))
943             {
944                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
945                              &cmd_str, &cmd_len);
946                 if (r < 2)
947                     continue;
948                 tagBegin (spec, d1_stack, d1_level, cmd_str, cmd_len);
949                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
950                              &cmd_str, &cmd_len);
951             }
952         }
953         else if (!strcmp (p, "end"))
954         {
955             r = execTok (spec, &s, arg_no, arg_start, arg_end,
956                          &cmd_str, &cmd_len);
957             if (r > 1)
958             {
959                 p = regxStrz (cmd_str, cmd_len);
960                 if (!strcmp (p, "record"))
961                 {
962                     *d1_level = 0;
963                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
964                                  &cmd_str, &cmd_len);
965 #if REGX_DEBUG
966                     logf (LOG_DEBUG, "end record");
967 #endif
968                     returnCode = 0;
969                 }
970                 else if (!strcmp (p, "element"))
971                 {
972                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
973                                  &cmd_str, &cmd_len);
974 #if 0
975                     if (*d1_level == 1)
976                     {
977                         *d1_level = 0;
978                         returnCode = 0;
979                     }
980 #endif
981                     if (r > 2)
982                     {
983                         tagEnd (spec, d1_stack, d1_level, cmd_str, cmd_len);
984                         r = execTok (spec, &s, arg_no, arg_start, arg_end,
985                                      &cmd_str, &cmd_len);
986                     }
987                     else
988                         tagEnd (spec, d1_stack, d1_level, NULL, 0);
989                 }
990                 else
991                     logf (LOG_WARN, "missing record/element/variant");
992             }
993             else
994                 logf (LOG_WARN, "missing record/element/variant");
995         }
996         else if (!strcmp (p, "data"))
997         {
998             int textFlag = 0;
999             int element_len;
1000             const char *element_str = NULL;
1001             
1002             while ((r = execTok (spec, &s, arg_no, arg_start, arg_end,
1003                                  &cmd_str, &cmd_len)) == 3)
1004             {
1005                 if (cmd_len==5 && !memcmp ("-text", cmd_str, cmd_len))
1006                     textFlag = 1;
1007                 else if (cmd_len==8 && !memcmp ("-element", cmd_str, cmd_len))
1008                 {
1009                     r = execTok (spec, &s, arg_no, arg_start, arg_end,
1010                                  &element_str, &element_len);
1011                     if (r < 2)
1012                         break;
1013                 }
1014                 else 
1015                     logf (LOG_WARN, "bad data option: %.*s",
1016                           cmd_len, cmd_str);
1017             }
1018             if (r != 2)
1019             {
1020                 logf (LOG_WARN, "missing data item after data");
1021                 continue;
1022             }
1023             if (element_str)
1024                 tagBegin (spec, d1_stack, d1_level, element_str, element_len);
1025             do
1026             {
1027                 execData (spec, d1_stack, d1_level, cmd_str, cmd_len,
1028                           textFlag);
1029                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1030                          &cmd_str, &cmd_len);
1031             } while (r > 1);
1032             if (element_str)
1033                 tagEnd (spec, d1_stack, d1_level, NULL, 0);
1034         }
1035         else if (!strcmp (p, "unread"))
1036         {
1037             int no, offset;
1038             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1039                          &cmd_str, &cmd_len);
1040             if (r==3 && cmd_len == 7 && !memcmp ("-offset", cmd_str, cmd_len))
1041             {
1042                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1043                              &cmd_str, &cmd_len);
1044                 if (r < 2)
1045                 {
1046                     logf (LOG_WARN, "missing number after -offset");
1047                     continue;
1048                 }
1049                 p = regxStrz (cmd_str, cmd_len);
1050                 offset = atoi (p);
1051                 r = execTok (spec, &s, arg_no, arg_start, arg_end,
1052                              &cmd_str, &cmd_len);
1053             }
1054             else
1055                 offset = 0;
1056             if (r < 2)
1057             {
1058                 logf (LOG_WARN, "missing index after unread command");
1059                 continue;
1060             }
1061             if (cmd_len != 1 || *cmd_str < '0' || *cmd_str > '9')
1062             {
1063                 logf (LOG_WARN, "bad index after unread command");
1064                 continue;
1065             }
1066             else
1067             {
1068                 no = *cmd_str - '0';
1069                 if (no >= arg_no)
1070                     no = arg_no - 1;
1071                 *pptr = arg_start[no] + offset;
1072             }
1073             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1074                          &cmd_str, &cmd_len);
1075         }
1076         else
1077         {
1078             logf (LOG_WARN, "unknown code command: %.*s", cmd_len, cmd_str);
1079             r = execTok (spec, &s, arg_no, arg_start, arg_end,
1080                          &cmd_str, &cmd_len);
1081             continue;
1082         }
1083         if (r > 1)
1084         {
1085             logf (LOG_WARN, "ignoring token %.*s", cmd_len, cmd_str);
1086             do {
1087                 r = execTok (spec, &s, arg_no, arg_start, arg_end, &cmd_str,
1088                              &cmd_len);
1089             } while (r > 1);
1090         }
1091     }
1092     return returnCode;
1093 }
1094
1095
1096 static int execAction (struct lexSpec *spec, struct lexRuleAction *ap,
1097                        data1_node **d1_stack, int *d1_level,
1098                        int start_ptr, int *pptr)
1099 {
1100     int sptr;
1101     int arg_start[20];
1102     int arg_end[20];
1103     int arg_no = 1;
1104
1105     arg_start[0] = start_ptr;
1106     arg_end[0] = *pptr;
1107
1108     while (ap)
1109     {
1110         switch (ap->which)
1111         {
1112         case REGX_PATTERN:
1113             if (ap->u.pattern.body)
1114             {
1115                 arg_start[arg_no] = *pptr;
1116                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1117                 {
1118                     arg_end[arg_no] = F_WIN_EOF;
1119                     arg_no++;
1120                     arg_start[arg_no] = F_WIN_EOF;
1121                     arg_end[arg_no] = F_WIN_EOF;
1122 /* return 1*/
1123                 }
1124                 else
1125                 {
1126                     arg_end[arg_no] = sptr;
1127                     arg_no++;
1128                     arg_start[arg_no] = sptr;
1129                     arg_end[arg_no] = *pptr;
1130                 }
1131             }
1132             else
1133             {
1134                 arg_start[arg_no] = *pptr;
1135                 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa))
1136                     return 1;
1137                 if (sptr != arg_start[arg_no])
1138                     return 1;
1139                 arg_end[arg_no] = *pptr;
1140             }
1141             arg_no++;
1142             break;
1143         case REGX_CODE:
1144             if (!execCode (spec, arg_no, arg_start, arg_end, pptr,
1145                            ap->u.code, d1_stack, d1_level))
1146                 return 0;
1147             break;
1148         case REGX_END:
1149             arg_start[arg_no] = *pptr;
1150             arg_end[arg_no] = F_WIN_EOF;
1151             arg_no++;
1152             *pptr = F_WIN_EOF;
1153         }
1154         ap = ap->next;
1155     }
1156     return 1;
1157 }
1158
1159 static int execRule (struct lexSpec *spec, struct lexTrans *trans,
1160                      data1_node **d1_stack, int *d1_level,
1161                      int ruleNo, int start_ptr, int *pptr)
1162 {
1163 #if REGX_DEBUG
1164     logf (LOG_DEBUG, "execRule %d", ruleNo);
1165 #endif
1166     return execAction (spec, trans->fastRule[ruleNo]->actionList,
1167                        d1_stack, d1_level, start_ptr, pptr);
1168 }
1169
1170 data1_node *lexNode (struct lexSpec *spec, struct lexTrans *trans,
1171                      data1_node **d1_stack, int *d1_level,
1172                      int *ptr)
1173 {
1174     struct DFA_state *state = trans->dfa->states[0];
1175     struct DFA_tran *t;
1176     unsigned char c;
1177     unsigned char c_prev = '\n';
1178     int i;
1179     int last_rule = 0;
1180     int last_ptr = *ptr;
1181     int start_ptr = *ptr;
1182     int skip_ptr = *ptr;
1183
1184     while (1)
1185     {
1186         c = f_win_advance (spec, ptr);
1187         if (*ptr == F_WIN_EOF)
1188         {
1189             if (last_rule)
1190             {
1191                 if (skip_ptr < start_ptr)
1192                 {
1193                     int size;
1194                     char *buf;
1195                     buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1196                     execDataP (spec, d1_stack, d1_level, buf, size, 0);
1197                 }
1198                 *ptr = last_ptr;
1199                 if (!execRule (spec, trans, d1_stack, d1_level, last_rule,
1200                                start_ptr, ptr))
1201                     break;
1202                 skip_ptr = *ptr;
1203                 last_rule = 0;
1204             }
1205             else if (skip_ptr < *ptr)
1206             {
1207                 int size;
1208                 char *buf;
1209                 buf = f_win_get (spec, skip_ptr, *ptr, &size);
1210                 execDataP (spec, d1_stack, d1_level, buf, size, 0);
1211             }
1212             if (*ptr == F_WIN_EOF)
1213                 break;
1214         }
1215         t = state->trans;
1216         i = state->tran_no;
1217         while (1)
1218             if (--i < 0)
1219             {   /* no transition for character c ... */
1220                 if (last_rule)
1221                 {
1222                     if (skip_ptr < start_ptr)
1223                     {
1224                         int size;
1225                         char *buf;
1226                         buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1227                         execDataP (spec, d1_stack, d1_level, buf, size, 0);
1228                     }
1229                     *ptr = last_ptr;
1230                     if (!execRule (spec, trans, d1_stack, d1_level, last_rule,
1231                                    start_ptr, ptr))
1232                     {
1233                         if (spec->f_win_ef && *ptr != F_WIN_EOF)
1234                         {
1235 #if REGX_DEBUG
1236                             logf (LOG_DEBUG, "regx: endf ptr=%d", *ptr);
1237 #endif
1238                             (*spec->f_win_ef)(spec->f_win_fh, *ptr);
1239                         }
1240                         return NULL;
1241                     }
1242                     skip_ptr = *ptr;
1243                     last_rule = 0;
1244                     start_ptr = *ptr;
1245                     if (start_ptr > 0)
1246                     {
1247                         --start_ptr;
1248                         c_prev = f_win_advance (spec, &start_ptr);
1249                     }
1250                 }
1251                 else
1252                 {
1253                     c_prev = f_win_advance (spec, &start_ptr);
1254                     *ptr = start_ptr;
1255                 }
1256                 state = trans->dfa->states[0];
1257                 break;
1258             }
1259             else if (c >= t->ch[0] && c <= t->ch[1])
1260             {   /* transition ... */
1261                 state = trans->dfa->states[t->to];
1262                 if (state->rule_no)
1263                 {
1264                     if (c_prev == '\n')
1265                     {
1266                         last_rule = state->rule_no;
1267                         last_ptr = *ptr;
1268                     } 
1269                     else if (state->rule_nno)
1270                     {
1271                         last_rule = state->rule_nno;
1272                         last_ptr = *ptr;
1273                     }
1274                 }
1275                 break;
1276             }
1277             else
1278                 t++;
1279     }
1280     return NULL;
1281 }
1282
1283 static data1_node *lexRoot (struct lexSpec *spec, off_t offset)
1284 {
1285     data1_node *d1_stack[512];
1286     int d1_level = 0;
1287     int ptr = offset;
1288
1289     d1_stack[d1_level] = NULL;
1290     if (spec->beginActionList)
1291         execAction (spec, spec->beginActionList,
1292                     d1_stack, &d1_level, 0, &ptr);
1293     lexNode (spec, &spec->trans, d1_stack, &d1_level, &ptr);
1294     if (spec->endActionList)
1295         execAction (spec, spec->endActionList,
1296                     d1_stack, &d1_level, ptr, &ptr);
1297     return *d1_stack;
1298 }
1299
1300 data1_node *grs_read_regx (struct grs_read_info *p)
1301 {
1302     int res;
1303     data1_node *n;
1304
1305 #if REGX_DEBUG
1306     logf (LOG_DEBUG, "grs_read_regx");
1307 #endif
1308     if (!curLexSpec || strcmp (curLexSpec->name, p->type))
1309     {
1310         if (curLexSpec)
1311             lexSpecDel (&curLexSpec);
1312         curLexSpec = lexSpecMk (p->type);
1313         res = readFileSpec (curLexSpec);
1314         if (res)
1315         {
1316             lexSpecDel (&curLexSpec);
1317             return NULL;
1318         }
1319     }
1320     if (!p->offset)
1321     {
1322         curLexSpec->f_win_start = 0;
1323         curLexSpec->f_win_end = 0;
1324         curLexSpec->f_win_rf = p->readf;
1325         curLexSpec->f_win_sf = p->seekf;
1326         curLexSpec->f_win_fh = p->fh;
1327         curLexSpec->f_win_ef = p->endf;
1328         curLexSpec->f_win_size = 500000;
1329     }
1330     curLexSpec->m = p->mem;
1331     curLexSpec->dh = p->dh;
1332     n = lexRoot (curLexSpec, p->offset);
1333     return n;
1334 }