The UAT gui starts to work
[obnox/wireshark/wip.git] / epan / dfilter / dfilter.c
1 /*
2  * $Id$
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
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 #include "dfilter-int.h"
31 #include "syntax-tree.h"
32 #include "gencode.h"
33 #include "semcheck.h"
34 #include "dfvm.h"
35 #include <epan/epan_dissect.h>
36 #include "dfilter.h"
37 #include "dfilter-macro.h"
38 #include <epan/report_err.h>
39
40 #define DFILTER_TOKEN_ID_OFFSET 1
41
42 /* Global error message space for dfilter_compile errors */
43 static gchar dfilter_error_msg_buf[1024];
44 gchar *dfilter_error_msg;       /* NULL when no error resulted */
45
46 /* From scanner.c */
47 void df_scanner_text(const char *text);
48 void    df_scanner_cleanup(void);
49 int     df_lex(void);
50
51 /* Holds the singular instance of our Lemon parser object */
52 static void*    ParserObj = NULL;
53
54 void
55 dfilter_fail(const char *format, ...)
56 {
57         va_list args;
58
59         /* If we've already reported one error, don't overwite it */
60         if (dfilter_error_msg != NULL)
61                 return;
62
63         va_start(args, format);
64
65         g_vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
66                         format, args);
67         dfilter_error_msg = dfilter_error_msg_buf;
68         va_end(args);
69 }
70
71
72 /* Initialize the dfilter module */
73 void
74 dfilter_init(void)
75 {
76         if (ParserObj) {
77                 g_message("I expected ParserObj to be NULL\n");
78                 /* Free the Lemon Parser object */
79                 DfilterFree(ParserObj, g_free);
80         }
81         /* Allocate an instance of our Lemon-based parser */
82         ParserObj = DfilterAlloc(g_malloc);
83
84 /* Enable parser tracing by defining AM_CFLAGS
85  * so that it contains "-DDFTRACE".
86  */
87 #ifdef DFTRACE
88         /* Trace parser */
89         DfilterTrace(stdout, "lemon> ");
90 #endif
91         
92         /* Initialize the syntax-tree sub-sub-system */
93         sttype_init();
94         
95         dfilter_macro_init();
96 }
97
98 /* Clean-up the dfilter module */
99 void
100 dfilter_cleanup(void)
101 {
102         /* Free the Lemon Parser object */
103         if (ParserObj) {
104                 DfilterFree(ParserObj, g_free);
105         }
106
107         /* Clean up the syntax-tree sub-sub-system */
108         sttype_cleanup();
109 }
110
111 static dfilter_t*
112 dfilter_new(void)
113 {
114         dfilter_t       *df;
115
116         df = g_new(dfilter_t, 1);
117         df->insns = NULL;
118
119         return df;
120 }
121
122 /* Given a GPtrArray of instructions (dfvm_insn_t),
123  * free them. */
124 static void
125 free_insns(GPtrArray *insns)
126 {
127         unsigned int    i;
128         dfvm_insn_t     *insn;
129
130         for (i = 0; i < insns->len; i++) {
131                 insn = g_ptr_array_index(insns, i);
132                 dfvm_insn_free(insn);
133         }
134 }
135
136 void
137 dfilter_free(dfilter_t *df)
138 {
139         if (df->insns) {
140                 free_insns(df->insns);
141         }
142
143         if (df->interesting_fields) {
144                 g_free(df->interesting_fields);
145         }
146
147         g_free(df->registers);
148         g_free(df->attempted_load);
149         g_free(df);
150 }
151
152
153 static dfwork_t*
154 dfwork_new(void)
155 {
156         dfwork_t        *dfw;
157
158         dfw = g_new(dfwork_t, 1);
159
160         dfw->st_root = NULL;
161         dfw->syntax_error = FALSE;
162         dfw->insns = NULL;
163         dfw->loaded_fields = NULL;
164         dfw->interesting_fields = NULL;
165         dfw->next_insn_id = 0;
166         dfw->next_register = 0;
167
168         return dfw;
169 }
170
171 static void
172 dfwork_free(dfwork_t *dfw)
173 {
174         if (dfw->st_root) {
175                 stnode_free(dfw->st_root);
176         }
177
178         if (dfw->loaded_fields) {
179                 g_hash_table_destroy(dfw->loaded_fields);
180         }
181
182         if (dfw->interesting_fields) {
183                 g_hash_table_destroy(dfw->interesting_fields);
184         }
185
186         if (dfw->insns) {
187                 free_insns(dfw->insns);
188         }
189         
190         g_free(dfw);
191 }
192
193
194 gboolean
195 dfilter_compile(const gchar *text, dfilter_t **dfp)
196 {
197         int             token;
198         dfilter_t       *dfilter;
199         dfwork_t        *dfw;
200         gboolean failure = FALSE;
201                 
202         dfilter_error_msg = NULL;
203
204         if ( !( text = dfilter_macro_apply(text, 0, &dfilter_error_msg) ) ) {
205                 return FALSE;
206         }
207         
208         dfw = dfwork_new();
209
210         df_scanner_text(text);
211
212         while (1) {
213                 df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
214                 token = df_lex();
215
216                 /* Check for scanner failure */
217                 if (token == SCAN_FAILED) {
218                         failure = TRUE;
219                         break;
220                 }
221
222                 /* Check for end-of-input */
223                 if (token == 0) {
224                         break;
225                 }
226
227                 /* Give the token to the parser */
228                 Dfilter(ParserObj, token, df_lval, dfw);
229                 /* We've used the stnode_t, so we don't want to free it */
230                 df_lval = NULL;
231
232                 if (dfw->syntax_error) {
233                         failure = TRUE;
234                         break;
235                 }
236         } /* while (1) */
237
238         /* If we created an stnode_t but didn't use it, free it; the
239          * parser doesn't know about it and won't free it for us. */
240         if (df_lval) {
241                 stnode_free(df_lval);
242                 df_lval = NULL;
243         }
244
245         /* Tell the parser that we have reached the end of input; that
246          * way, it'll reset its state for the next compile.  (We want
247          * to do that even if we got a syntax error, to make sure the
248          * parser state is cleaned up; we don't create a new parser
249          * object when we start a new parse, and don't destroy it when
250          * the parse finishes.) */
251         Dfilter(ParserObj, 0, NULL, dfw);
252
253         /* One last check for syntax error (after EOF) */
254         if (dfw->syntax_error)
255                 failure = TRUE;
256
257         /* Reset flex */
258         df_scanner_cleanup();
259
260         if (failure)
261                 goto FAILURE;
262
263         /* Success, but was it an empty filter? If so, discard
264          * it and set *dfp to NULL */
265         if (dfw->st_root == NULL) {
266                 *dfp = NULL;
267         }
268         else {
269
270                 /* Check semantics and do necessary type conversion*/
271                 if (!dfw_semcheck(dfw)) {
272                         goto FAILURE;
273                 }
274
275                 /* Create bytecode */
276                 dfw_gencode(dfw);
277
278                 /* Tuck away the bytecode in the dfilter_t */
279                 dfilter = dfilter_new();
280                 dfilter->insns = dfw->insns;
281                 dfw->insns = NULL;
282                 dfilter->interesting_fields = dfw_interesting_fields(dfw,
283                         &dfilter->num_interesting_fields);
284
285                 /* Initialize run-time space */
286                 dfilter->num_registers = dfw->next_register;
287                 dfilter->registers = g_new0(GList*, dfilter->num_registers);
288                 dfilter->attempted_load = g_new0(gboolean, dfilter->num_registers);
289
290                 /* And give it to the user. */
291                 *dfp = dfilter;
292         }
293         /* SUCCESS */
294         dfwork_free(dfw);
295         return TRUE;
296
297 FAILURE:
298         if (dfw) {
299                 dfwork_free(dfw);
300         }
301         dfilter_fail("Unable to parse filter string \"%s\".", text);
302         *dfp = NULL;
303         return FALSE;
304
305 }
306
307
308 gboolean
309 dfilter_apply(dfilter_t *df, proto_tree *tree)
310 {
311         return dfvm_apply(df, tree);
312 }
313
314 gboolean
315 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
316 {
317         return dfvm_apply(df, edt->tree);
318 }
319
320
321 void
322 dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
323 {
324     int i;
325
326     for (i = 0; i < df->num_interesting_fields; i++) {
327         proto_tree_prime_hfid(tree, df->interesting_fields[i]);
328     }
329 }
330
331
332 void
333 dfilter_dump(dfilter_t *df)
334 {
335         dfvm_dump(stdout, df->insns);
336 }