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