Update Free Software Foundation address.
[metze/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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 const 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_new0(dfilter_t, 1);
117         df->insns = NULL;
118     df->deprecated = NULL;
119
120         return df;
121 }
122
123 /* Given a GPtrArray of instructions (dfvm_insn_t),
124  * free them. */
125 static void
126 free_insns(GPtrArray *insns)
127 {
128         unsigned int    i;
129         dfvm_insn_t     *insn;
130
131         for (i = 0; i < insns->len; i++) {
132                 insn = (dfvm_insn_t     *)g_ptr_array_index(insns, i);
133                 dfvm_insn_free(insn);
134         }
135         g_ptr_array_free(insns, TRUE);
136 }
137
138 void
139 dfilter_free(dfilter_t *df)
140 {
141         guint i;
142
143         if (!df)
144                 return;
145
146         if (df->insns) {
147                 free_insns(df->insns);
148         }
149         if (df->consts) {
150                 free_insns(df->consts);
151         }
152
153         g_free(df->interesting_fields);
154
155         /* clear registers */
156         for (i = 0; i < df->max_registers; i++) {
157                 if (df->registers[i]) {
158                         g_list_free(df->registers[i]);
159                 }
160         }
161
162         if (df->deprecated) {
163                 for (i = 0; i < df->deprecated->len; ++i) {
164                         gchar *depr = (gchar *)g_ptr_array_index(df->deprecated, i);
165                         g_free(depr);
166                 }
167                 g_ptr_array_free(df->deprecated, TRUE);
168         }
169
170         g_free(df->registers);
171         g_free(df->attempted_load);
172         g_free(df);
173 }
174
175
176 static dfwork_t*
177 dfwork_new(void)
178 {
179         dfwork_t        *dfw;
180
181         dfw = g_new0(dfwork_t, 1);
182         dfw->first_constant = -1;
183
184         return dfw;
185 }
186
187 static void
188 dfwork_free(dfwork_t *dfw)
189 {
190         if (dfw->st_root) {
191                 stnode_free(dfw->st_root);
192         }
193
194         if (dfw->loaded_fields) {
195                 g_hash_table_destroy(dfw->loaded_fields);
196         }
197
198         if (dfw->interesting_fields) {
199                 g_hash_table_destroy(dfw->interesting_fields);
200         }
201
202         if (dfw->insns) {
203                 free_insns(dfw->insns);
204         }
205
206         if (dfw->consts) {
207                 free_insns(dfw->consts);
208         }
209
210         g_free(dfw);
211 }
212
213 gboolean
214 dfilter_compile(const gchar *text, dfilter_t **dfp)
215 {
216         int             token;
217         dfilter_t       *dfilter;
218         dfwork_t        *dfw;
219         gboolean failure = FALSE;
220         const char      *depr_test;
221         guint           i;
222         GPtrArray       *deprecated;
223
224         g_assert(dfp);
225
226         if (!text) {
227                 *dfp = NULL;
228                 return FALSE;
229         }
230
231         dfilter_error_msg = NULL;
232
233         if ( !( text = dfilter_macro_apply(text, &dfilter_error_msg) ) ) {
234                 return FALSE;
235         }
236
237         dfw = dfwork_new();
238
239         df_scanner_text(text);
240
241         deprecated = g_ptr_array_new();
242
243         while (1) {
244                 df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
245                 token = df_lex();
246
247                 /* Check for scanner failure */
248                 if (token == SCAN_FAILED) {
249                         failure = TRUE;
250                         break;
251                 }
252
253                 /* Check for end-of-input */
254                 if (token == 0) {
255                         break;
256                 }
257
258                 /* See if the node is deprecated */
259                 depr_test = stnode_deprecated(df_lval);
260
261                 if (depr_test) {
262                         for (i = 0; i < deprecated->len; i++) {
263                                 if (g_ascii_strcasecmp(depr_test, (const gchar *)g_ptr_array_index(deprecated, i)) == 0) {
264                                         /* It's already in our list */
265                                         depr_test = NULL;
266                                 }
267                         }
268                 }
269
270                 if (depr_test) {
271                         g_ptr_array_add(deprecated, g_strdup(depr_test));
272                 }
273
274                 /* Give the token to the parser */
275                 Dfilter(ParserObj, token, df_lval, dfw);
276                 /* We've used the stnode_t, so we don't want to free it */
277                 df_lval = NULL;
278
279                 if (dfw->syntax_error) {
280                         failure = TRUE;
281                         break;
282                 }
283
284         } /* while (1) */
285
286         /* If we created an stnode_t but didn't use it, free it; the
287          * parser doesn't know about it and won't free it for us. */
288         if (df_lval) {
289                 stnode_free(df_lval);
290                 df_lval = NULL;
291         }
292
293         /* Tell the parser that we have reached the end of input; that
294          * way, it'll reset its state for the next compile.  (We want
295          * to do that even if we got a syntax error, to make sure the
296          * parser state is cleaned up; we don't create a new parser
297          * object when we start a new parse, and don't destroy it when
298          * the parse finishes.) */
299         Dfilter(ParserObj, 0, NULL, dfw);
300
301         /* One last check for syntax error (after EOF) */
302         if (dfw->syntax_error)
303                 failure = TRUE;
304
305         /* Reset flex */
306         df_scanner_cleanup();
307
308         if (failure)
309                 goto FAILURE;
310
311         /* Success, but was it an empty filter? If so, discard
312          * it and set *dfp to NULL */
313         if (dfw->st_root == NULL) {
314                 *dfp = NULL;
315                 for (i = 0; i < deprecated->len; ++i) {
316                         gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
317                         g_free(depr);
318                 }
319                 g_ptr_array_free(deprecated, TRUE);
320         }
321         else {
322
323                 /* Check semantics and do necessary type conversion*/
324                 if (!dfw_semcheck(dfw)) {
325                         goto FAILURE;
326                 }
327
328                 /* Create bytecode */
329                 dfw_gencode(dfw);
330
331                 /* Tuck away the bytecode in the dfilter_t */
332                 dfilter = dfilter_new();
333                 dfilter->insns = dfw->insns;
334                 dfilter->consts = dfw->consts;
335                 dfw->insns = NULL;
336                 dfw->consts = NULL;
337                 dfilter->interesting_fields = dfw_interesting_fields(dfw,
338                         &dfilter->num_interesting_fields);
339
340                 /* Initialize run-time space */
341                 dfilter->num_registers = dfw->first_constant;
342                 dfilter->max_registers = dfw->next_register;
343                 dfilter->registers = g_new0(GList*, dfilter->max_registers);
344                 dfilter->attempted_load = g_new0(gboolean, dfilter->max_registers);
345
346                 /* Initialize constants */
347                 dfvm_init_const(dfilter);
348
349                 /* Add any deprecated items */
350                 dfilter->deprecated = deprecated;
351
352                 /* And give it to the user. */
353                 *dfp = dfilter;
354         }
355         /* SUCCESS */
356         dfwork_free(dfw);
357         return TRUE;
358
359 FAILURE:
360         if (dfw) {
361                 dfwork_free(dfw);
362         }
363         for (i = 0; i < deprecated->len; ++i) {
364                 gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
365                 g_free(depr);
366         }
367         g_ptr_array_free(deprecated, TRUE);
368         dfilter_fail("Unable to parse filter string \"%s\".", text);
369         *dfp = NULL;
370         return FALSE;
371
372 }
373
374
375 gboolean
376 dfilter_apply(dfilter_t *df, proto_tree *tree)
377 {
378         return dfvm_apply(df, tree);
379 }
380
381 gboolean
382 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
383 {
384         return dfvm_apply(df, edt->tree);
385 }
386
387
388 void
389 dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
390 {
391     int i;
392
393     for (i = 0; i < df->num_interesting_fields; i++) {
394         proto_tree_prime_hfid(tree, df->interesting_fields[i]);
395     }
396 }
397
398 GPtrArray *
399 dfilter_deprecated_tokens(dfilter_t *df) {
400         if (df->deprecated && df->deprecated->len > 0) {
401                 return df->deprecated;
402         }
403         return NULL;
404 }
405
406 void
407 dfilter_dump(dfilter_t *df)
408 {
409         guint i;
410         const gchar *sep = "";
411
412         dfvm_dump(stdout, df);
413
414         if (df->deprecated && df->deprecated->len) {
415                 printf("\nDeprecated tokens: ");
416                 for (i = 0; i < df->deprecated->len; i++) {
417                         printf("%s\"%s\"", sep, (char *) g_ptr_array_index(df->deprecated, i));
418                         sep = ", ";
419                 }
420                 printf("\n");
421         }
422 }