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