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