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