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