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