Regular expression support. Argument passing by name option. New FML
[egate.git] / fml / fmlstr.c
1 /*
2  * FML interpreter. Europagate, 1995
3  *
4  * $Log: fmlstr.c,v $
5  * Revision 1.4  1995/02/27 09:01:21  adam
6  * Regular expression support. Argument passing by name option. New FML
7  * function strlen.
8  *
9  * Revision 1.3  1995/02/23  08:32:06  adam
10  * Changed header.
11  *
12  * Revision 1.1  1995/02/10  18:15:53  adam
13  * FML function 'strcmp' implemented. This function can be used to
14  * test for existence of MARC fields.
15  *
16  */
17
18 #include <assert.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21
22 #include "fmlp.h"
23
24 #if USE_GNU_REGEX
25 #include <regex.h>
26 #endif
27
28 #if USE_GNU_REGEX
29 struct reg_cache {
30     struct re_pattern_buffer buf;
31     char *pattern;
32     struct reg_cache *next;
33 };
34
35 static int no_in_use = 0;
36 static struct reg_cache *reg_cache_list = NULL;
37
38 struct reg_cache *fml_reg_compile (const char *pattern)
39 {
40     struct reg_cache *list, *last = NULL;
41     for (list = reg_cache_list; list; list = list->next)
42     {
43         if (!strcmp (pattern, list->pattern))
44             return list;
45         last = list;
46     }
47     if (no_in_use >= 20)
48     {
49         for (list = reg_cache_list; list->next->next; list = list->next)
50             ;
51         free (list->next->pattern);
52         regfree (&list->next->buf);
53         free (list->next);
54         list->next = NULL;
55     }
56     else
57         no_in_use++;
58     list = malloc (sizeof (*list));
59     assert (list);
60     list->next = reg_cache_list;
61     reg_cache_list = list;
62     list->pattern = malloc (strlen(pattern)+1);
63     assert (list->pattern);
64     strcpy (list->pattern, pattern);
65
66     re_syntax_options = RE_SYNTAX_GREP;
67     list->buf.translate = NULL;
68     list->buf.fastmap = NULL;
69     list->buf.buffer = NULL;
70     list->buf.allocated = 0;
71     re_compile_pattern (pattern, strlen(pattern), &list->buf);
72     return list;
73 }
74
75 static int fml_reg_match (struct reg_cache *reg_pat, const char *str)
76 {
77     int ret, len = strlen (str);
78
79     ret = re_match (&reg_pat->buf, str, len, 0, NULL);
80     if (ret == len)
81          return 1;
82     return 0;
83 }
84
85 #endif
86
87 static struct fml_node *fml_exec_match (Fml fml, struct fml_node **lp, 
88                                          struct token *tp)
89 {
90     struct reg_cache *reg;
91     struct fml_node *fn;
92     const char *cp;
93     char pattern[128];
94     char sstring[128];
95
96     fml_cmd_lex (lp, tp); 
97     if (tp->kind == 't')
98     {
99         cp = tp->tokenbuf;
100         fml_cmd_lex (lp, tp);
101     }
102     else
103     {
104         fn = fml_expr_term (fml, lp, tp);
105         if (!fn->is_atom)
106         {
107             fml_node_delete (fml, fn);
108             return NULL;
109         }
110         fml_atom_str (fn->p[0], pattern);
111         fml_node_delete (fml, fn);
112         cp = pattern;
113     }
114     reg = fml_reg_compile (cp);
115     fn = fml_expr_term (fml, lp, tp);
116     if (!fn->is_atom)
117     {
118         fml_node_delete (fml, fn);
119         return NULL;
120     }
121     fml_atom_str (fn->p[0], sstring);
122     fml_node_delete (fml, fn);
123     if (fml_reg_match (reg, sstring))
124         return fml_mk_node_val (fml, 1);
125     return NULL;
126 }
127
128 static struct fml_node *fml_exec_strlen (Fml fml, struct fml_node **lp, 
129                                          struct token *tp)
130 {
131     struct fml_node *fn;
132     int len = 0;
133
134     fml_cmd_lex (lp, tp);
135     fn = fml_expr_term (fml, lp, tp);
136     while (fn)
137     {
138         if (fn->is_atom)
139             len += fml_atom_len (fn->p[0]);
140         fn = fn->p[1];
141         if (fn)
142             len++;
143     }
144     fml_node_delete (fml, fn);
145     return fml_mk_node_val (fml, len);
146 }
147
148 static struct fml_node *fml_exec_strcmp (Fml fml, struct fml_node **lp, 
149                                          struct token *tp)
150 {
151     char *arg;
152     struct fml_node *fn = NULL, *fn1, *fn2;
153     int n;
154
155     fml_cmd_lex (lp, tp);
156
157     fn1 = fml_expr_term (fml, lp, tp);
158     fn2 = fml_expr_term (fml, lp, tp);
159     if (!fn1->is_atom && !fn2->is_atom)
160         fn = NULL;
161     n = fml_atom_cmp (fml, fn1->p[0], fn2->p[0]);
162     if (n == 0)
163         arg = "0";
164     else if (n > 0)
165         arg = "1";
166     else 
167         arg = "-1";
168     fml_node_delete (fml, fn1);
169     fml_node_delete (fml, fn2);
170     fn = fml_node_alloc (fml);
171     fn->is_atom = 1;
172     fn->p[0] = fml_atom_alloc (fml, arg);
173     return fn;
174 }
175
176 void fml_str_init (Fml fml)
177 {
178     struct fml_sym_info *sym_info;
179
180     sym_info = fml_sym_add (fml->sym_tab, "strcmp");
181     sym_info->kind = FML_CPREFIX;
182     sym_info->prefix = fml_exec_strcmp;
183     sym_info = fml_sym_add (fml->sym_tab, "strlen");
184     sym_info->kind = FML_CPREFIX;
185     sym_info->prefix = fml_exec_strlen;
186 #if USE_GNU_REGEX
187     sym_info = fml_sym_add (fml->sym_tab, "match");
188     sym_info->kind = FML_CPREFIX;
189     sym_info->prefix = fml_exec_match;
190 #endif
191 }