Allow filtering on 24-bit integral fields.
[obnox/wireshark/wip.git] / dfilter-scanner.l
1 %{
2
3 /* dfilter-scanner.l
4  * Scanner for display filters
5  *
6  * $Id: dfilter-scanner.l,v 1.28 2000/02/05 06:07:16 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_IO_H
33 #include <io.h>         /* for isatty() on win32 */
34 #endif
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #ifndef _STDIO_H
41 #include <stdio.h>
42 #endif
43
44 #ifndef _STRING_H
45 #include <string.h>
46 #endif
47
48 #ifndef __G_LIB_H__
49 #include <glib.h>
50 #endif
51
52 #ifndef __PROTO_H__
53 #include "proto.h"
54 #endif
55
56 #ifndef __DFILTER_H__
57 #include "dfilter.h"
58 #endif
59
60 #include "dfilter-int.h"
61
62 #include "dfilter-grammar.h"
63
64 /* Flex has a few routines which help us get the scanner to read
65  * from a string rather than from a file. POSIX lex only provides
66  * for reading from a file; any method of reading from a string
67  * is inherently non-portable.  Besides reading from a string,
68  * we have to worry about resetting the scanner after a bad
69  * parse; this too is non-portable. Combine the reset with
70  * a string input, and you have major non-portability. I'll provide
71  * the routines for flex here. If you really want to modify the
72  * scanner and use a non-flex lex implementation, you may
73  * add more ifdef's below.
74  */
75 #ifdef FLEX_SCANNER
76
77 /* Flex has built-in support for using a string as an input source
78  * instead of using a file. Nice!
79  */
80 YY_BUFFER_STATE string_input_buffer;
81
82 #else
83
84 static char *in_buffer;
85 #undef getc
86 #define getc(fp)  (*in_buffer == 0 ? EOF : *in_buffer++)
87
88 #endif
89
90 %}
91
92 whitespace      [\t ]
93 hex             [A-Fa-f0-9]{1,2}
94 hexsep          [-:\.]
95 minus           [-]
96 plus            [+]
97
98 %%
99
100 [\t\n ]+        /* ignore whitespace */
101
102
103 and|\&\&        { dfilter_lval.operand = TOK_AND; return TOK_AND; }
104 or|\|\|         { dfilter_lval.operand = TOK_OR; return TOK_OR; }
105 not|\!          { dfilter_lval.operand = TOK_NOT; return TOK_NOT; }
106 xor|\^\^        { dfilter_lval.operand = TOK_XOR; return TOK_XOR; }
107 eq|\=\=         { dfilter_lval.operand = TOK_EQ; return TOK_EQ; }
108 ne|\!\=         { dfilter_lval.operand = TOK_NE; return TOK_NE; }
109 gt|\>           { dfilter_lval.operand = TOK_GT; return TOK_GT; }
110 ge|\>\=         { dfilter_lval.operand = TOK_GE; return TOK_GE; }
111 lt|\<           { dfilter_lval.operand = TOK_LT; return TOK_LT; }
112 le|\<\=         { dfilter_lval.operand = TOK_LE; return TOK_LE; }
113
114 \[{whitespace}*-?[0-9]+{whitespace}*:{whitespace}*[0-9]+{whitespace}*\] { /* range [ x : y ] */
115
116         char    *byterange_string = g_strdup(yytext);
117         char    *s = byterange_string + 1; /* I don't want the first '[' */
118         char    *p;
119
120         /* Get the offset from the string */
121         if ((p = strtok(s, ":"))) {
122                 dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
123         }
124         else {
125                 g_free(byterange_string);
126                 return 0;
127         }
128
129         /* Get the Length from the string */
130         if ((p = strtok(NULL, "]"))) {
131                 dfilter_lval.byte_range.length = strtoul(p, NULL, 10);
132         }
133         else {
134                 g_free(byterange_string);
135                 return 0;
136         }
137         g_free(byterange_string);
138         return T_VAL_BYTE_RANGE;
139 }
140
141 \[{whitespace}*-?[0-9]+{whitespace}*\] { /* range [ x  ] */
142
143         char    *byterange_string = g_strdup(yytext);
144         char    *s = byterange_string + 1; /* I don't want the first '[' */
145         char    *p;
146
147         /* Get the offset from the string */
148         if ((p = strtok(s, "]"))) {
149                 dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
150         }
151         else {
152                 g_free(byterange_string);
153                 return 0;
154         }
155
156         dfilter_lval.byte_range.length = 0;
157         g_free(byterange_string);
158         return T_VAL_BYTE_RANGE;
159 }
160
161 {hex}({hexsep}{hex})+ {                 /* byte string, any length */
162         dfilter_lval.string = g_strdup(yytext);
163         return T_VAL_BYTE_STRING;
164 }
165
166
167 0[xX][A-Fa-f0-9]+ {                     /* hex values */
168         dfilter_lval.string = g_strdup(yytext);
169         return T_VAL_UNQUOTED_STRING;
170 }
171
172 [A-Za-z0-9\:][A-Za-z0-9\.\_\-\:]+ {
173         /* looks like a protocol, field name, or hostname */
174
175         int retval = 0;
176         enum ftenum ftype;
177         dfilter_lval.variable.id = dfilter_lookup_token(yytext);
178         if (dfilter_lval.variable.id < 0) {
179                 dfilter_lval.string = g_strdup(yytext);
180                 return T_VAL_UNQUOTED_STRING;
181         }
182         
183         ftype = proto_registrar_get_ftype(dfilter_lval.variable.id);
184         switch (ftype) {
185                 case FT_NONE:
186                         retval = T_FT_NONE;
187                         break;
188                 case FT_BOOLEAN:
189                         retval = T_FT_BOOLEAN;
190                         break;
191                 case FT_UINT8:
192                         retval = T_FT_UINT8;
193                         break;
194                 case FT_UINT16:
195                         retval = T_FT_UINT16;
196                         break;
197                 case FT_UINT24:
198                         retval = T_FT_UINT24;
199                         break;
200                 case FT_UINT32:
201                         retval = T_FT_UINT32;
202                         break;
203                 case FT_INT8:
204                         retval = T_FT_INT8;
205                         break;
206                 case FT_INT16:
207                         retval = T_FT_INT16;
208                         break;
209                 case FT_INT24:
210                         retval = T_FT_INT24;
211                         break;
212                 case FT_INT32:
213                         retval = T_FT_INT32;
214                         break;
215                 case FT_DOUBLE:
216                         retval = T_FT_DOUBLE;
217                         break;
218                 case FT_ABSOLUTE_TIME:
219                         dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-of-day values.",
220                             yytext);
221                         retval = 0;
222                         break;
223                 case FT_RELATIVE_TIME:
224                         dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-delta values.",
225                             yytext);
226                         retval = 0;
227                         break;
228                 case FT_STRING:
229                         retval = T_FT_STRING;
230                         break;
231                 case FT_ETHER:
232                         retval = T_FT_ETHER;
233                         break;
234                 case FT_BYTES:
235                         retval = T_FT_BYTES;
236                         break;
237                 case FT_IPv4:
238                         retval = T_FT_IPv4;
239                         break;
240                 case FT_IPv6:
241                         retval = T_FT_IPv6;
242                         break;
243                 case FT_IPXNET:
244                         retval = T_FT_IPXNET;
245                         break;
246                 default:
247                         printf("ftype for %s is %d\n", yytext, ftype);
248                         g_assert_not_reached();
249                         retval = 0;
250                         break;
251         }
252         dfilter_lval.variable.type = retval;
253         return retval;
254 }
255
256 ({plus}|{minus})?[0-9]+ {                       /* decimal and octal integers */
257         dfilter_lval.string = g_strdup(yytext);
258         return T_VAL_UNQUOTED_STRING;
259 }
260
261 ({plus}|{minus})?([0-9]+|[0-9]+\.[0-9]+|\.[0-9]+)([eE]({plus}|{minus})?[0-9]+)? {
262         /* I'm trying to capture all floating points here, and
263          * am using the strtod manpage as the description of
264          * valid formats */
265         dfilter_lval.string = g_strdup(yytext);
266         return T_VAL_UNQUOTED_STRING;
267 }
268
269 [0-9\:\.]+ {
270         dfilter_lval.string = g_strdup(yytext);
271         return T_VAL_UNQUOTED_STRING;
272 }
273
274 .       return yytext[0];
275 %%
276
277 /* Resets scanner and assigns the char* argument
278  * as the text to scan
279  */
280 void
281 dfilter_scanner_text(char *text)
282 {
283 #ifdef FLEX_SCANNER
284         string_input_buffer = yy_scan_string(text);
285 #else
286         in_buffer = text;
287 #endif
288 }
289
290 void
291 dfilter_scanner_cleanup(void)
292 {
293 #ifdef FLEX_SCANNER
294         yy_delete_buffer(string_input_buffer);
295 #else
296         /* There is no standard way to reset a lex scanner.
297          * This is necessary after a failed parse on a syntactically
298          * incorrect display filter. You have to reset the scanner
299          * so that yy_lex() doesn't start scanning from the middle
300          * of the previous input string.
301          */
302 #endif
303 }
304
305 /* Flex has an option '%option noyywrap' so that I don't have to
306  * provide this yywrap function, but in order to maintain portability,
307  * I'll just use this yywrap() function.
308  */
309 int
310 yywrap()
311 {
312         return 1; /* stop at EOF, instead of looking for next file */
313 }
314
315 /* converts a string representing a byte array
316  * to a guint8 array.
317  *
318  * Returns a non-null GByteArray pointer on success, NULL on failure.
319  */
320 GByteArray*
321 byte_str_to_guint8_array(const char *s)
322 {
323         GByteArray      *barray;
324         guint8          val;
325         char            *byte_str = g_strdup(s); /* local copy of string */
326         char            *p, *str;
327
328         barray = g_byte_array_new();
329         /* XXX - don't use global_df, but pass in pointer to GSList* */
330         global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
331
332         byte_str = g_strdup(s);
333         str = byte_str;
334         while ((p = strtok(str, "-:."))) {
335                 val = (guint8) strtoul(p, NULL, 16);
336                 g_byte_array_append(barray, &val, 1);
337
338                 /* subsequent calls to strtok() require NULL as arg 1 */
339                 str = NULL;
340         }
341
342         g_free(byte_str);
343         return barray;
344 }