One small regex change, just to be safe.
[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.5 1999/08/12 15:20:18 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-grammar.h"
57
58 static int ether_str_to_guint8_array(const char *s, guint8 *mac);
59
60 /* in dfilter-grammar.y */
61 extern GSList *dfilter_list_byte_arrays;
62
63 /* Flex has a few routines which help us get the scanner to read
64  * from a string rather than from a file. POSIX lex only provides
65  * for reading from a file; any method of reading from a string
66  * is inherently non-portable.  Besides reading from a string,
67  * we have to worry about resetting the scanner after a bad
68  * parse; this too is non-portable. Combine the reset with
69  * a string input, and you have major non-portability. I'll provide
70  * the routines for flex here. If you really want to modify the
71  * scanner and use a non-flex lex implementation, you may
72  * add more ifdef's below.
73  */
74 #ifdef FLEX_SCANNER
75
76 /* Flex has built-in support for using a string as an input source
77  * instead of using a file. Nice!
78  */
79 YY_BUFFER_STATE string_input_buffer;
80
81 #else
82
83 static char *in_buffer;
84 #undef getc
85 #define getc(fp)  (*in_buffer == 0 ? EOF : *in_buffer++)
86
87 #endif
88
89 %}
90
91 whitespace      [\t ]
92 hex             [A-Fa-f0-9]{1,2}
93 hexsep          [-:\.]
94
95 %%
96
97 [\t\n ]+        /* ignore whitespace */
98
99
100 and|\&\&        { yylval.operand = TOK_AND; return TOK_AND; }
101 or|\|\|         { yylval.operand = TOK_OR; return TOK_OR; }
102 not|\!          { yylval.operand = TOK_NOT; return TOK_NOT; }
103 xor|\^\^        { yylval.operand = TOK_XOR; return TOK_XOR; }
104 eq|\=\=         { yylval.operand = TOK_EQ; return TOK_EQ; }
105 ne|\!\=         { yylval.operand = TOK_NE; return TOK_NE; }
106 gt|\>           { yylval.operand = TOK_GT; return TOK_GT; }
107 ge|\>\=         { yylval.operand = TOK_GE; return TOK_GE; }
108 lt|\<           { yylval.operand = TOK_LT; return TOK_LT; }
109 le|\<\=         { yylval.operand = TOK_LE; return TOK_LE; }
110
111 true            { yylval.operand = TOK_TRUE; return TOK_TRUE; }
112 false           { yylval.operand = TOK_FALSE; return TOK_FALSE; }
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                 yylval.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                 yylval.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
142 ({hex}{hexsep}){1,2}{hex} {             /* small byte array */
143
144         yylval.bytes = byte_str_to_guint8_array(yytext);
145         return T_VAL_BYTES;
146 }       
147
148 ({hex}{hexsep}){3}{hex} {               /* possibly IPv4 address (e.g., 0.0.0.0) */
149
150         yylval.id = g_strdup(yytext);
151         return T_VAL_UNQUOTED_STRING;
152 }       
153
154 ({hex}{hexsep}){4}{hex} {               /* small byte array */
155
156         yylval.bytes = byte_str_to_guint8_array(yytext);
157         return T_VAL_BYTES;
158 }       
159
160 ({hex}{hexsep}){5}{hex} {               /* possibly Ether Hardware Address */
161
162         /* it's faster to copy six bytes to yylval than to create a GByteArray
163          * structure and append 6 bytes. That means I'll have to handle this
164          * overloaded meaning of 6 bytes == 1 ether in the parser (what happens
165          * when a T_VAL_ETHER is passed when an expression expects a T_VAL_BYTES?),
166          * but the speed of processing T_VAL_ETHER's makes up for the added
167          * complexity.
168          */
169         ether_str_to_guint8_array(yytext, yylval.ether);
170         return T_VAL_ETHER;
171 }       
172
173 ({hex}{hexsep}){6,}{hex} {              /* large byte array */
174
175         yylval.bytes = byte_str_to_guint8_array(yytext);
176         return T_VAL_BYTES;
177 }       
178
179 [A-Za-z][A-Za-z0-9\.\_]+        {       /* looks like a protocol or field name */
180
181         int retval = 0;
182         enum ftenum ftype;
183         yylval.variable = dfilter_lookup_token(yytext);
184         if (yylval.variable == 0) {
185                 yylval.id = g_strdup(yytext);
186                 return T_VAL_UNQUOTED_STRING;
187         }
188         
189         ftype = proto_registrar_get_ftype(yylval.variable);
190         switch (ftype) {
191                 case FT_UINT8:
192                 case FT_VALS_UINT8:
193                         retval = T_FT_UINT8;
194                         break;
195                 case FT_UINT16:
196                 case FT_VALS_UINT16:
197                         retval = T_FT_UINT16;
198                         break;
199                 case FT_UINT32:
200                 case FT_VALS_UINT32:
201                 case FT_VALS_UINT24:
202                         retval = T_FT_UINT32;
203                         break;
204                 case FT_ETHER:
205                         retval = T_FT_ETHER;
206                         break;
207                 case FT_IPv4:
208                         retval = T_FT_IPv4;
209                         break;
210                 case FT_NONE:
211                         retval = T_FT_NONE;
212                         break;
213                 case FT_BYTES:
214                         retval = T_FT_BYTES;
215                         break;
216                 case FT_BOOLEAN:
217                         retval = T_FT_BOOLEAN;
218                         break;
219                 case FT_IPXNET:
220                         retval = T_FT_IPXNET;
221                         break;
222                 default:
223                         g_assert_not_reached();
224                         retval = 0;
225                         break;
226         }
227         return retval;
228 }
229
230 [0-9]+ {                                /* decimal or octal values */
231         yylval.id = g_strdup(yytext);
232         return T_VAL_UNQUOTED_STRING;
233 }
234
235
236 0[xX][A-Fa-f0-9]+ {                     /* hex values */
237         yylval.id = g_strdup(yytext);
238         return T_VAL_UNQUOTED_STRING;
239 }
240
241 [0-9\:\.]+ {
242         yylval.id = g_strdup(yytext);
243         return T_VAL_UNQUOTED_STRING;
244 }
245
246 .       return yytext[0];
247 %%
248
249 /* Resets scanner and assigns the char* argument
250  * as the text to scan
251  */
252 void
253 dfilter_scanner_text(char *text)
254 {
255 #ifdef FLEX_SCANNER
256         string_input_buffer = yy_scan_string(text);
257 #else
258         in_buffer = text;
259 #endif
260 }
261
262 void
263 dfilter_scanner_cleanup(void)
264 {
265 #ifdef FLEX_SCANNER
266         yy_delete_buffer(string_input_buffer);
267 #else
268         /* There is no standard way to reset a lex scanner.
269          * This is necessary after a failed parse on a syntactically
270          * incorrect display filter. You have to reset the scanner
271          * so that yy_lex() doesn't start scanning from the middle
272          * of the previous input string.
273          */
274 #endif
275 }
276
277 /* Flex has an option '%option noyywrap' so that I don't have to
278  * provide this yywrap function, but in order to maintain portability,
279  * I'll just use this yywrap() function.
280  */
281 int
282 yywrap()
283 {
284         return 1; /* stop at EOF, instead of looking for next file */
285 }
286
287 /* converts a string representing an ether HW address
288  * to a guint8 array.
289  *
290  * Returns 0 on failure, 1 on success
291  */
292 static int
293 ether_str_to_guint8_array(const char *s, guint8 *mac)
294 {
295         char ether_str[18]; /* 2+1+2+1+2+1+2+1+2+1+2 + 1 */
296         char *p, *str;
297         int i = 0;
298
299         if (strlen(s) > 17) {
300                 return 0;
301         }
302         strcpy(ether_str, s); /* local copy of string */
303         str = ether_str;
304         while ((p = strtok(str, "-:."))) {
305                 mac[i] = (guint8) strtoul(p, NULL, 16);
306                 i++;
307                 /* catch short strings with too many hex bytes: 0.0.0.0.0.0.0 */
308                 if (i > 6) {
309                         break;
310                 }
311                 /* subsequent calls to strtok() require NULL as arg 1 */
312                 str = NULL;
313         }
314         return 0;
315 }
316
317 /* converts a string representing a byte array
318  * to a guint8 array.
319  *
320  * Returns a non-null GByteArray pointer on success, NULL on failure.
321  */
322 GByteArray*
323 byte_str_to_guint8_array(const char *s)
324 {
325         GByteArray      *barray;
326         guint8          val;
327         char            *byte_str = g_strdup(s); /* local copy of string */
328         char            *p, *str;
329
330         barray = g_byte_array_new();
331         dfilter_list_byte_arrays = g_slist_append(dfilter_list_byte_arrays, barray);
332
333         byte_str = g_strdup(s);
334         str = byte_str;
335         while ((p = strtok(str, "-:."))) {
336                 val = (guint8) strtoul(p, NULL, 16);
337                 g_byte_array_append(barray, &val, 1);
338
339                 /* subsequent calls to strtok() require NULL as arg 1 */
340                 str = NULL;
341         }
342
343         g_free(byte_str);
344         return barray;
345 }