44b8d04acbe8a3a970eb2113bb249a5514f08a94
[egate.git] / fml / fmlstr.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /*
45  * FML interpreter. Europagate, 1995
46  *
47  * $Log: fmlstr.c,v $
48  * Revision 1.7  1995/05/16 09:39:34  adam
49  * LICENSE.
50  *
51  * Revision 1.6  1995/03/27  12:49:51  adam
52  * Removed CFLAGS def. Bug fix (compile error when USE_GNU_REGEX=0).
53  *
54  * Revision 1.5  1995/03/02  08:06:07  adam
55  * Fml function strsub implemented. New test files marc[45].fml.
56  * New test options in fmltest.
57  *
58  * Revision 1.4  1995/02/27  09:01:21  adam
59  * Regular expression support. Argument passing by name option. New FML
60  * function strlen.
61  *
62  * Revision 1.3  1995/02/23  08:32:06  adam
63  * Changed header.
64  *
65  * Revision 1.1  1995/02/10  18:15:53  adam
66  * FML function 'strcmp' implemented. This function can be used to
67  * test for existence of MARC fields.
68  *
69  */
70
71 #include <assert.h>
72 #include <stdlib.h>
73 #include <stdio.h>
74
75 #include "fmlp.h"
76
77 #if USE_GNU_REGEX
78 #include <regex.h>
79 #endif
80
81 #if USE_GNU_REGEX
82 struct reg_cache {
83     struct re_pattern_buffer buf;
84     char *pattern;
85     struct reg_cache *next;
86 };
87
88 static int no_in_use = 0;
89 static struct reg_cache *reg_cache_list = NULL;
90
91 struct reg_cache *fml_reg_compile (const char *pattern)
92 {
93     struct reg_cache *list, *last = NULL;
94     for (list = reg_cache_list; list; list = list->next)
95     {
96         if (!strcmp (pattern, list->pattern))
97             return list;
98         last = list;
99     }
100     if (no_in_use >= 20)
101     {
102         for (list = reg_cache_list; list->next->next; list = list->next)
103             ;
104         free (list->next->pattern);
105         regfree (&list->next->buf);
106         free (list->next);
107         list->next = NULL;
108     }
109     else
110         no_in_use++;
111     list = malloc (sizeof (*list));
112     assert (list);
113     list->next = reg_cache_list;
114     reg_cache_list = list;
115     list->pattern = malloc (strlen(pattern)+1);
116     assert (list->pattern);
117     strcpy (list->pattern, pattern);
118
119     re_syntax_options = RE_SYNTAX_GREP;
120     list->buf.translate = NULL;
121     list->buf.fastmap = NULL;
122     list->buf.buffer = NULL;
123     list->buf.allocated = 0;
124     re_compile_pattern (pattern, strlen(pattern), &list->buf);
125     return list;
126 }
127
128 static int fml_reg_match (struct reg_cache *reg_pat, const char *str)
129 {
130     int ret, len = strlen (str);
131
132     ret = re_match (&reg_pat->buf, str, len, 0, NULL);
133     if (ret == len)
134          return 1;
135     return 0;
136 }
137
138 static struct fml_node *fml_exec_match (Fml fml, struct fml_node **lp, 
139                                          struct token *tp)
140 {
141     struct reg_cache *reg;
142     struct fml_node *fn;
143     const char *cp;
144     char pattern[128];
145     char sstring[128];
146
147     fml_cmd_lex (lp, tp); 
148     if (tp->kind == 't')
149     {
150         cp = tp->tokenbuf;
151         fml_cmd_lex (lp, tp);
152     }
153     else
154     {
155         fn = fml_expr_term (fml, lp, tp);
156         if (!fn->is_atom)
157         {
158             fml_node_delete (fml, fn);
159             return NULL;
160         }
161         fml_atom_str (fn->p[0], pattern);
162         fml_node_delete (fml, fn);
163         cp = pattern;
164     }
165     reg = fml_reg_compile (cp);
166     fn = fml_expr_term (fml, lp, tp);
167     if (!fn->is_atom)
168     {
169         fml_node_delete (fml, fn);
170         return NULL;
171     }
172     fml_atom_str (fn->p[0], sstring);
173     fml_node_delete (fml, fn);
174     if (fml_reg_match (reg, sstring))
175         return fml_mk_node_val (fml, 1);
176     return NULL;
177 }
178
179 #endif
180
181 static struct fml_node *fml_exec_strlen (Fml fml, struct fml_node **lp, 
182                                          struct token *tp)
183 {
184     struct fml_node *fn;
185     int len = 0;
186
187     fml_cmd_lex (lp, tp);
188     fn = fml_expr_term (fml, lp, tp);
189     while (fn)
190     {
191         if (fn->is_atom)
192             len += fml_atom_len (fn->p[0]);
193         fn = fn->p[1];
194         if (fn)
195             len++;
196     }
197     fml_node_delete (fml, fn);
198     return fml_mk_node_val (fml, len);
199 }
200
201 static struct fml_node *fml_exec_strsub (Fml fml, struct fml_node **lp,
202                                          struct token *tp)
203 {
204     struct fml_node *fn_str;
205     struct fml_node *fn_offset;
206     struct fml_node *fn_length;
207     struct fml_node *fn_res;
208     int offset, length;
209
210     fml_cmd_lex (lp, tp);
211     fn_str = fml_expr_term (fml, lp, tp);
212     fn_offset = fml_expr_term (fml, lp, tp);
213     fn_length = fml_expr_term (fml, lp, tp);
214     if (!fn_offset->is_atom || !fn_length->is_atom || !fn_str->is_atom)
215     {
216         fml_node_delete (fml, fn_str);
217         fml_node_delete (fml, fn_offset);
218         fml_node_delete (fml, fn_length);
219         return NULL;
220     }
221     offset = fml_atom_val (fn_offset->p[0]);
222     fml_node_delete (fml, fn_offset);
223     length = fml_atom_val (fn_length->p[0]);
224     fml_node_delete (fml, fn_length);
225     if (offset == 0 && fml_atom_len (fn_str->p[0]) < length)
226         return fn_str;
227     fn_res = fml_node_alloc (fml);
228     fn_res->is_atom = 1;
229     fn_res->p[0]= fml_atom_strsub (fml, fn_str->p[0], offset, length);
230     fml_node_delete (fml, fn_str);
231     return fn_res;
232 }
233
234 static struct fml_node *fml_exec_strcmp (Fml fml, struct fml_node **lp, 
235                                          struct token *tp)
236 {
237     char *arg;
238     struct fml_node *fn = NULL, *fn1, *fn2;
239     int n;
240
241     fml_cmd_lex (lp, tp);
242
243     fn1 = fml_expr_term (fml, lp, tp);
244     fn2 = fml_expr_term (fml, lp, tp);
245     if (!fn1->is_atom && !fn2->is_atom)
246         fn = NULL;
247     n = fml_atom_cmp (fml, fn1->p[0], fn2->p[0]);
248     if (n == 0)
249         arg = "0";
250     else if (n > 0)
251         arg = "1";
252     else 
253         arg = "-1";
254     fml_node_delete (fml, fn1);
255     fml_node_delete (fml, fn2);
256     fn = fml_node_alloc (fml);
257     fn->is_atom = 1;
258     fn->p[0] = fml_atom_alloc (fml, arg);
259     return fn;
260 }
261
262 void fml_str_init (Fml fml)
263 {
264     struct fml_sym_info *sym_info;
265
266     sym_info = fml_sym_add (fml->sym_tab, "strcmp");
267     sym_info->kind = FML_CPREFIX;
268     sym_info->prefix = fml_exec_strcmp;
269     sym_info = fml_sym_add (fml->sym_tab, "strlen");
270     sym_info->kind = FML_CPREFIX;
271     sym_info->prefix = fml_exec_strlen;
272     sym_info = fml_sym_add (fml->sym_tab, "strsub");
273     sym_info->kind = FML_CPREFIX;
274     sym_info->prefix = fml_exec_strsub;
275 #if USE_GNU_REGEX
276     sym_info = fml_sym_add (fml->sym_tab, "match");
277     sym_info->kind = FML_CPREFIX;
278     sym_info->prefix = fml_exec_match;
279 #endif
280 }