Run latex
[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.8  2001/02/26 14:32:36  adam
49  * Updated for YAZ 1.7. HTML output tidy up. Added LOC target.
50  *
51  * Revision 1.7  1995/05/16 09:39:34  adam
52  * LICENSE.
53  *
54  * Revision 1.6  1995/03/27  12:49:51  adam
55  * Removed CFLAGS def. Bug fix (compile error when USE_GNU_REGEX=0).
56  *
57  * Revision 1.5  1995/03/02  08:06:07  adam
58  * Fml function strsub implemented. New test files marc[45].fml.
59  * New test options in fmltest.
60  *
61  * Revision 1.4  1995/02/27  09:01:21  adam
62  * Regular expression support. Argument passing by name option. New FML
63  * function strlen.
64  *
65  * Revision 1.3  1995/02/23  08:32:06  adam
66  * Changed header.
67  *
68  * Revision 1.1  1995/02/10  18:15:53  adam
69  * FML function 'strcmp' implemented. This function can be used to
70  * test for existence of MARC fields.
71  *
72  */
73
74 #include <assert.h>
75 #include <stdlib.h>
76 #include <stdio.h>
77 #include <string.h>
78
79 #include "fmlp.h"
80
81 #if USE_GNU_REGEX
82 #include <regex.h>
83 #endif
84
85 #if USE_GNU_REGEX
86 struct reg_cache {
87     struct re_pattern_buffer buf;
88     char *pattern;
89     struct reg_cache *next;
90 };
91
92 static int no_in_use = 0;
93 static struct reg_cache *reg_cache_list = NULL;
94
95 struct reg_cache *fml_reg_compile (const char *pattern)
96 {
97     struct reg_cache *list, *last = NULL;
98     for (list = reg_cache_list; list; list = list->next)
99     {
100         if (!strcmp (pattern, list->pattern))
101             return list;
102         last = list;
103     }
104     if (no_in_use >= 20)
105     {
106         for (list = reg_cache_list; list->next->next; list = list->next)
107             ;
108         free (list->next->pattern);
109         regfree (&list->next->buf);
110         free (list->next);
111         list->next = NULL;
112     }
113     else
114         no_in_use++;
115     list = malloc (sizeof (*list));
116     assert (list);
117     list->next = reg_cache_list;
118     reg_cache_list = list;
119     list->pattern = malloc (strlen(pattern)+1);
120     assert (list->pattern);
121     strcpy (list->pattern, pattern);
122
123     re_syntax_options = RE_SYNTAX_GREP;
124     list->buf.translate = NULL;
125     list->buf.fastmap = NULL;
126     list->buf.buffer = NULL;
127     list->buf.allocated = 0;
128     re_compile_pattern (pattern, strlen(pattern), &list->buf);
129     return list;
130 }
131
132 static int fml_reg_match (struct reg_cache *reg_pat, const char *str)
133 {
134     int ret, len = strlen (str);
135
136     ret = re_match (&reg_pat->buf, str, len, 0, NULL);
137     if (ret == len)
138          return 1;
139     return 0;
140 }
141
142 static struct fml_node *fml_exec_match (Fml fml, struct fml_node **lp, 
143                                          struct token *tp)
144 {
145     struct reg_cache *reg;
146     struct fml_node *fn;
147     const char *cp;
148     char pattern[128];
149     char sstring[128];
150
151     fml_cmd_lex (lp, tp); 
152     if (tp->kind == 't')
153     {
154         cp = tp->tokenbuf;
155         fml_cmd_lex (lp, tp);
156     }
157     else
158     {
159         fn = fml_expr_term (fml, lp, tp);
160         if (!fn->is_atom)
161         {
162             fml_node_delete (fml, fn);
163             return NULL;
164         }
165         fml_atom_str (fn->p[0], pattern);
166         fml_node_delete (fml, fn);
167         cp = pattern;
168     }
169     reg = fml_reg_compile (cp);
170     fn = fml_expr_term (fml, lp, tp);
171     if (!fn->is_atom)
172     {
173         fml_node_delete (fml, fn);
174         return NULL;
175     }
176     fml_atom_str (fn->p[0], sstring);
177     fml_node_delete (fml, fn);
178     if (fml_reg_match (reg, sstring))
179         return fml_mk_node_val (fml, 1);
180     return NULL;
181 }
182
183 #endif
184
185 static struct fml_node *fml_exec_strlen (Fml fml, struct fml_node **lp, 
186                                          struct token *tp)
187 {
188     struct fml_node *fn;
189     int len = 0;
190
191     fml_cmd_lex (lp, tp);
192     fn = fml_expr_term (fml, lp, tp);
193     while (fn)
194     {
195         if (fn->is_atom)
196             len += fml_atom_len (fn->p[0]);
197         fn = fn->p[1];
198         if (fn)
199             len++;
200     }
201     fml_node_delete (fml, fn);
202     return fml_mk_node_val (fml, len);
203 }
204
205 static struct fml_node *fml_exec_strsub (Fml fml, struct fml_node **lp,
206                                          struct token *tp)
207 {
208     struct fml_node *fn_str;
209     struct fml_node *fn_offset;
210     struct fml_node *fn_length;
211     struct fml_node *fn_res;
212     int offset, length;
213
214     fml_cmd_lex (lp, tp);
215     fn_str = fml_expr_term (fml, lp, tp);
216     fn_offset = fml_expr_term (fml, lp, tp);
217     fn_length = fml_expr_term (fml, lp, tp);
218     if (!fn_offset->is_atom || !fn_length->is_atom || !fn_str->is_atom)
219     {
220         fml_node_delete (fml, fn_str);
221         fml_node_delete (fml, fn_offset);
222         fml_node_delete (fml, fn_length);
223         return NULL;
224     }
225     offset = fml_atom_val (fn_offset->p[0]);
226     fml_node_delete (fml, fn_offset);
227     length = fml_atom_val (fn_length->p[0]);
228     fml_node_delete (fml, fn_length);
229     if (offset == 0 && fml_atom_len (fn_str->p[0]) < length)
230         return fn_str;
231     fn_res = fml_node_alloc (fml);
232     fn_res->is_atom = 1;
233     fn_res->p[0]= fml_atom_strsub (fml, fn_str->p[0], offset, length);
234     fml_node_delete (fml, fn_str);
235     return fn_res;
236 }
237
238 static struct fml_node *fml_exec_strcmp (Fml fml, struct fml_node **lp, 
239                                          struct token *tp)
240 {
241     char *arg;
242     struct fml_node *fn = NULL, *fn1, *fn2;
243     int n;
244
245     fml_cmd_lex (lp, tp);
246
247     fn1 = fml_expr_term (fml, lp, tp);
248     fn2 = fml_expr_term (fml, lp, tp);
249     if (!fn1->is_atom && !fn2->is_atom)
250         fn = NULL;
251     n = fml_atom_cmp (fml, fn1->p[0], fn2->p[0]);
252     if (n == 0)
253         arg = "0";
254     else if (n > 0)
255         arg = "1";
256     else 
257         arg = "-1";
258     fml_node_delete (fml, fn1);
259     fml_node_delete (fml, fn2);
260     fn = fml_node_alloc (fml);
261     fn->is_atom = 1;
262     fn->p[0] = fml_atom_alloc (fml, arg);
263     return fn;
264 }
265
266 void fml_str_init (Fml fml)
267 {
268     struct fml_sym_info *sym_info;
269
270     sym_info = fml_sym_add (fml->sym_tab, "strcmp");
271     sym_info->kind = FML_CPREFIX;
272     sym_info->prefix = fml_exec_strcmp;
273     sym_info = fml_sym_add (fml->sym_tab, "strlen");
274     sym_info->kind = FML_CPREFIX;
275     sym_info->prefix = fml_exec_strlen;
276     sym_info = fml_sym_add (fml->sym_tab, "strsub");
277     sym_info->kind = FML_CPREFIX;
278     sym_info->prefix = fml_exec_strsub;
279 #if USE_GNU_REGEX
280     sym_info = fml_sym_add (fml->sym_tab, "match");
281     sym_info->kind = FML_CPREFIX;
282     sym_info->prefix = fml_exec_match;
283 #endif
284 }