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