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