IDZEBRA 2.2.11
mod_grs_regx.c
Go to the documentation of this file.
1/* This file is part of the Zebra server.
2 Copyright (C) Index Data
3
4Zebra is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18*/
19
20#if HAVE_CONFIG_H
21#include <config.h>
22#endif
23#include <stdio.h>
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
28
29#include <yaz/tpath.h>
30#include <yaz/snprintf.h>
31#include <idzebra/util.h>
32#include <dfa.h>
33#include <idzebra/recgrs.h>
34
35#if HAVE_TCL_H
36#include <tcl.h>
37
38#if MAJOR_VERSION >= 8
39#define HAVE_TCL_OBJECTS
40#endif
41#endif
42
43#define REGX_DEBUG 0
44
45#define F_WIN_EOF 2000000000
46#define F_WIN_READ 1
47
48#define REGX_EOF 0
49#define REGX_PATTERN 1
50#define REGX_BODY 2
51#define REGX_BEGIN 3
52#define REGX_END 4
53#define REGX_CODE 5
54#define REGX_CONTEXT 6
55#define REGX_INIT 7
56
57#define REGX_MAX_ARGS 20
58
59struct regxCode {
60 char *str;
61#if HAVE_TCL_OBJECTS
62 Tcl_Obj *tcl_obj;
63#endif
64};
65
67 int which;
68 union {
69 struct {
70 struct DFA *dfa; /* REGX_PATTERN */
71 int body;
73 struct regxCode *code; /* REGX_CODE */
74 } u;
76};
77
79 int no;
81};
82
83struct lexRule {
85 struct lexRule *next;
86};
87
101
103 int max;
104 char *buf;
105};
106
107struct lexSpec {
108 char *name;
110
114
116 NMEM m;
118#if HAVE_TCL_H
119 Tcl_Interp *tcl_interp;
120#endif
122 off_t (*f_win_ef)(struct ZebraRecStream *s, off_t *);
123
124 int f_win_start; /* first byte of buffer is this file offset */
125 int f_win_end; /* last byte of buffer is this offset - 1 */
126 int f_win_size; /* size of buffer */
127 char *f_win_buf; /* buffer itself */
128 int (*f_win_rf)(struct ZebraRecStream *, char *, size_t);
129 off_t (*f_win_sf)(struct ZebraRecStream *, off_t);
130
136
140 int ptr;
141};
142
143struct lexSpecs {
144 struct lexSpec *spec;
145 char type[256];
146};
147
148static char *f_win_get (struct lexSpec *spec, off_t start_pos, off_t end_pos,
149 int *size)
150{
151 int i, r, off = start_pos - spec->f_win_start;
152
153 if (off >= 0 && end_pos <= spec->f_win_end)
154 {
155 *size = end_pos - start_pos;
156 return spec->f_win_buf + off;
157 }
158 if (off < 0 || start_pos >= spec->f_win_end)
159 {
160 (*spec->f_win_sf)(spec->stream, start_pos);
161 spec->f_win_start = start_pos;
162
163 if (!spec->f_win_buf)
164 spec->f_win_buf = (char *) xmalloc (spec->f_win_size);
165 *size = (*spec->f_win_rf)(spec->stream, spec->f_win_buf,
166 spec->f_win_size);
167 spec->f_win_end = spec->f_win_start + *size;
168
169 if (*size > end_pos - start_pos)
170 *size = end_pos - start_pos;
171 return spec->f_win_buf;
172 }
173 for (i = 0; i<spec->f_win_end - start_pos; i++)
174 spec->f_win_buf[i] = spec->f_win_buf[i + off];
175 r = (*spec->f_win_rf)(spec->stream,
176 spec->f_win_buf + i,
177 spec->f_win_size - i);
178 spec->f_win_start = start_pos;
179 spec->f_win_end += r;
180 *size = i + r;
181 if (*size > end_pos - start_pos)
182 *size = end_pos - start_pos;
183 return spec->f_win_buf;
184}
185
186static int f_win_advance (struct lexSpec *spec, int *pos)
187{
188 int size;
189 char *buf;
190
191 if (*pos >= spec->f_win_start && *pos < spec->f_win_end)
192 return spec->f_win_buf[(*pos)++ - spec->f_win_start];
193 if (*pos == F_WIN_EOF)
194 return 0;
195 buf = f_win_get (spec, *pos, *pos+1, &size);
196 if (size == 1)
197 {
198 (*pos)++;
199 return *buf;
200 }
201 *pos = F_WIN_EOF;
202 return 0;
203}
204
205static void regxCodeDel (struct regxCode **pp)
206{
207 struct regxCode *p = *pp;
208 if (p)
209 {
210#if HAVE_TCL_OBJECTS
211 if (p->tcl_obj)
212 Tcl_DecrRefCount (p->tcl_obj);
213#endif
214 xfree (p->str);
215 xfree (p);
216 *pp = NULL;
217 }
218}
219
220static void regxCodeMk (struct regxCode **pp, const char *buf, int len)
221{
222 struct regxCode *p;
223
224 p = (struct regxCode *) xmalloc (sizeof(*p));
225 p->str = (char *) xmalloc (len+1);
226 memcpy (p->str, buf, len);
227 p->str[len] = '\0';
228#if HAVE_TCL_OBJECTS
229 p->tcl_obj = Tcl_NewStringObj ((char *) buf, len);
230 if (p->tcl_obj)
231 Tcl_IncrRefCount (p->tcl_obj);
232#endif
233 *pp = p;
234}
235
236static struct DFA *lexSpecDFA (void)
237{
238 struct DFA *dfa;
239
240 dfa = dfa_init ();
241 dfa_parse_cmap_del (dfa, ' ');
242 dfa_parse_cmap_del (dfa, '\t');
243 dfa_parse_cmap_add (dfa, '/', 0);
244 return dfa;
245}
246
247static void actionListDel (struct lexRuleAction **rap)
248{
249 struct lexRuleAction *ra1, *ra;
250
251 for (ra = *rap; ra; ra = ra1)
252 {
253 ra1 = ra->next;
254 switch (ra->which)
255 {
256 case REGX_PATTERN:
257 dfa_delete (&ra->u.pattern.dfa);
258 break;
259 case REGX_CODE:
260 regxCodeDel (&ra->u.code);
261 break;
262 }
263 xfree (ra);
264 }
265 *rap = NULL;
266}
267
268static struct lexContext *lexContextCreate (const char *name)
269{
270 struct lexContext *p = (struct lexContext *) xmalloc (sizeof(*p));
271
272 p->name = xstrdup (name);
273 p->ruleNo = 1;
274 p->initFlag = 0;
275 p->dfa = lexSpecDFA ();
276 p->rules = NULL;
277 p->fastRule = NULL;
278 p->beginActionList = NULL;
279 p->endActionList = NULL;
280 p->initActionList = NULL;
281 p->next = NULL;
282 return p;
283}
284
285static void lexContextDestroy (struct lexContext *p)
286{
287 struct lexRule *rp, *rp1;
288
289 dfa_delete (&p->dfa);
290 xfree (p->fastRule);
291 for (rp = p->rules; rp; rp = rp1)
292 {
293 rp1 = rp->next;
295 xfree (rp);
296 }
300 xfree (p->name);
301 xfree (p);
302}
303
304static struct lexSpec *lexSpecCreate (const char *name, data1_handle dh)
305{
306 struct lexSpec *p;
307 int i;
308
309 p = (struct lexSpec *) xmalloc (sizeof(*p));
310 p->name = (char *) xmalloc (strlen(name)+1);
311 strcpy (p->name, name);
312
313#if HAVE_TCL_H
314 p->tcl_interp = 0;
315#endif
316 p->dh = dh;
317 p->context = NULL;
318 p->context_stack_size = 100;
319 p->context_stack = (struct lexContext **)
320 xmalloc (sizeof(*p->context_stack) * p->context_stack_size);
321 p->f_win_buf = NULL;
322
323 p->maxLevel = 128;
324 p->concatBuf = (struct lexConcatBuf *)
325 xmalloc (sizeof(*p->concatBuf) * p->maxLevel);
326 for (i = 0; i < p->maxLevel; i++)
327 {
328 p->concatBuf[i].max = 0;
329 p->concatBuf[i].buf = 0;
330 }
331 p->d1_stack = (data1_node **) xmalloc (sizeof(*p->d1_stack) * p->maxLevel);
332 p->d1_level = 0;
333 return p;
334}
335
336static void lexSpecDestroy (struct lexSpec **pp)
337{
338 struct lexSpec *p;
339 struct lexContext *lt;
340 int i;
341
342 assert (pp);
343 p = *pp;
344 if (!p)
345 return ;
346
347 for (i = 0; i < p->maxLevel; i++)
348 xfree (p->concatBuf[i].buf);
349 xfree (p->concatBuf);
350
351 lt = p->context;
352 while (lt)
353 {
354 struct lexContext *lt_next = lt->next;
356 lt = lt_next;
357 }
358#if HAVE_TCL_OBJECTS
359 if (p->tcl_interp)
360 Tcl_DeleteInterp (p->tcl_interp);
361#endif
362 xfree (p->name);
363 xfree (p->f_win_buf);
364 xfree (p->context_stack);
365 xfree (p->d1_stack);
366 xfree (p);
367 *pp = NULL;
368}
369
370static int readParseToken (const char **cpp, int *len)
371{
372 const char *cp = *cpp;
373 char cmd[32];
374 int i, level;
375
376 while (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\r')
377 cp++;
378 switch (*cp)
379 {
380 case '\0':
381 return 0;
382 case '/':
383 *cpp = cp+1;
384 return REGX_PATTERN;
385 case '{':
386 *cpp = cp+1;
387 level = 1;
388 while (*++cp)
389 {
390 if (*cp == '{')
391 level++;
392 else if (*cp == '}')
393 {
394 level--;
395 if (level == 0)
396 break;
397 }
398 }
399 *len = cp - *cpp;
400 return REGX_CODE;
401 default:
402 i = 0;
403 while (1)
404 {
405 if (*cp >= 'a' && *cp <= 'z')
406 cmd[i] = *cp;
407 else if (*cp >= 'A' && *cp <= 'Z')
408 cmd[i] = *cp + 'a' - 'A';
409 else
410 break;
411 if (i < (int) sizeof(cmd)-2)
412 i++;
413 cp++;
414 }
415 cmd[i] = '\0';
416 if (i == 0)
417 {
418 yaz_log (YLOG_WARN, "bad character %d %c", *cp, *cp);
419 cp++;
420 while (*cp && *cp != ' ' && *cp != '\t' &&
421 *cp != '\n' && *cp != '\r')
422 cp++;
423 *cpp = cp;
424 return 0;
425 }
426 *cpp = cp;
427 if (!strcmp (cmd, "begin"))
428 return REGX_BEGIN;
429 else if (!strcmp (cmd, "end"))
430 return REGX_END;
431 else if (!strcmp (cmd, "body"))
432 return REGX_BODY;
433 else if (!strcmp (cmd, "context"))
434 return REGX_CONTEXT;
435 else if (!strcmp (cmd, "init"))
436 return REGX_INIT;
437 else
438 {
439 yaz_log (YLOG_WARN, "bad command %s", cmd);
440 return 0;
441 }
442 }
443}
444
445static int actionListMk (struct lexSpec *spec, const char *s,
446 struct lexRuleAction **ap)
447{
448 int r, tok, len;
449 int bodyMark = 0;
450 const char *s0;
451
452 while ((tok = readParseToken (&s, &len)))
453 {
454 switch (tok)
455 {
456 case REGX_BODY:
457 bodyMark = 1;
458 continue;
459 case REGX_CODE:
460 *ap = (struct lexRuleAction *) xmalloc (sizeof(**ap));
461 (*ap)->which = tok;
462 regxCodeMk (&(*ap)->u.code, s, len);
463 s += len+1;
464 break;
465 case REGX_PATTERN:
466 *ap = (struct lexRuleAction *) xmalloc (sizeof(**ap));
467 (*ap)->which = tok;
468 (*ap)->u.pattern.body = bodyMark;
469 bodyMark = 0;
470 (*ap)->u.pattern.dfa = lexSpecDFA ();
471 s0 = s;
472 r = dfa_parse ((*ap)->u.pattern.dfa, &s);
473 if (r || *s != '/')
474 {
475 int pos = s - s0;
476 xfree (*ap);
477 *ap = NULL;
478 yaz_log(YLOG_WARN, "regular expression error '%.*s'", pos, s0);
479 return -1;
480 }
481 else
482 {
483 int pos = s - s0;
484 if (debug_dfa_tran)
485 printf("pattern: %.*s\n", pos, s0);
486 dfa_mkstate((*ap)->u.pattern.dfa);
487 s++;
488 }
489 break;
490 case REGX_BEGIN:
491 yaz_log (YLOG_WARN, "cannot use BEGIN here");
492 continue;
493 case REGX_INIT:
494 yaz_log (YLOG_WARN, "cannot use INIT here");
495 continue;
496 case REGX_END:
497 *ap = (struct lexRuleAction *) xmalloc (sizeof(**ap));
498 (*ap)->which = tok;
499 break;
500 }
501 ap = &(*ap)->next;
502 }
503 *ap = NULL;
504 return 0;
505}
506
507int readOneSpec (struct lexSpec *spec, const char *s)
508{
509 int len, r, tok;
510 struct lexRule *rp;
511 struct lexContext *lc;
512
513 tok = readParseToken (&s, &len);
514 if (tok == REGX_CONTEXT)
515 {
516 char context_name[32];
517 tok = readParseToken (&s, &len);
518 if (tok != REGX_CODE)
519 {
520 yaz_log (YLOG_WARN, "missing name after CONTEXT keyword");
521 return 0;
522 }
523 if (len > 31)
524 len = 31;
525 memcpy (context_name, s, len);
526 context_name[len] = '\0';
527 lc = lexContextCreate (context_name);
528 lc->next = spec->context;
529 spec->context = lc;
530 return 0;
531 }
532 if (!spec->context)
533 spec->context = lexContextCreate ("main");
534
535 switch (tok)
536 {
537 case REGX_BEGIN:
539 actionListMk (spec, s, &spec->context->beginActionList);
540 break;
541 case REGX_END:
543 actionListMk (spec, s, &spec->context->endActionList);
544 break;
545 case REGX_INIT:
547 actionListMk (spec, s, &spec->context->initActionList);
548 break;
549 case REGX_PATTERN:
550#if REGX_DEBUG
551 yaz_log (YLOG_LOG, "rule %d %s", spec->context->ruleNo, s);
552#endif
553 r = dfa_parse (spec->context->dfa, &s);
554 if (r)
555 {
556 yaz_log (YLOG_WARN, "regular expression error. r=%d", r);
557 return -1;
558 }
559 if (*s != '/')
560 {
561 yaz_log (YLOG_WARN, "expects / at end of pattern. got %c", *s);
562 return -1;
563 }
564 s++;
565 rp = (struct lexRule *) xmalloc (sizeof(*rp));
566 rp->info.no = spec->context->ruleNo++;
567 rp->next = spec->context->rules;
568 spec->context->rules = rp;
569 actionListMk (spec, s, &rp->info.actionList);
570 }
571 return 0;
572}
573
574int readFileSpec (struct lexSpec *spec)
575{
576 struct lexContext *lc;
577 int c, i, errors = 0;
578 FILE *spec_inf = 0;
579 WRBUF lineBuf;
580 char fname[256];
581
582#if HAVE_TCL_H
583 if (spec->tcl_interp)
584 {
585 yaz_snprintf(fname, sizeof(fname), "%s.tflt", spec->name);
586 spec_inf = data1_path_fopen (spec->dh, fname, "r");
587 }
588#endif
589 if (!spec_inf)
590 {
591 yaz_snprintf(fname, sizeof(fname), "%s.flt", spec->name);
592 spec_inf = data1_path_fopen (spec->dh, fname, "r");
593 }
594 if (!spec_inf)
595 {
596 yaz_log(YLOG_ERRNO|YLOG_WARN, "cannot read spec file %s", spec->name);
597 return -1;
598 }
599 yaz_log(YLOG_LOG, "reading regx filter %s", fname);
600#if HAVE_TCL_H
601 if (spec->tcl_interp)
602 yaz_log(YLOG_LOG, "Tcl enabled");
603#endif
604
605#if 0
606 debug_dfa_trav = 0;
607 debug_dfa_tran = 1;
609 dfa_verbose = 1;
610#endif
611
612 lineBuf = wrbuf_alloc();
613 spec->lineNo = 0;
614 c = getc (spec_inf);
615 while (c != EOF)
616 {
617 wrbuf_rewind (lineBuf);
618 if (c == '#' || c == '\n' || c == ' ' || c == '\t' || c == '\r')
619 {
620 while (c != '\n' && c != EOF)
621 c = getc (spec_inf);
622 spec->lineNo++;
623 if (c == '\n')
624 c = getc (spec_inf);
625 }
626 else
627 {
628 int addLine = 0;
629
630 while (1)
631 {
632 int c1 = c;
633 wrbuf_putc(lineBuf, c);
634 c = getc (spec_inf);
635 while (c == '\r')
636 c = getc (spec_inf);
637 if (c == EOF)
638 break;
639 if (c1 == '\n')
640 {
641 if (c != ' ' && c != '\t')
642 break;
643 addLine++;
644 }
645 }
646 wrbuf_putc(lineBuf, '\0');
647 readOneSpec (spec, wrbuf_buf(lineBuf));
648 spec->lineNo += addLine;
649 }
650 }
651 fclose (spec_inf);
652 wrbuf_destroy(lineBuf);
653
654 for (lc = spec->context; lc; lc = lc->next)
655 {
656 struct lexRule *rp;
657 lc->fastRule = (struct lexRuleInfo **)
658 xmalloc (sizeof(*lc->fastRule) * lc->ruleNo);
659 for (i = 0; i < lc->ruleNo; i++)
660 lc->fastRule[i] = NULL;
661 for (rp = lc->rules; rp; rp = rp->next)
662 lc->fastRule[rp->info.no] = &rp->info;
663 dfa_mkstate (lc->dfa);
664 }
665 if (errors)
666 return -1;
667
668 return 0;
669}
670
671#if 0
672static struct lexSpec *curLexSpec = NULL;
673#endif
674
675static void execData (struct lexSpec *spec,
676 const char *ebuf, int elen, int formatted_text,
677 const char *attribute_str, int attribute_len)
678{
679 struct data1_node *res, *parent;
680 int org_len;
681
682 if (elen == 0) /* shouldn't happen, but it does! */
683 return ;
684#if REGX_DEBUG
685 if (elen > 80)
686 yaz_log (YLOG_LOG, "data(%d bytes) %.40s ... %.*s", elen,
687 ebuf, 40, ebuf + elen-40);
688 else if (elen == 1 && ebuf[0] == '\n')
689 {
690 yaz_log (YLOG_LOG, "data(new line)");
691 }
692 else if (elen > 0)
693 yaz_log (YLOG_LOG, "data(%d bytes) %.*s", elen, elen, ebuf);
694 else
695 yaz_log (YLOG_LOG, "data(%d bytes)", elen);
696#endif
697
698 if (spec->d1_level <= 1)
699 return;
700
701 parent = spec->d1_stack[spec->d1_level -1];
702 assert (parent);
703
704 if (attribute_str)
705 {
706 data1_xattr **ap;
707 res = parent;
708 if (res->which != DATA1N_tag)
709 return;
710 /* sweep through exising attributes.. */
711 for (ap = &res->u.tag.attributes; *ap; ap = &(*ap)->next)
712 if (strlen((*ap)->name) == attribute_len &&
713 !memcmp((*ap)->name, attribute_str, attribute_len))
714 break;
715 if (!*ap)
716 {
717 /* new attribute. Create it with name + value */
718 *ap = nmem_malloc(spec->m, sizeof(**ap));
719
720 (*ap)->name = nmem_malloc(spec->m, attribute_len+1);
721 memcpy((*ap)->name, attribute_str, attribute_len);
722 (*ap)->name[attribute_len] = '\0';
723
724 (*ap)->value = nmem_malloc(spec->m, elen+1);
725 memcpy((*ap)->value, ebuf, elen);
726 (*ap)->value[elen] = '\0';
727 (*ap)->next = 0;
728 }
729 else
730 {
731 /* append to value if attribute already exists */
732 char *nv = nmem_malloc(spec->m, elen + 1 + strlen((*ap)->value));
733 strcpy(nv, (*ap)->value);
734 memcpy (nv + strlen(nv), ebuf, elen);
735 nv[strlen(nv)+elen] = '\0';
736 (*ap)->value = nv;
737 }
738 }
739 else
740 {
741 if ((res = spec->d1_stack[spec->d1_level]) &&
742 res->which == DATA1N_data)
743 org_len = res->u.data.len;
744 else
745 {
746 org_len = 0;
747
748 res = data1_mk_node2 (spec->dh, spec->m, DATA1N_data, parent);
749 res->u.data.what = DATA1I_text;
750 res->u.data.len = 0;
751 res->u.data.formatted_text = formatted_text;
752 res->u.data.data = 0;
753
754 if (spec->d1_stack[spec->d1_level])
755 spec->d1_stack[spec->d1_level]->next = res;
756 spec->d1_stack[spec->d1_level] = res;
757 }
758 if (org_len + elen >= spec->concatBuf[spec->d1_level].max)
759 {
760 char *old_buf, *new_buf;
761
762 spec->concatBuf[spec->d1_level].max = org_len + elen + 256;
763 new_buf = (char *) xmalloc (spec->concatBuf[spec->d1_level].max);
764 if ((old_buf = spec->concatBuf[spec->d1_level].buf))
765 {
766 memcpy (new_buf, old_buf, org_len);
767 xfree (old_buf);
768 }
769 spec->concatBuf[spec->d1_level].buf = new_buf;
770 }
771 memcpy (spec->concatBuf[spec->d1_level].buf + org_len, ebuf, elen);
772 res->u.data.len += elen;
773 }
774}
775
776static void execDataP (struct lexSpec *spec,
777 const char *ebuf, int elen, int formatted_text)
778{
779 execData (spec, ebuf, elen, formatted_text, 0, 0);
780}
781
782static void tagDataRelease (struct lexSpec *spec)
783{
784 data1_node *res;
785
786 if ((res = spec->d1_stack[spec->d1_level]) &&
787 res->which == DATA1N_data &&
788 res->u.data.what == DATA1I_text)
789 {
790 assert (!res->u.data.data);
791 assert (res->u.data.len > 0);
792 if (res->u.data.len > DATA1_LOCALDATA)
793 res->u.data.data = (char *) nmem_malloc (spec->m, res->u.data.len);
794 else
795 res->u.data.data = res->lbuf;
796 memcpy (res->u.data.data, spec->concatBuf[spec->d1_level].buf,
797 res->u.data.len);
798 }
799}
800
801static void variantBegin (struct lexSpec *spec,
802 const char *class_str, int class_len,
803 const char *type_str, int type_len,
804 const char *value_str, int value_len)
805{
806 struct data1_node *parent = spec->d1_stack[spec->d1_level -1];
807 char tclass[DATA1_MAX_SYMBOL], ttype[DATA1_MAX_SYMBOL];
808 data1_vartype *tp;
809 int i;
810 data1_node *res;
811
812 if (spec->d1_level == 0)
813 {
814 yaz_log (YLOG_WARN, "in variant begin. No record type defined");
815 return ;
816 }
817 if (class_len >= DATA1_MAX_SYMBOL)
818 class_len = DATA1_MAX_SYMBOL-1;
819 memcpy (tclass, class_str, class_len);
820 tclass[class_len] = '\0';
821
822 if (type_len >= DATA1_MAX_SYMBOL)
823 type_len = DATA1_MAX_SYMBOL-1;
824 memcpy (ttype, type_str, type_len);
825 ttype[type_len] = '\0';
826
827#if REGX_DEBUG
828 yaz_log (YLOG_LOG, "variant begin(%s,%s,%d)", tclass, ttype,
829 spec->d1_level);
830#endif
831
832 if (!(tp =
834 tclass, ttype)))
835 return;
836
838 {
839 res = data1_mk_node2 (spec->dh, spec->m, DATA1N_variant, parent);
840 if (spec->d1_stack[spec->d1_level])
841 tagDataRelease (spec);
842 spec->d1_stack[spec->d1_level] = res;
843 spec->d1_stack[++(spec->d1_level)] = NULL;
844 }
845 for (i = spec->d1_level-1; spec->d1_stack[i]->which == DATA1N_variant; i--)
846 if (spec->d1_stack[i]->u.variant.type == tp)
847 {
848 spec->d1_level = i;
849 break;
850 }
851
852#if REGX_DEBUG
853 yaz_log (YLOG_LOG, "variant node(%d)", spec->d1_level);
854#endif
855 parent = spec->d1_stack[spec->d1_level-1];
856 res = data1_mk_node2 (spec->dh, spec->m, DATA1N_variant, parent);
857 res->u.variant.type = tp;
858
859 if (value_len >= DATA1_LOCALDATA)
860 value_len =DATA1_LOCALDATA-1;
861 memcpy (res->lbuf, value_str, value_len);
862 res->lbuf[value_len] = '\0';
863
864 res->u.variant.value = res->lbuf;
865
866 if (spec->d1_stack[spec->d1_level])
867 tagDataRelease (spec);
868 spec->d1_stack[spec->d1_level] = res;
869 spec->d1_stack[++(spec->d1_level)] = NULL;
870}
871
872static void tagStrip (const char **tag, int *len)
873{
874 int i;
875
876 for (i = *len; i > 0 && isspace((*tag)[i-1]); --i)
877 ;
878 *len = i;
879 for (i = 0; i < *len && isspace((*tag)[i]); i++)
880 ;
881 *tag += i;
882 *len -= i;
883}
884
885static void tagBegin (struct lexSpec *spec,
886 const char *tag, int len)
887{
888 if (spec->d1_level == 0)
889 {
890 yaz_log (YLOG_WARN, "in element begin. No record type defined");
891 return ;
892 }
893 tagStrip (&tag, &len);
894 if (spec->d1_stack[spec->d1_level])
895 tagDataRelease (spec);
896
897#if REGX_DEBUG
898 yaz_log (YLOG_LOG, "begin tag(%.*s, %d)", len, tag, spec->d1_level);
899#endif
900
901 spec->d1_stack[spec->d1_level] = data1_mk_tag_n (
902 spec->dh, spec->m, tag, len, 0, spec->d1_stack[spec->d1_level -1]);
903 spec->d1_stack[++(spec->d1_level)] = NULL;
904}
905
906static void tagEnd (struct lexSpec *spec, int min_level,
907 const char *tag, int len)
908{
909 tagStrip (&tag, &len);
910 while (spec->d1_level > min_level)
911 {
912 tagDataRelease (spec);
913 (spec->d1_level)--;
914 if (spec->d1_level == 0)
915 break;
916 if ((spec->d1_stack[spec->d1_level]->which == DATA1N_tag) &&
917 (!tag ||
918 (strlen(spec->d1_stack[spec->d1_level]->u.tag.tag) ==
919 (size_t) len &&
920 !memcmp (spec->d1_stack[spec->d1_level]->u.tag.tag, tag, len))))
921 break;
922 }
923#if REGX_DEBUG
924 yaz_log (YLOG_LOG, "end tag(%d)", spec->d1_level);
925#endif
926}
927
928
929static int tryMatch (struct lexSpec *spec, int *pptr, int *mptr,
930 struct DFA *dfa, int greedy)
931{
932 struct DFA_state *state = dfa->states[0];
933 struct DFA_tran *t;
934 unsigned char c = 0;
935 unsigned char c_prev = 0;
936 int ptr = *pptr; /* current pointer */
937 int start_ptr = *pptr; /* first char of match */
938 int last_ptr = 0; /* last char of match */
939 int last_rule = 0; /* rule number of current match */
940 int restore_ptr = 0;
941 int i;
942
943 if (ptr)
944 {
945 --ptr;
946 c = f_win_advance (spec, &ptr);
947 }
948 while (1)
949 {
950 if (dfa->states[0] == state)
951 {
952 c_prev = c;
953 restore_ptr = ptr;
954 }
955 c = f_win_advance (spec, &ptr);
956
957 if (ptr == F_WIN_EOF)
958 {
959 if (last_rule)
960 {
961 *mptr = start_ptr;
962 *pptr = last_ptr;
963 return 1;
964 }
965 break;
966 }
967
968 t = state->trans;
969 i = state->tran_no;
970 while (1)
971 if (--i < 0) /* no transition for character c */
972 {
973 if (last_rule)
974 {
975 *mptr = start_ptr; /* match starts here */
976 *pptr = last_ptr; /* match end here (+1) */
977 return 1;
978 }
979 state = dfa->states[0];
980
981 ptr = restore_ptr;
982 c = f_win_advance (spec, &ptr);
983
984 start_ptr = ptr;
985
986 break;
987 }
988 else if (c >= t->ch[0] && c <= t->ch[1])
989 {
990 state = dfa->states[t->to];
991 if (state->rule_no && c_prev == '\n')
992 {
993 last_rule = state->rule_no;
994 last_ptr = ptr;
995 }
996 else if (state->rule_nno)
997 {
998 last_rule = state->rule_nno;
999 last_ptr = ptr;
1000 }
1001 break;
1002 }
1003 else
1004 t++;
1005 }
1006 return 0;
1007}
1008
1009static int execTok (struct lexSpec *spec, const char **src,
1010 const char **tokBuf, int *tokLen)
1011{
1012 const char *s = *src;
1013
1014 while (*s == ' ' || *s == '\t')
1015 s++;
1016 if (!*s)
1017 return 0;
1018 if (*s == '$' && s[1] >= '0' && s[1] <= '9')
1019 {
1020 int n = 0;
1021 s++;
1022 while (*s >= '0' && *s <= '9')
1023 n = n*10 + (*s++ -'0');
1024 if (spec->arg_no == 0)
1025 {
1026 *tokBuf = "";
1027 *tokLen = 0;
1028 }
1029 else
1030 {
1031 if (n >= spec->arg_no)
1032 n = spec->arg_no-1;
1033 *tokBuf = f_win_get (spec, spec->arg_start[n], spec->arg_end[n],
1034 tokLen);
1035 }
1036 }
1037 else if (*s == '\"')
1038 {
1039 *tokBuf = ++s;
1040 while (*s && *s != '\"')
1041 s++;
1042 *tokLen = s - *tokBuf;
1043 if (*s)
1044 s++;
1045 *src = s;
1046 }
1047 else if (*s == '\n' || *s == ';')
1048 {
1049 *src = s+1;
1050 return 1;
1051 }
1052 else if (*s == '-')
1053 {
1054 *tokBuf = s++;
1055 while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' &&
1056 *s != ';')
1057 s++;
1058 *tokLen = s - *tokBuf;
1059 *src = s;
1060 return 3;
1061 }
1062 else
1063 {
1064 *tokBuf = s++;
1065 while (*s && *s != ' ' && *s != '\t' && *s != '\n' && *s != '\r' &&
1066 *s != ';')
1067 s++;
1068 *tokLen = s - *tokBuf;
1069 }
1070 *src = s;
1071 return 2;
1072}
1073
1074static char *regxStrz (const char *src, int len, char *str)
1075{
1076 if (len > 63)
1077 len = 63;
1078 memcpy (str, src, len);
1079 str[len] = '\0';
1080 return str;
1081}
1082
1083#if HAVE_TCL_H
1084static int cmd_tcl_begin (ClientData clientData, Tcl_Interp *interp,
1085 int argc, const char **argv)
1086{
1087 struct lexSpec *spec = (struct lexSpec *) clientData;
1088 if (argc < 2)
1089 return TCL_ERROR;
1090 if (!strcmp(argv[1], "record") && argc == 3)
1091 {
1092 const char *absynName = argv[2];
1093 data1_node *res;
1094
1095#if REGX_DEBUG
1096 yaz_log (YLOG_LOG, "begin record %s", absynName);
1097#endif
1098 res = data1_mk_root (spec->dh, spec->m, absynName);
1099
1100 spec->d1_level = 0;
1101
1102 spec->d1_stack[spec->d1_level++] = res;
1103
1104 res = data1_mk_tag (spec->dh, spec->m, absynName, 0, res);
1105
1106 spec->d1_stack[spec->d1_level++] = res;
1107
1108 spec->d1_stack[spec->d1_level] = NULL;
1109 }
1110 else if (!strcmp(argv[1], "element") && argc == 3)
1111 {
1112 tagBegin (spec, argv[2], strlen(argv[2]));
1113 }
1114 else if (!strcmp (argv[1], "variant") && argc == 5)
1115 {
1116 variantBegin (spec, argv[2], strlen(argv[2]),
1117 argv[3], strlen(argv[3]),
1118 argv[4], strlen(argv[4]));
1119 }
1120 else if (!strcmp (argv[1], "context") && argc == 3)
1121 {
1122 struct lexContext *lc = spec->context;
1123#if REGX_DEBUG
1124 yaz_log (YLOG_LOG, "begin context %s",argv[2]);
1125#endif
1126 while (lc && strcmp (argv[2], lc->name))
1127 lc = lc->next;
1128 if (lc)
1129 {
1130 spec->context_stack[++(spec->context_stack_top)] = lc;
1131 }
1132 else
1133 yaz_log (YLOG_WARN, "unknown context %s", argv[2]);
1134 }
1135 else
1136 return TCL_ERROR;
1137 return TCL_OK;
1138}
1139
1140static int cmd_tcl_end (ClientData clientData, Tcl_Interp *interp,
1141 int argc, const char **argv)
1142{
1143 struct lexSpec *spec = (struct lexSpec *) clientData;
1144 if (argc < 2)
1145 return TCL_ERROR;
1146
1147 if (!strcmp (argv[1], "record"))
1148 {
1149 while (spec->d1_level)
1150 {
1151 tagDataRelease (spec);
1152 (spec->d1_level)--;
1153 }
1154#if REGX_DEBUG
1155 yaz_log (YLOG_LOG, "end record");
1156#endif
1157 spec->stop_flag = 1;
1158 }
1159 else if (!strcmp (argv[1], "element"))
1160 {
1161 int min_level = 2;
1162 const char *element = 0;
1163 if (argc >= 3 && !strcmp(argv[2], "-record"))
1164 {
1165 min_level = 0;
1166 if (argc == 4)
1167 element = argv[3];
1168 }
1169 else
1170 if (argc == 3)
1171 element = argv[2];
1172 tagEnd (spec, min_level, element, (element ? strlen(element) : 0));
1173 if (spec->d1_level <= 1)
1174 {
1175#if REGX_DEBUG
1176 yaz_log (YLOG_LOG, "end element end records");
1177#endif
1178 spec->stop_flag = 1;
1179 }
1180 }
1181 else if (!strcmp (argv[1], "context"))
1182 {
1183#if REGX_DEBUG
1184 yaz_log (YLOG_LOG, "end context");
1185#endif
1186 if (spec->context_stack_top)
1187 (spec->context_stack_top)--;
1188 }
1189 else
1190 return TCL_ERROR;
1191 return TCL_OK;
1192}
1193
1194static int cmd_tcl_data (ClientData clientData, Tcl_Interp *interp,
1195 int argc, const char **argv)
1196{
1197 int argi = 1;
1198 int textFlag = 0;
1199 const char *element = 0;
1200 const char *attribute = 0;
1201 struct lexSpec *spec = (struct lexSpec *) clientData;
1202
1203 while (argi < argc)
1204 {
1205 if (!strcmp("-text", argv[argi]))
1206 {
1207 textFlag = 1;
1208 argi++;
1209 }
1210 else if (!strcmp("-element", argv[argi]))
1211 {
1212 argi++;
1213 if (argi < argc)
1214 element = argv[argi++];
1215 }
1216 else if (!strcmp("-attribute", argv[argi]))
1217 {
1218 argi++;
1219 if (argi < argc)
1220 attribute = argv[argi++];
1221 }
1222 else
1223 break;
1224 }
1225 if (element)
1226 tagBegin (spec, element, strlen(element));
1227
1228 while (argi < argc)
1229 {
1230#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0)
1231 Tcl_DString ds;
1232 char *native = Tcl_UtfToExternalDString(0, argv[argi], -1, &ds);
1233 execData (spec, native, strlen(native), textFlag, attribute,
1234 attribute ? strlen(attribute) : 0);
1235 Tcl_DStringFree (&ds);
1236#else
1237 execData (spec, argv[argi], strlen(argv[argi]), textFlag, attribute,
1238 attribute ? strlen(attribute) : 0);
1239#endif
1240 argi++;
1241 }
1242 if (element)
1243 tagEnd (spec, 2, NULL, 0);
1244 return TCL_OK;
1245}
1246
1247static int cmd_tcl_unread (ClientData clientData, Tcl_Interp *interp,
1248 int argc, const char **argv)
1249{
1250 struct lexSpec *spec = (struct lexSpec *) clientData;
1251 int argi = 1;
1252 int offset = 0;
1253 int no;
1254
1255 while (argi < argc)
1256 {
1257 if (!strcmp("-offset", argv[argi]))
1258 {
1259 argi++;
1260 if (argi < argc)
1261 {
1262 offset = atoi(argv[argi]);
1263 argi++;
1264 }
1265 }
1266 else
1267 break;
1268 }
1269 if (argi != argc-1)
1270 return TCL_ERROR;
1271 no = atoi(argv[argi]);
1272 if (no >= spec->arg_no)
1273 no = spec->arg_no - 1;
1274 spec->ptr = spec->arg_start[no] + offset;
1275 return TCL_OK;
1276}
1277
1278static void execTcl (struct lexSpec *spec, struct regxCode *code)
1279{
1280 int i;
1281 int ret;
1282 for (i = 0; i < spec->arg_no; i++)
1283 {
1284 char var_name[10], *var_buf;
1285 int var_len, ch;
1286
1287 yaz_snprintf(var_name, sizeof(var_name), "%d", i);
1288 var_buf = f_win_get(spec, spec->arg_start[i], spec->arg_end[i],
1289 &var_len);
1290 if (var_buf)
1291 {
1292 ch = var_buf[var_len];
1293 var_buf[var_len] = '\0';
1294 Tcl_SetVar (spec->tcl_interp, var_name, var_buf, 0);
1295 var_buf[var_len] = ch;
1296 }
1297 }
1298#if HAVE_TCL_OBJECTS
1299 ret = Tcl_GlobalEvalObj(spec->tcl_interp, code->tcl_obj);
1300#else
1301 ret = Tcl_GlobalEval (spec->tcl_interp, code->str);
1302#endif
1303 if (ret != TCL_OK)
1304 {
1305 const char *err = Tcl_GetVar(spec->tcl_interp, "errorInfo", 0);
1306 yaz_log(YLOG_FATAL, "Tcl error, line=%d, \"%s\"\n%s",
1307#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 5
1308 spec->tcl_interp->errorLine,
1309 spec->tcl_interp->result,
1310#else
1311 Tcl_GetErrorLine(spec->tcl_interp),
1312 Tcl_GetStringResult(spec->tcl_interp),
1313#endif
1314 err ? err : "[NO ERRORINFO]");
1315 }
1316}
1317/* HAVE_TCL_H */
1318#endif
1319
1320static void execCode (struct lexSpec *spec, struct regxCode *code)
1321{
1322 const char *s = code->str;
1323 int cmd_len, r;
1324 const char *cmd_str;
1325
1326 r = execTok (spec, &s, &cmd_str, &cmd_len);
1327 while (r)
1328 {
1329 char *p, ptmp[64];
1330
1331 if (r == 1)
1332 {
1333 r = execTok (spec, &s, &cmd_str, &cmd_len);
1334 continue;
1335 }
1336 p = regxStrz (cmd_str, cmd_len, ptmp);
1337 if (!strcmp (p, "begin"))
1338 {
1339 r = execTok (spec, &s, &cmd_str, &cmd_len);
1340 if (r < 2)
1341 {
1342 yaz_log (YLOG_WARN, "missing keyword after 'begin'");
1343 continue;
1344 }
1345 p = regxStrz (cmd_str, cmd_len, ptmp);
1346 if (!strcmp (p, "record"))
1347 {
1348 r = execTok (spec, &s, &cmd_str, &cmd_len);
1349 if (r < 2)
1350 continue;
1351 if (spec->d1_level <= 1)
1352 {
1353 static char absynName[64];
1354 data1_node *res;
1355
1356 if (cmd_len > 63)
1357 cmd_len = 63;
1358 memcpy (absynName, cmd_str, cmd_len);
1359 absynName[cmd_len] = '\0';
1360#if REGX_DEBUG
1361 yaz_log (YLOG_LOG, "begin record %s", absynName);
1362#endif
1363 res = data1_mk_root (spec->dh, spec->m, absynName);
1364
1365 spec->d1_level = 0;
1366
1367 spec->d1_stack[spec->d1_level++] = res;
1368
1369 res = data1_mk_tag (spec->dh, spec->m, absynName, 0, res);
1370
1371 spec->d1_stack[spec->d1_level++] = res;
1372
1373 spec->d1_stack[spec->d1_level] = NULL;
1374 }
1375 r = execTok (spec, &s, &cmd_str, &cmd_len);
1376 }
1377 else if (!strcmp (p, "element"))
1378 {
1379 r = execTok (spec, &s, &cmd_str, &cmd_len);
1380 if (r < 2)
1381 continue;
1382 tagBegin (spec, cmd_str, cmd_len);
1383 r = execTok (spec, &s, &cmd_str, &cmd_len);
1384 }
1385 else if (!strcmp (p, "variant"))
1386 {
1387 int class_len;
1388 const char *class_str = NULL;
1389 int type_len;
1390 const char *type_str = NULL;
1391 int value_len;
1392 const char *value_str = NULL;
1393 r = execTok (spec, &s, &cmd_str, &cmd_len);
1394 if (r < 2)
1395 continue;
1396 class_str = cmd_str;
1397 class_len = cmd_len;
1398 r = execTok (spec, &s, &cmd_str, &cmd_len);
1399 if (r < 2)
1400 continue;
1401 type_str = cmd_str;
1402 type_len = cmd_len;
1403
1404 r = execTok (spec, &s, &cmd_str, &cmd_len);
1405 if (r < 2)
1406 continue;
1407 value_str = cmd_str;
1408 value_len = cmd_len;
1409
1410 variantBegin (spec, class_str, class_len,
1411 type_str, type_len, value_str, value_len);
1412
1413
1414 r = execTok (spec, &s, &cmd_str, &cmd_len);
1415 }
1416 else if (!strcmp (p, "context"))
1417 {
1418 if (r > 1)
1419 {
1420 struct lexContext *lc = spec->context;
1421 r = execTok (spec, &s, &cmd_str, &cmd_len);
1422 p = regxStrz (cmd_str, cmd_len, ptmp);
1423#if REGX_DEBUG
1424 yaz_log (YLOG_LOG, "begin context %s", p);
1425#endif
1426 while (lc && strcmp (p, lc->name))
1427 lc = lc->next;
1428 if (lc)
1429 spec->context_stack[++(spec->context_stack_top)] = lc;
1430 else
1431 yaz_log (YLOG_WARN, "unknown context %s", p);
1432
1433 }
1434 r = execTok (spec, &s, &cmd_str, &cmd_len);
1435 }
1436 else
1437 {
1438 yaz_log (YLOG_WARN, "bad keyword '%s' after begin", p);
1439 }
1440 }
1441 else if (!strcmp (p, "end"))
1442 {
1443 r = execTok (spec, &s, &cmd_str, &cmd_len);
1444 if (r < 2)
1445 {
1446 yaz_log (YLOG_WARN, "missing keyword after 'end'");
1447 continue;
1448 }
1449 p = regxStrz (cmd_str, cmd_len, ptmp);
1450 if (!strcmp (p, "record"))
1451 {
1452 while (spec->d1_level)
1453 {
1454 tagDataRelease (spec);
1455 (spec->d1_level)--;
1456 }
1457 r = execTok (spec, &s, &cmd_str, &cmd_len);
1458#if REGX_DEBUG
1459 yaz_log (YLOG_LOG, "end record");
1460#endif
1461 spec->stop_flag = 1;
1462 }
1463 else if (!strcmp (p, "element"))
1464 {
1465 int min_level = 2;
1466 while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1467 {
1468 if (cmd_len==7 && !memcmp ("-record", cmd_str, cmd_len))
1469 min_level = 0;
1470 }
1471 if (r > 2)
1472 {
1473 tagEnd (spec, min_level, cmd_str, cmd_len);
1474 r = execTok (spec, &s, &cmd_str, &cmd_len);
1475 }
1476 else
1477 tagEnd (spec, min_level, NULL, 0);
1478 if (spec->d1_level <= 1)
1479 {
1480#if REGX_DEBUG
1481 yaz_log (YLOG_LOG, "end element end records");
1482#endif
1483 spec->stop_flag = 1;
1484 }
1485
1486 }
1487 else if (!strcmp (p, "context"))
1488 {
1489#if REGX_DEBUG
1490 yaz_log (YLOG_LOG, "end context");
1491#endif
1492 if (spec->context_stack_top)
1493 (spec->context_stack_top)--;
1494 r = execTok (spec, &s, &cmd_str, &cmd_len);
1495 }
1496 else
1497 yaz_log (YLOG_WARN, "bad keyword '%s' after end", p);
1498 }
1499 else if (!strcmp (p, "data"))
1500 {
1501 int textFlag = 0;
1502 int element_len;
1503 const char *element_str = NULL;
1504 int attribute_len;
1505 const char *attribute_str = NULL;
1506
1507 while ((r = execTok (spec, &s, &cmd_str, &cmd_len)) == 3)
1508 {
1509 if (cmd_len==5 && !memcmp ("-text", cmd_str, cmd_len))
1510 textFlag = 1;
1511 else if (cmd_len==8 && !memcmp ("-element", cmd_str, cmd_len))
1512 {
1513 r = execTok (spec, &s, &element_str, &element_len);
1514 if (r < 2)
1515 break;
1516 }
1517 else if (cmd_len==10 && !memcmp ("-attribute", cmd_str,
1518 cmd_len))
1519 {
1520 r = execTok (spec, &s, &attribute_str, &attribute_len);
1521 if (r < 2)
1522 break;
1523 }
1524 else
1525 yaz_log (YLOG_WARN, "bad data option: %.*s",
1526 cmd_len, cmd_str);
1527 }
1528 if (r != 2)
1529 {
1530 yaz_log (YLOG_WARN, "missing data item after data");
1531 continue;
1532 }
1533 if (element_str)
1534 tagBegin (spec, element_str, element_len);
1535 do
1536 {
1537 execData (spec, cmd_str, cmd_len, textFlag,
1538 attribute_str, attribute_len);
1539 r = execTok (spec, &s, &cmd_str, &cmd_len);
1540 } while (r > 1);
1541 if (element_str)
1542 tagEnd (spec, 2, NULL, 0);
1543 }
1544 else if (!strcmp (p, "unread"))
1545 {
1546 int no, offset;
1547 r = execTok (spec, &s, &cmd_str, &cmd_len);
1548 if (r==3 && cmd_len == 7 && !memcmp ("-offset", cmd_str, cmd_len))
1549 {
1550 r = execTok (spec, &s, &cmd_str, &cmd_len);
1551 if (r < 2)
1552 {
1553 yaz_log (YLOG_WARN, "missing number after -offset");
1554 continue;
1555 }
1556 p = regxStrz (cmd_str, cmd_len, ptmp);
1557 offset = atoi (p);
1558 r = execTok (spec, &s, &cmd_str, &cmd_len);
1559 }
1560 else
1561 offset = 0;
1562 if (r < 2)
1563 {
1564 yaz_log (YLOG_WARN, "missing index after unread command");
1565 continue;
1566 }
1567 if (cmd_len != 1 || *cmd_str < '0' || *cmd_str > '9')
1568 {
1569 yaz_log (YLOG_WARN, "bad index after unread command");
1570 continue;
1571 }
1572 else
1573 {
1574 no = *cmd_str - '0';
1575 if (no >= spec->arg_no)
1576 no = spec->arg_no - 1;
1577 spec->ptr = spec->arg_start[no] + offset;
1578 }
1579 r = execTok (spec, &s, &cmd_str, &cmd_len);
1580 }
1581 else if (!strcmp (p, "context"))
1582 {
1583 if (r > 1)
1584 {
1585 struct lexContext *lc = spec->context;
1586 r = execTok (spec, &s, &cmd_str, &cmd_len);
1587 p = regxStrz (cmd_str, cmd_len, ptmp);
1588
1589 while (lc && strcmp (p, lc->name))
1590 lc = lc->next;
1591 if (lc)
1592 spec->context_stack[spec->context_stack_top] = lc;
1593 else
1594 yaz_log (YLOG_WARN, "unknown context %s", p);
1595
1596 }
1597 r = execTok (spec, &s, &cmd_str, &cmd_len);
1598 }
1599 else
1600 {
1601 yaz_log (YLOG_WARN, "unknown code command '%.*s'", cmd_len, cmd_str);
1602 r = execTok (spec, &s, &cmd_str, &cmd_len);
1603 continue;
1604 }
1605 if (r > 1)
1606 {
1607 yaz_log (YLOG_WARN, "ignoring token %.*s", cmd_len, cmd_str);
1608 do {
1609 r = execTok (spec, &s, &cmd_str, &cmd_len);
1610 } while (r > 1);
1611 }
1612 }
1613}
1614
1615
1616static int execAction (struct lexSpec *spec, struct lexRuleAction *ap,
1617 int start_ptr, int *pptr)
1618{
1619 int sptr;
1620 int arg_no = 1;
1621
1622 if (!ap)
1623 return 1;
1624 spec->arg_start[0] = start_ptr;
1625 spec->arg_end[0] = *pptr;
1626
1627 while (ap && arg_no < REGX_MAX_ARGS)
1628 {
1629 switch (ap->which)
1630 {
1631 case REGX_PATTERN:
1632 if (ap->u.pattern.body)
1633 {
1634 spec->arg_start[arg_no] = *pptr;
1635 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa, 0))
1636 {
1637 spec->arg_end[arg_no] = F_WIN_EOF;
1638 arg_no++;
1639 spec->arg_start[arg_no] = F_WIN_EOF;
1640 spec->arg_end[arg_no] = F_WIN_EOF;
1641 yaz_log(YLOG_DEBUG, "Pattern match rest of record");
1642 *pptr = F_WIN_EOF;
1643 }
1644 else
1645 {
1646 spec->arg_end[arg_no] = sptr;
1647 arg_no++;
1648 spec->arg_start[arg_no] = sptr;
1649 spec->arg_end[arg_no] = *pptr;
1650 }
1651 }
1652 else
1653 {
1654 spec->arg_start[arg_no] = *pptr;
1655 if (!tryMatch (spec, pptr, &sptr, ap->u.pattern.dfa, 1))
1656 return 1;
1657 if (sptr != spec->arg_start[arg_no])
1658 return 1;
1659 spec->arg_end[arg_no] = *pptr;
1660 }
1661 arg_no++;
1662 break;
1663 case REGX_CODE:
1664 spec->arg_no = arg_no;
1665 spec->ptr = *pptr;
1666#if HAVE_TCL_H
1667 if (spec->tcl_interp)
1668 execTcl(spec, ap->u.code);
1669 else
1670 execCode (spec, ap->u.code);
1671#else
1672 execCode (spec, ap->u.code);
1673#endif
1674 *pptr = spec->ptr;
1675 if (spec->stop_flag)
1676 return 0;
1677 break;
1678 case REGX_END:
1679 spec->arg_start[arg_no] = *pptr;
1680 spec->arg_end[arg_no] = F_WIN_EOF;
1681 arg_no++;
1682 *pptr = F_WIN_EOF;
1683 }
1684 ap = ap->next;
1685 }
1686 return 1;
1687}
1688
1689static int execRule (struct lexSpec *spec, struct lexContext *context,
1690 int ruleNo, int start_ptr, int *pptr)
1691{
1692#if REGX_DEBUG
1693 yaz_log (YLOG_LOG, "exec rule %d", ruleNo);
1694#endif
1695 return execAction (spec, context->fastRule[ruleNo]->actionList,
1696 start_ptr, pptr);
1697}
1698
1699int lexNode (struct lexSpec *spec, int *ptr)
1700{
1701 struct lexContext *context = spec->context_stack[spec->context_stack_top];
1702 struct DFA_state *state = context->dfa->states[0];
1703 struct DFA_tran *t;
1704 unsigned char c;
1705 unsigned char c_prev = '\n';
1706 int i;
1707 int last_rule = 0; /* rule number of current match */
1708 int last_ptr = *ptr; /* last char of match */
1709 int start_ptr = *ptr; /* first char of match */
1710 int skip_ptr = *ptr; /* first char of run */
1711 int more = 0;
1712
1713 while (1)
1714 {
1715 c = f_win_advance (spec, ptr);
1716 if (*ptr == F_WIN_EOF)
1717 {
1718 /* end of file met */
1719 if (last_rule)
1720 {
1721 /* there was a match */
1722 if (skip_ptr < start_ptr)
1723 {
1724 /* deal with chars that didn't match */
1725 int size;
1726 char *buf;
1727 buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1728 execDataP (spec, buf, size, 0);
1729 }
1730 /* restore pointer */
1731 *ptr = last_ptr;
1732 /* execute rule */
1733 if (!execRule (spec, context, last_rule, start_ptr, ptr))
1734 return more;
1735 /* restore skip pointer */
1736 skip_ptr = *ptr;
1737 last_rule = 0;
1738 }
1739 else if (skip_ptr < *ptr)
1740 {
1741 /* deal with chars that didn't match */
1742 int size;
1743 char *buf;
1744 buf = f_win_get (spec, skip_ptr, *ptr, &size);
1745 execDataP (spec, buf, size, 0);
1746 }
1747 state = context->dfa->states[0];
1748 if (*ptr == F_WIN_EOF)
1749 return more;
1750 }
1751 t = state->trans;
1752 i = state->tran_no;
1753 while (1)
1754 if (--i < 0)
1755 { /* no transition for character c ... */
1756 if (last_rule)
1757 {
1758 if (skip_ptr < start_ptr)
1759 {
1760 /* deal with chars that didn't match */
1761 int size;
1762 char *buf;
1763 buf = f_win_get (spec, skip_ptr, start_ptr, &size);
1764 execDataP (spec, buf, size, 0);
1765 }
1766 /* restore pointer */
1767 *ptr = last_ptr;
1768 if (!execRule (spec, context, last_rule, start_ptr, ptr))
1769 {
1770 if (spec->f_win_ef && *ptr != F_WIN_EOF)
1771 {
1772 off_t end_offset = *ptr;
1773#if REGX_DEBUG
1774 yaz_log (YLOG_LOG, "regx: endf ptr=%d", *ptr);
1775#endif
1776 (*spec->f_win_ef)(spec->stream, &end_offset);
1777 }
1778 return more;
1779 }
1780 context = spec->context_stack[spec->context_stack_top];
1781 skip_ptr = *ptr;
1782 last_rule = 0;
1783 last_ptr = start_ptr = *ptr;
1784 if (start_ptr > 0)
1785 {
1786 --start_ptr;
1787 c_prev = f_win_advance (spec, &start_ptr);
1788 }
1789 }
1790 else
1791 {
1792 c_prev = f_win_advance (spec, &start_ptr);
1793 *ptr = start_ptr;
1794 }
1795 state = context->dfa->states[0];
1796 break;
1797 }
1798 else if (c >= t->ch[0] && c <= t->ch[1])
1799 { /* transition ... */
1800 state = context->dfa->states[t->to];
1801 if (state->rule_no)
1802 {
1803 if (c_prev == '\n')
1804 {
1805 last_rule = state->rule_no;
1806 last_ptr = *ptr;
1807 }
1808 else if (state->rule_nno)
1809 {
1810 last_rule = state->rule_nno;
1811 last_ptr = *ptr;
1812 }
1813 more = 1;
1814 }
1815 break;
1816 }
1817 else
1818 t++;
1819 }
1820 return more;
1821}
1822
1823static data1_node *lexRoot (struct lexSpec *spec, off_t offset,
1824 const char *context_name)
1825{
1826 struct lexContext *lt = spec->context;
1827 int ptr = offset;
1828 int ret;
1829
1830 spec->stop_flag = 0;
1831 spec->d1_level = 0;
1832 spec->context_stack_top = 0;
1833 while (lt)
1834 {
1835 if (!strcmp (lt->name, context_name))
1836 break;
1837 lt = lt->next;
1838 }
1839 if (!lt)
1840 {
1841 yaz_log (YLOG_WARN, "cannot find context %s", context_name);
1842 return NULL;
1843 }
1844 spec->context_stack[spec->context_stack_top] = lt;
1845 spec->d1_stack[spec->d1_level] = NULL;
1846#if 1
1847 if (!lt->initFlag)
1848 {
1849 lt->initFlag = 1;
1850 execAction (spec, lt->initActionList, ptr, &ptr);
1851 }
1852#endif
1853 execAction (spec, lt->beginActionList, ptr, &ptr);
1854
1855 ret = lexNode (spec, &ptr);
1856 while (spec->d1_level)
1857 {
1858 tagDataRelease (spec);
1859 (spec->d1_level)--;
1860 }
1861 if (!ret)
1862 return 0;
1863 execAction (spec, lt->endActionList, ptr, &ptr);
1864 return spec->d1_stack[0];
1865}
1866
1867void grs_destroy(void *clientData)
1868{
1869 struct lexSpecs *specs = (struct lexSpecs *) clientData;
1870 if (specs->spec)
1871 {
1872 lexSpecDestroy(&specs->spec);
1873 }
1874 xfree (specs);
1875}
1876
1878{
1879 struct lexSpecs *specs = (struct lexSpecs *) xmalloc (sizeof(*specs));
1880 specs->spec = 0;
1881 strcpy(specs->type, "");
1882 return specs;
1883}
1884
1885
1886ZEBRA_RES grs_config(void *clientData, Res res, const char *args)
1887{
1888 struct lexSpecs *specs = (struct lexSpecs *) clientData;
1889 if (strlen(args) < sizeof(specs->type))
1890 strcpy(specs->type, args);
1891 return ZEBRA_OK;
1892}
1893
1895{
1896 int res;
1897 struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1898 struct lexSpec **curLexSpec = &specs->spec;
1899 off_t start_offset;
1900
1901#if REGX_DEBUG
1902 yaz_log (YLOG_LOG, "grs_read_regx");
1903#endif
1904 if (!*curLexSpec || strcmp ((*curLexSpec)->name, specs->type))
1905 {
1906 if (*curLexSpec)
1907 lexSpecDestroy (curLexSpec);
1908 *curLexSpec = lexSpecCreate (specs->type, p->dh);
1909 res = readFileSpec (*curLexSpec);
1910 if (res)
1911 {
1912 lexSpecDestroy (curLexSpec);
1913 return NULL;
1914 }
1915 }
1916 (*curLexSpec)->dh = p->dh;
1917 start_offset = p->stream->tellf(p->stream);
1918 if (start_offset == 0)
1919 {
1920 (*curLexSpec)->f_win_start = 0;
1921 (*curLexSpec)->f_win_end = 0;
1922 (*curLexSpec)->f_win_rf = p->stream->readf;
1923 (*curLexSpec)->f_win_sf = p->stream->seekf;
1924 (*curLexSpec)->stream = p->stream;
1925 (*curLexSpec)->f_win_ef = p->stream->endf;
1926 (*curLexSpec)->f_win_size = 500000;
1927 }
1928 (*curLexSpec)->m = p->mem;
1929 return lexRoot (*curLexSpec, start_offset, "main");
1930}
1931
1932static int extract_regx(void *clientData, struct recExtractCtrl *ctrl)
1933{
1934 return zebra_grs_extract(clientData, ctrl, grs_read_regx);
1935}
1936
1937static int retrieve_regx(void *clientData, struct recRetrieveCtrl *ctrl)
1938{
1939 return zebra_grs_retrieve(clientData, ctrl, grs_read_regx);
1940}
1941
1942static struct recType regx_type = {
1943 0,
1944 "grs.regx",
1945 grs_init,
1946 grs_config,
1950};
1951
1952
1953#if HAVE_TCL_H
1954data1_node *grs_read_tcl (struct grs_read_info *p)
1955{
1956 int res;
1957 struct lexSpecs *specs = (struct lexSpecs *) p->clientData;
1958 struct lexSpec **curLexSpec = &specs->spec;
1959 off_t start_offset;
1960
1961#if REGX_DEBUG
1962 yaz_log (YLOG_LOG, "grs_read_tcl");
1963#endif
1964 if (!*curLexSpec || strcmp ((*curLexSpec)->name, specs->type))
1965 {
1966 Tcl_Interp *tcl_interp;
1967 if (*curLexSpec)
1968 lexSpecDestroy (curLexSpec);
1969 *curLexSpec = lexSpecCreate (specs->type, p->dh);
1970 Tcl_FindExecutable("");
1971 tcl_interp = (*curLexSpec)->tcl_interp = Tcl_CreateInterp();
1972 Tcl_Init(tcl_interp);
1973 Tcl_CreateCommand (tcl_interp, "begin", cmd_tcl_begin, *curLexSpec, 0);
1974 Tcl_CreateCommand (tcl_interp, "end", cmd_tcl_end, *curLexSpec, 0);
1975 Tcl_CreateCommand (tcl_interp, "data", cmd_tcl_data, *curLexSpec, 0);
1976 Tcl_CreateCommand (tcl_interp, "unread", cmd_tcl_unread,
1977 *curLexSpec, 0);
1978 res = readFileSpec (*curLexSpec);
1979 if (res)
1980 {
1981 lexSpecDestroy (curLexSpec);
1982 return NULL;
1983 }
1984 }
1985 (*curLexSpec)->dh = p->dh;
1986 start_offset = p->stream->tellf(p->stream);
1987 if (start_offset == 0)
1988 {
1989 (*curLexSpec)->f_win_start = 0;
1990 (*curLexSpec)->f_win_end = 0;
1991 (*curLexSpec)->f_win_rf = p->stream->readf;
1992 (*curLexSpec)->f_win_sf = p->stream->seekf;
1993 (*curLexSpec)->stream = p->stream;
1994 (*curLexSpec)->f_win_ef = p->stream->endf;
1995 (*curLexSpec)->f_win_size = 500000;
1996 }
1997 (*curLexSpec)->m = p->mem;
1998 return lexRoot (*curLexSpec, start_offset, "main");
1999}
2000
2001static int extract_tcl(void *clientData, struct recExtractCtrl *ctrl)
2002{
2003 return zebra_grs_extract(clientData, ctrl, grs_read_tcl);
2004}
2005
2006static int retrieve_tcl(void *clientData, struct recRetrieveCtrl *ctrl)
2007{
2008 return zebra_grs_retrieve(clientData, ctrl, grs_read_tcl);
2009}
2010
2011static struct recType tcl_type = {
2012 0,
2013 "grs.tcl",
2014 grs_init,
2015 grs_config,
2017 extract_tcl,
2018 retrieve_tcl,
2019};
2020
2021#endif
2022
2023RecType
2024#if IDZEBRA_STATIC_GRS_REGX
2025idzebra_filter_grs_regx
2026#else
2028#endif
2029
2030[] = {
2031 &regx_type,
2032#if HAVE_TCL_H
2033 &tcl_type,
2034#endif
2035 0,
2036};
2037/*
2038 * Local variables:
2039 * c-basic-offset: 4
2040 * c-file-style: "Stroustrup"
2041 * indent-tabs-mode: nil
2042 * End:
2043 * vim: shiftwidth=4 tabstop=8 expandtab
2044 */
2045
#define DATA1N_variant
Definition data1.h:280
data1_node * data1_mk_root(data1_handle dh, NMEM nmem, const char *name)
Definition d1_read.c:174
data1_node * data1_mk_tag_n(data1_handle dh, NMEM nmem, const char *tag, size_t len, const char **attr, data1_node *at)
Definition d1_read.c:259
#define DATA1N_tag
Definition data1.h:276
#define DATA1N_data
Definition data1.h:278
FILE * data1_path_fopen(data1_handle dh, const char *file, const char *mode)
Definition d1_handle.c:147
data1_vartype * data1_getvartypeby_absyn(data1_handle dh, data1_absyn *absyn, char *zclass, char *type)
Definition d1_varset.c:50
data1_node * data1_mk_node2(data1_handle dh, NMEM m, int type, data1_node *parent)
Definition d1_read.c:146
#define DATA1_LOCALDATA
Definition data1.h:338
#define DATA1_MAX_SYMBOL
Definition data1.h:38
data1_node * data1_mk_tag(data1_handle dh, NMEM nmem, const char *tag, const char **attr, data1_node *at)
Definition d1_read.c:295
#define DATA1I_text
Definition data1.h:314
struct data1_handle_info * data1_handle
Definition data1.h:77
void dfa_parse_cmap_add(struct DFA *d, int from, int to)
Definition dfa.c:978
void dfa_parse_cmap_del(struct DFA *d, int from)
Definition dfa.c:960
int dfa_parse(struct DFA *, const char **)
Definition dfa.c:1121
void dfa_mkstate(struct DFA *)
Definition dfa.c:1148
void dfa_delete(struct DFA **)
Definition dfa.c:1158
int debug_dfa_followpos
Definition dfa.c:68
int debug_dfa_trav
Definition dfa.c:66
struct DFA * dfa_init(void)
Definition dfa.c:1092
int dfa_verbose
Definition dfa.c:69
int debug_dfa_tran
Definition dfa.c:67
RecType idzebra_filter[]
Definition mod_alvis.c:723
static void tagEnd(struct lexSpec *spec, int min_level, const char *tag, int len)
#define REGX_BODY
static void lexContextDestroy(struct lexContext *p)
static void execData(struct lexSpec *spec, const char *ebuf, int elen, int formatted_text, const char *attribute_str, int attribute_len)
static int execRule(struct lexSpec *spec, struct lexContext *context, int ruleNo, int start_ptr, int *pptr)
static int extract_regx(void *clientData, struct recExtractCtrl *ctrl)
static struct DFA * lexSpecDFA(void)
static void lexSpecDestroy(struct lexSpec **pp)
static char * f_win_get(struct lexSpec *spec, off_t start_pos, off_t end_pos, int *size)
static int readParseToken(const char **cpp, int *len)
static int execTok(struct lexSpec *spec, const char **src, const char **tokBuf, int *tokLen)
static void tagDataRelease(struct lexSpec *spec)
static int execAction(struct lexSpec *spec, struct lexRuleAction *ap, int start_ptr, int *pptr)
#define REGX_CONTEXT
#define REGX_END
#define REGX_BEGIN
static void variantBegin(struct lexSpec *spec, const char *class_str, int class_len, const char *type_str, int type_len, const char *value_str, int value_len)
static int f_win_advance(struct lexSpec *spec, int *pos)
static void regxCodeDel(struct regxCode **pp)
static data1_node * lexRoot(struct lexSpec *spec, off_t offset, const char *context_name)
static void actionListDel(struct lexRuleAction **rap)
static void tagStrip(const char **tag, int *len)
static int actionListMk(struct lexSpec *spec, const char *s, struct lexRuleAction **ap)
static struct lexContext * lexContextCreate(const char *name)
static struct lexSpec * lexSpecCreate(const char *name, data1_handle dh)
int readFileSpec(struct lexSpec *spec)
static void execCode(struct lexSpec *spec, struct regxCode *code)
static void tagBegin(struct lexSpec *spec, const char *tag, int len)
#define REGX_INIT
#define F_WIN_EOF
static void regxCodeMk(struct regxCode **pp, const char *buf, int len)
static char * regxStrz(const char *src, int len, char *str)
ZEBRA_RES grs_config(void *clientData, Res res, const char *args)
int readOneSpec(struct lexSpec *spec, const char *s)
#define REGX_MAX_ARGS
static void execDataP(struct lexSpec *spec, const char *ebuf, int elen, int formatted_text)
void * grs_init(Res res, RecType recType)
int lexNode(struct lexSpec *spec, int *ptr)
data1_node * grs_read_regx(struct grs_read_info *p)
void grs_destroy(void *clientData)
static int tryMatch(struct lexSpec *spec, int *pptr, int *mptr, struct DFA *dfa, int greedy)
#define REGX_PATTERN
static int retrieve_regx(void *clientData, struct recRetrieveCtrl *ctrl)
static struct recType regx_type
#define REGX_CODE
struct recType * RecType
Definition recctrl.h:148
int zebra_grs_retrieve(void *clientData, struct recRetrieveCtrl *p, data1_node *(*grs_read)(struct grs_read_info *))
Definition recgrs.c:1072
int zebra_grs_extract(void *clientData, struct recExtractCtrl *p, data1_node *(*grs_read)(struct grs_read_info *))
Definition recgrs.c:936
struct res_struct * Res
Definition res.h:27
short rule_no
Definition dfa.h:49
short tran_no
Definition dfa.h:48
short rule_nno
Definition dfa.h:50
struct DFA_tran * trans
Definition dfa.h:45
Definition dfa.h:30
unsigned short to
Definition dfa.h:32
unsigned char ch[2]
Definition dfa.h:31
Definition dfa.h:53
struct DFA_state ** states
Definition dfa.h:55
record reader stream
Definition recctrl.h:71
off_t(* seekf)(struct ZebraRecStream *s, off_t offset)
seek function
Definition recctrl.h:77
off_t(* endf)(struct ZebraRecStream *s, off_t *offset)
set and get of record position
Definition recctrl.h:81
int(* readf)(struct ZebraRecStream *s, char *buf, size_t count)
read function
Definition recctrl.h:75
off_t(* tellf)(struct ZebraRecStream *s)
tell function
Definition recctrl.h:79
char lbuf[DATA1_LOCALDATA]
Definition data1.h:339
char * type
Definition data1.h:290
struct data1_node * parent
Definition data1.h:343
struct data1_node::@301101362156040217205154262063004221063310255144::@326023201334017323323260313204345146150132264306 variant
char * tag
Definition data1.h:296
char * data
Definition data1.h:307
struct data1_node * next
Definition data1.h:340
int len
Definition data1.h:308
struct data1_node::@301101362156040217205154262063004221063310255144::@312107066076370025032234161075372154153236151322 root
struct data1_absyn * absyn
Definition data1.h:291
unsigned formatted_text
Definition data1.h:322
int which
Definition data1.h:285
char * value
Definition data1.h:328
union data1_node::@301101362156040217205154262063004221063310255144 u
struct data1_xattr * next
Definition data1.h:262
data1_handle dh
Definition recgrs.h:31
struct ZebraRecStream * stream
Definition recgrs.h:28
void * clientData
Definition recgrs.h:29
struct lexRuleAction * endActionList
char * name
struct lexRuleInfo ** fastRule
struct lexRule * rules
struct lexRuleAction * beginActionList
struct DFA * dfa
struct lexRuleAction * initActionList
struct lexContext * next
struct lexRuleAction * next
struct regxCode * code
struct DFA * dfa
struct lexRuleAction::@361152206274041047011207072351072023354250134264::@331307174160120347270273164353043313014042030275 pattern
union lexRuleAction::@361152206274041047011207072351072023354250134264 u
struct lexRuleAction * actionList
struct lexRule * next
struct lexRuleInfo info
char * f_win_buf
data1_handle dh
int f_win_size
int f_win_end
int context_stack_size
off_t(* f_win_ef)(struct ZebraRecStream *s, off_t *)
struct lexContext * context
off_t(* f_win_sf)(struct ZebraRecStream *, off_t)
int stop_flag
int arg_start[REGX_MAX_ARGS]
struct ZebraRecStream * stream
data1_node ** d1_stack
struct lexContext ** context_stack
int f_win_start
int arg_end[REGX_MAX_ARGS]
int(* f_win_rf)(struct ZebraRecStream *, char *, size_t)
int context_stack_top
char * name
struct lexConcatBuf * concatBuf
char type[256]
struct lexSpec * spec
record extract for indexing
Definition recctrl.h:101
char * str
#define ZEBRA_OK
Definition util.h:82
short ZEBRA_RES
Common return type for Zebra API.
Definition util.h:80