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