FIXUP: WIP: verification_trailer
[wireshark-wip.git] / epan / dfilter / scanner.l
blob00e1cd2aa82018e09c1d083740b81b5bee47d631
1 /*
2  * We don't use input, so don't generate code for it.
3  */
4 %option noinput
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
12  * We don't read from the terminal.
13  */
14 %option never-interactive
17  * Prefix scanner routines with "df_" rather than "yy", so this scanner
18  * can coexist with other scanners.
19  */
20 %option prefix="df_"
24  * $Id$
25  *
26  * Wireshark - Network traffic analyzer
27  * By Gerald Combs <gerald@wireshark.org>
28  * Copyright 2001 Gerald Combs
29  *
30  * This program is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU General Public License
32  * as published by the Free Software Foundation; either version 2
33  * of the License, or (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License
41  * along with this program; if not, write to the Free Software
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
43  */
45 #include "config.h"
47 #include <stdlib.h>
48 #include <errno.h>
50 #include "dfilter-int.h"
51 #include "syntax-tree.h"
52 #include "grammar.h"
53 #include "dfunctions.h"
54 #include "scanner_lex.h"
56 #ifdef _WIN32
57 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
58 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
59 #pragma warning (disable:4018)
60 #endif
62 #define LVAL            df_lval
63 #define LVAL_TYPE       stnode_t*
64 #define LVAL_INIT_VAL   NULL
65 #define MODNAME         df
66 #define FLEX_YY_PREFIX  df_
68 #include <lemonflex-head.inc>
70 /*#undef YY_NO_UNPUT*/
72 static int set_lval(int token, gpointer data);
73 static int set_lval_int(int token, char *s);
74 static int simple(int token);
75 static gboolean str_to_gint32(char *s, gint32* pint);
76 GString* quoted_string = NULL;
77 static void mark_lval_deprecated(const char *s);
81 %x RANGE_INT
82 %x RANGE_PUNCT
83 %x DQUOTE
87 [[:blank:]\n]+  /* ignore whitespace */
91 "("                             return simple(TOKEN_LPAREN);
92 ")"                             return simple(TOKEN_RPAREN);
93 ","                             return simple(TOKEN_COMMA);
95 "=="                    return simple(TOKEN_TEST_EQ);
96 "eq"                    return simple(TOKEN_TEST_EQ);
97 "!="                    {
98         mark_lval_deprecated("!=");
99         return simple(TOKEN_TEST_NE);
101 "ne"                    {
102         mark_lval_deprecated("ne");
103         return simple(TOKEN_TEST_NE);
105 ">"                             return simple(TOKEN_TEST_GT);
106 "gt"                    return simple(TOKEN_TEST_GT);
107 ">="                    return simple(TOKEN_TEST_GE);
108 "ge"                    return simple(TOKEN_TEST_GE);
109 "<"                             return simple(TOKEN_TEST_LT);
110 "lt"                    return simple(TOKEN_TEST_LT);
111 "<="                    return simple(TOKEN_TEST_LE);
112 "le"                    return simple(TOKEN_TEST_LE);
113 "bitwise_and"   return simple(TOKEN_TEST_BITWISE_AND);
114 "&"                             return simple(TOKEN_TEST_BITWISE_AND);
115 "contains"              return simple(TOKEN_TEST_CONTAINS);
116 "~"                             return simple(TOKEN_TEST_MATCHES);
117 "matches"               return simple(TOKEN_TEST_MATCHES);
118 "!"                             return simple(TOKEN_TEST_NOT);
119 "not"                   return simple(TOKEN_TEST_NOT);
120 "&&"                    return simple(TOKEN_TEST_AND);
121 "and"                   return simple(TOKEN_TEST_AND);
122 "||"                    return simple(TOKEN_TEST_OR);
123 "or"                    return simple(TOKEN_TEST_OR);
126 "["                                     {
127         BEGIN(RANGE_INT);
128         return simple(TOKEN_LBRACKET);
131 <RANGE_INT>[+-]?[[:digit:]]+            {
132         BEGIN(RANGE_PUNCT);
133         return set_lval_int(TOKEN_INTEGER, yytext);
136 <RANGE_INT>[+-]?0x[[:xdigit:]]+         {
137         BEGIN(RANGE_PUNCT);
138         return set_lval_int(TOKEN_INTEGER, yytext);
141 <RANGE_INT,RANGE_PUNCT>":"              {
142         BEGIN(RANGE_INT);
143         return simple(TOKEN_COLON);
146 <RANGE_PUNCT>"-"                        {
147         BEGIN(RANGE_INT);
148         return simple(TOKEN_HYPHEN);
151 <RANGE_INT,RANGE_PUNCT>","              {
152         BEGIN(RANGE_INT);
153         return simple(TOKEN_COMMA);
156 <RANGE_INT,RANGE_PUNCT>"]"              {
157         BEGIN(INITIAL);
158         return simple(TOKEN_RBRACKET);
161         /* Error if none of the above while scanning a range (slice) */
163 <RANGE_PUNCT>[^:\-,\]]+         {
164         dfilter_fail("Invalid string \"%s\" found while scanning slice.", yytext);
165         return SCAN_FAILED;
168         /* XXX It would be nice to be able to match an entire non-integer string,
169          * but beware of Flex's "match the most text" rule.
170          */
172 <RANGE_INT>.    {
173         dfilter_fail("Invalid character \"%s\" found while scanning slice; expected integer.", yytext);
174         return SCAN_FAILED;
177 \042                            {
178         /* start quote */
179         /* The example of how to scan for strings was taken from
180         the flex 2.5.4 manual, from the section "Start Conditions".
181         See:
182         http://www.gnu.org/software/flex/manual/html_node/flex_11.html */
184         BEGIN(DQUOTE);
185         /* A previous filter that failed to compile due to
186         a missing end quote will have left quoted_string set
187         to something. Clear it now that we are starting
188         a new quoted string. */
189         if (quoted_string) {
190                 g_string_free(quoted_string, TRUE);
191                 /* Don't set quoted_string to NULL, as we
192                 do in other quoted_string-cleanup code, as we're
193                 about to set it in the next line. */
194         }
195         quoted_string = g_string_new("");
198 <DQUOTE><<EOF>>                         {
199         /* unterminated string */
200         /* The example of how to handle unclosed strings was taken from
201         the flex 2.5.4 manual, from the section "End-of-file rules".
202         See:
203         http://www.gnu.org/software/flex/manual/html_node/flex_13.html */
205         dfilter_fail("The final quote was missing from a quoted string.");
206         return SCAN_FAILED;
209 <DQUOTE>\042                    {
210         /* end quote */
211         int token;
212         BEGIN(INITIAL);
213         token = set_lval(TOKEN_STRING, quoted_string->str);
214         g_string_free(quoted_string, TRUE);
215         quoted_string = NULL;
216         return token;
219 <DQUOTE>\\[0-7]{1,3} {
220         /* octal sequence */
221         unsigned long result;
222         result = strtoul(yytext + 1, NULL, 8);
223         if (result > 0xff) {
224                 g_string_free(quoted_string, TRUE);
225                 quoted_string = NULL;
226                 dfilter_fail("%s is larger than 255.", yytext);
227                 return SCAN_FAILED;
228         }
229         g_string_append_c(quoted_string, (gchar) result);
232 <DQUOTE>\\x[[:xdigit:]]{1,2} {
233         /* hex sequence */
234         unsigned long result;
235         result = strtoul(yytext + 2, NULL, 16);
236         g_string_append_c(quoted_string, (gchar) result);
240 <DQUOTE>\\.                             {
241         /* escaped character */
242         g_string_append_c(quoted_string, yytext[1]);
245 <DQUOTE>[^\\\042]+                      {
246         /* non-escaped string */
247         g_string_append(quoted_string, yytext);
252 [-[:alnum:]_\.:]+\/[[:digit:]]+  {
253         /* CIDR */
254         return set_lval(TOKEN_UNPARSED, yytext);
257 [-\+[:alnum:]_.:]+      {
258         /* Is it a field name? */
259         header_field_info *hfinfo;
260         df_func_def_t *df_func_def;
262         hfinfo = proto_registrar_get_byname(yytext);
263         if (hfinfo) {
264                 /* Yes, it's a field name */
265                 return set_lval(TOKEN_FIELD, hfinfo);
266         }
267         else {
268                 /* Is it a function name? */
269                 df_func_def = df_func_lookup(yytext);
270                 if (df_func_def) {
271                     /* yes, it's a dfilter function */
272                     return set_lval(TOKEN_FUNCTION, df_func_def);
273                 }
274                 else {
275                     /* No, so treat it as an unparsed string */
276                     return set_lval(TOKEN_UNPARSED, yytext);
277                 }
278         }
281 . {
282         /* Default */
283         return set_lval(TOKEN_UNPARSED, yytext);
289 static int
290 simple(int token)
292         switch (token) {
293                 case TOKEN_LPAREN:
294                 case TOKEN_RPAREN:
295                 case TOKEN_LBRACKET:
296                 case TOKEN_RBRACKET:
297                 case TOKEN_COLON:
298                 case TOKEN_COMMA:
299                 case TOKEN_HYPHEN:
300                 case TOKEN_TEST_EQ:
301                 case TOKEN_TEST_NE:
302                 case TOKEN_TEST_GT:
303                 case TOKEN_TEST_GE:
304                 case TOKEN_TEST_LT:
305                 case TOKEN_TEST_LE:
306                 case TOKEN_TEST_BITWISE_AND:
307                 case TOKEN_TEST_CONTAINS:
308                 case TOKEN_TEST_MATCHES:
309                 case TOKEN_TEST_NOT:
310                 case TOKEN_TEST_AND:
311                 case TOKEN_TEST_OR:
312                         break;
313                 default:
314                         g_assert_not_reached();
315         }
316         return token;
319 static int
320 set_lval(int token, gpointer data)
322         sttype_id_t     type_id = STTYPE_UNINITIALIZED;
324         switch (token) {
325                 case TOKEN_STRING:
326                         type_id = STTYPE_STRING;
327                         break;
328                 case TOKEN_FIELD:
329                         type_id = STTYPE_FIELD;
330                         break;
331                 case TOKEN_UNPARSED:
332                         type_id = STTYPE_UNPARSED;
333                         break;
334                 case TOKEN_FUNCTION:
335                         type_id = STTYPE_FUNCTION;
336                         break;
337                 default:
338                         g_assert_not_reached();
339         }
340         stnode_init(df_lval, type_id, data);
341         return token;
344 static int
345 set_lval_int(int token, char *s)
347         sttype_id_t     type_id = STTYPE_UNINITIALIZED;
348         gint32          val;
350         if (!str_to_gint32(s, &val)) {
351                 return SCAN_FAILED;
352         }
354         switch (token) {
355                 case TOKEN_INTEGER:
356                         type_id = STTYPE_INTEGER;
357                         break;
358                 default:
359                         g_assert_not_reached();
360         }
362         stnode_init_int(df_lval, type_id, val);
363         return token;
367 static gboolean
368 str_to_gint32(char *s, gint32* pint)
370         char    *endptr;
371         long    integer;
373         errno = 0;
374         integer = strtol(s, &endptr, 0);
376         if (errno == EINVAL || endptr == s || *endptr != '\0') {
377                 /* This isn't a valid number. */
378                 dfilter_fail("\"%s\" is not a valid number.", s);
379                 return FALSE;
380         }
381         if (errno == ERANGE) {
382                 if (integer == LONG_MAX) {
383                         dfilter_fail("\"%s\" causes an integer overflow.", s);
384                 }
385                 else if (integer == LONG_MIN) {
386                         dfilter_fail("\"%s\" causes an integer underflow.", s);
387                 }
388                 else {
389                         /*
390                          * XXX - can "strtol()" set errno to ERANGE without
391                          * returning LONG_MAX or LONG_MIN?
392                          */
393                         dfilter_fail("\"%s\" is not an integer.", s);
394                 }
395                 return FALSE;
396         }
397         if (integer > G_MAXINT32) {
398                 /*
399                  * Fits in a long, but not in a gint32 (a long might be
400                  * 64 bits).
401                  */
402                 dfilter_fail("\"%s\" causes an integer overflow.", s);
403                 return FALSE;
404         }
405         if (integer < G_MININT32) {
406                 /*
407                  * Fits in a long, but not in a gint32 (a long might be
408                  * 64 bits).
409                  */
410                 dfilter_fail("\"%s\" causes an integer underflow.", s);
411                 return FALSE;
412         }
414         *pint = (gint32)integer;
415         return TRUE;
418 static void
419 mark_lval_deprecated(const char *s)
421         df_lval->deprecated_token = s;
424 #include <lemonflex-tail.inc>