Move the code to build the balanced tree of fields into "proto_init()",
[obnox/wireshark/wip.git] / epan / dfilter / dfilter.c
1 /*
2  * $Id: dfilter.c,v 1.9 2002/04/29 07:55:32 guy Exp $
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@ethereal.com>
6  * Copyright 2001 Gerald Combs
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #ifdef NEED_SNPRINTF_H
31 #include "snprintf.h"
32 #endif
33
34 #include "dfilter-int.h"
35 #include "syntax-tree.h"
36 #include "gencode.h"
37 #include "semcheck.h"
38 #include "dfvm.h"
39 #include <epan/epan_dissect.h>
40
41 #define DFILTER_TOKEN_ID_OFFSET 1
42
43 /* Global error message space for dfilter_compile errors */
44 static gchar dfilter_error_msg_buf[1024];
45 gchar *dfilter_error_msg;       /* NULL when no error resulted */
46
47 /* In proto.c */
48 extern int hf_text_only;
49
50 /* From scanner.c */
51 void    df_scanner_text(const char *text);
52 void    df_scanner_file(FILE *fh);
53 void    df_scanner_cleanup(void);
54 int     df_lex(void);
55
56 /* Holds the singular instance of our Lemon parser object */
57 static void*    ParserObj = NULL;
58
59 void
60 dfilter_fail(char *format, ...)
61 {
62         va_list args;
63
64         /* If we've already reported one error, don't overwite it */
65         if (dfilter_error_msg != NULL)
66                 return;
67
68         va_start(args, format);
69
70         vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
71                         format, args);
72         dfilter_error_msg = dfilter_error_msg_buf;
73         va_end(args);
74 }
75
76
77 /* Initialize the dfilter module */
78 void
79 dfilter_init(void)
80 {
81         if (ParserObj) {
82                 g_message("I expected ParserObj to be NULL\n");
83                 /* Free the Lemon Parser object */
84                 DfilterFree(ParserObj, g_free);
85         }
86         /* Allocate an instance of our Lemon-based parser */
87         ParserObj = DfilterAlloc(g_malloc);
88
89         /* Initialize the syntax-tree sub-sub-system */
90         sttype_init();
91 }
92
93 /* Clean-up the dfilter module */
94 void
95 dfilter_cleanup(void)
96 {
97         /* Free the Lemon Parser object */
98         if (ParserObj) {
99                 DfilterFree(ParserObj, g_free);
100         }
101
102         /* Clean up the syntax-tree sub-sub-system */
103         sttype_cleanup();
104 }
105
106 static dfilter_t*
107 dfilter_new(void)
108 {
109         dfilter_t       *df;
110
111         df = g_new(dfilter_t, 1);
112         df->insns = NULL;
113
114         return df;
115 }
116
117 /* Given a GPtrArray of instructions (dfvm_insn_t),
118  * free them. */
119 static void
120 free_insns(GPtrArray *insns)
121 {
122         unsigned int    i;
123         dfvm_insn_t     *insn;
124
125         for (i = 0; i < insns->len; i++) {
126                 insn = g_ptr_array_index(insns, i);
127                 dfvm_insn_free(insn);
128         }
129 }
130
131 void
132 dfilter_free(dfilter_t *df)
133 {
134         if (df->insns) {
135                 free_insns(df->insns);
136         }
137
138     if (df->interesting_fields) {
139         g_free(df->interesting_fields);
140     }
141
142         g_free(df->registers);
143         g_free(df->attempted_load);
144         g_free(df);
145 }
146
147
148 static dfwork_t*
149 dfwork_new(void)
150 {
151         dfwork_t        *dfw;
152
153         dfw = g_new(dfwork_t, 1);
154
155         dfw->st_root = NULL;
156         dfw->syntax_error = FALSE;
157         dfw->insns = NULL;
158         dfw->loaded_fields = NULL;
159         dfw->interesting_fields = NULL;
160         dfw->next_insn_id = 0;
161         dfw->next_register = 0;
162
163         return dfw;
164 }
165
166 static void
167 dfwork_free(dfwork_t *dfw)
168 {
169         if (dfw->st_root) {
170                 stnode_free(dfw->st_root);
171         }
172
173         if (dfw->loaded_fields) {
174                 g_hash_table_destroy(dfw->loaded_fields);
175         }
176
177         if (dfw->interesting_fields) {
178                 g_hash_table_destroy(dfw->interesting_fields);
179         }
180
181         if (dfw->insns) {
182                 free_insns(dfw->insns);
183         }
184
185
186         g_free(dfw);
187 }
188
189
190 gboolean
191 dfilter_compile(gchar *text, dfilter_t **dfp)
192 {
193         int             token;
194         dfilter_t       *dfilter;
195         dfwork_t        *dfw;
196
197         dfilter_error_msg = NULL;
198
199         dfw = dfwork_new();
200
201         df_scanner_text(text);
202
203         while (1) {
204                 df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
205                 token = df_lex();
206
207                 /* Check for end-of-input */
208                 if (token == 0) {
209                         /* Tell the parser that we have reached the end of input */
210                         Dfilter(ParserObj, 0, NULL, dfw);
211
212                         /* Free the stnode_t that we just generated, since
213                          * the parser doesn't know about it and won't free it
214                          * for us. */
215                         stnode_free(df_lval);
216                         df_lval = NULL;
217                         break;
218                 }
219
220                 /* Give the token to the parser */
221                 Dfilter(ParserObj, token, df_lval, dfw);
222
223                 if (dfw->syntax_error) {
224                         break;
225                 }
226         }
227
228         /* One last check for syntax error (after EOF) */
229         if (dfw->syntax_error) {
230                 goto FAILURE;
231         }
232
233
234         /* Success, but was it an empty filter? If so, discard
235          * it and set *dfp to NULL */
236         if (dfw->st_root == NULL) {
237                 *dfp = NULL;
238         }
239         else {
240
241                 /* Check semantics and do necessary type conversion*/
242                 if (!dfw_semcheck(dfw)) {
243                         goto FAILURE;
244                 }
245
246                 /* Create bytecode */
247                 dfw_gencode(dfw);
248         
249                 /* Tuck away the bytecode in the dfilter_t */
250                 dfilter = dfilter_new();
251                 dfilter->insns = dfw->insns;
252                 dfw->insns = NULL;
253         dfilter->interesting_fields = dfw_interesting_fields(dfw,
254                 &dfilter->num_interesting_fields);
255
256                 /* Initialize run-time space */
257                 dfilter->num_registers = dfw->next_register;
258                 dfilter->registers = g_new0(GList*, dfilter->num_registers);
259                 dfilter->attempted_load = g_new0(gboolean, dfilter->num_registers);
260
261                 /* And give it to the user. */
262                 *dfp = dfilter;
263         }
264         /* SUCCESS */
265         dfwork_free(dfw);
266
267         /* Reset flex */
268         df_scanner_cleanup();
269
270         return TRUE;
271
272 FAILURE:
273         if (dfw) {
274                 dfwork_free(dfw);
275         }
276         dfilter_fail("Unable to parse filter string \"%s\".", text);
277         *dfp = NULL;
278
279         /* Reset flex */
280         df_scanner_cleanup();
281         return FALSE;
282
283 }
284
285
286 gboolean
287 dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree)
288 {
289         return dfvm_apply(df, tvb, tree);
290 }
291
292 gboolean
293 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
294 {
295         return dfvm_apply(df, edt->tvb, edt->tree);
296 }
297
298
299 void
300 dfilter_foreach_interesting_field(dfilter_t *df, GFunc func,
301         gpointer user_data)
302 {
303     int i;
304
305     for (i = 0; i < df->num_interesting_fields; i++) {
306         func(GINT_TO_POINTER(df->interesting_fields[i]), user_data);
307     }
308 }
309                 
310
311 void
312 dfilter_dump(dfilter_t *df)
313 {
314         dfvm_dump(stdout, df->insns);
315 }