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