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