4 * Scanner for display filters
6 * $Id: dfilter-scanner.l,v 1.5 1999/08/12 15:20:18 gram Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@zing.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
56 #include "dfilter-grammar.h"
58 static int ether_str_to_guint8_array(const char *s, guint8 *mac);
60 /* in dfilter-grammar.y */
61 extern GSList *dfilter_list_byte_arrays;
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.
76 /* Flex has built-in support for using a string as an input source
77 * instead of using a file. Nice!
79 YY_BUFFER_STATE string_input_buffer;
83 static char *in_buffer;
85 #define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++)
97 [\t\n ]+ /* ignore whitespace */
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; }
111 true { yylval.operand = TOK_TRUE; return TOK_TRUE; }
112 false { yylval.operand = TOK_FALSE; return TOK_FALSE; }
114 \[{whitespace}*-?[0-9]+{whitespace}*:{whitespace}*[0-9]+{whitespace}*\] { /* range [ x : y ] */
116 char *byterange_string = g_strdup(yytext);
117 char *s = byterange_string + 1; /* I don't want the first '[' */
120 /* Get the offset from the string */
121 if ((p = strtok(s, ":"))) {
122 yylval.byte_range.offset = strtol(p, NULL, 10);
125 g_free(byterange_string);
129 /* Get the Length from the string */
130 if ((p = strtok(NULL, "]"))) {
131 yylval.byte_range.length = strtoul(p, NULL, 10);
134 g_free(byterange_string);
137 g_free(byterange_string);
138 return T_VAL_BYTE_RANGE;
142 ({hex}{hexsep}){1,2}{hex} { /* small byte array */
144 yylval.bytes = byte_str_to_guint8_array(yytext);
148 ({hex}{hexsep}){3}{hex} { /* possibly IPv4 address (e.g., 0.0.0.0) */
150 yylval.id = g_strdup(yytext);
151 return T_VAL_UNQUOTED_STRING;
154 ({hex}{hexsep}){4}{hex} { /* small byte array */
156 yylval.bytes = byte_str_to_guint8_array(yytext);
160 ({hex}{hexsep}){5}{hex} { /* possibly Ether Hardware Address */
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
169 ether_str_to_guint8_array(yytext, yylval.ether);
173 ({hex}{hexsep}){6,}{hex} { /* large byte array */
175 yylval.bytes = byte_str_to_guint8_array(yytext);
179 [A-Za-z][A-Za-z0-9\.\_]+ { /* looks like a protocol or field name */
183 yylval.variable = dfilter_lookup_token(yytext);
184 if (yylval.variable == 0) {
185 yylval.id = g_strdup(yytext);
186 return T_VAL_UNQUOTED_STRING;
189 ftype = proto_registrar_get_ftype(yylval.variable);
197 retval = T_FT_UINT16;
202 retval = T_FT_UINT32;
217 retval = T_FT_BOOLEAN;
220 retval = T_FT_IPXNET;
223 g_assert_not_reached();
230 [0-9]+ { /* decimal or octal values */
231 yylval.id = g_strdup(yytext);
232 return T_VAL_UNQUOTED_STRING;
236 0[xX][A-Fa-f0-9]+ { /* hex values */
237 yylval.id = g_strdup(yytext);
238 return T_VAL_UNQUOTED_STRING;
242 yylval.id = g_strdup(yytext);
243 return T_VAL_UNQUOTED_STRING;
249 /* Resets scanner and assigns the char* argument
250 * as the text to scan
253 dfilter_scanner_text(char *text)
256 string_input_buffer = yy_scan_string(text);
263 dfilter_scanner_cleanup(void)
266 yy_delete_buffer(string_input_buffer);
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.
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.
284 return 1; /* stop at EOF, instead of looking for next file */
287 /* converts a string representing an ether HW address
290 * Returns 0 on failure, 1 on success
293 ether_str_to_guint8_array(const char *s, guint8 *mac)
295 char ether_str[18]; /* 2+1+2+1+2+1+2+1+2+1+2 + 1 */
299 if (strlen(s) > 17) {
302 strcpy(ether_str, s); /* local copy of string */
304 while ((p = strtok(str, "-:."))) {
305 mac[i] = (guint8) strtoul(p, NULL, 16);
307 /* catch short strings with too many hex bytes: 0.0.0.0.0.0.0 */
311 /* subsequent calls to strtok() require NULL as arg 1 */
317 /* converts a string representing a byte array
320 * Returns a non-null GByteArray pointer on success, NULL on failure.
323 byte_str_to_guint8_array(const char *s)
327 char *byte_str = g_strdup(s); /* local copy of string */
330 barray = g_byte_array_new();
331 dfilter_list_byte_arrays = g_slist_append(dfilter_list_byte_arrays, barray);
333 byte_str = g_strdup(s);
335 while ((p = strtok(str, "-:."))) {
336 val = (guint8) strtoul(p, NULL, 16);
337 g_byte_array_append(barray, &val, 1);
339 /* subsequent calls to strtok() require NULL as arg 1 */