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