%top { /* Include this before everything else, for various large-file definitions */ #include "config.h" } /* * We want a reentrant scanner. */ %option reentrant /* * We want to generate code that can be used by a reentrant parser * generated by Bison or Berkeley YACC. */ %option bison-bridge /* * We don't read interactively from the terminal. */ %option never-interactive /* * We want to stop processing when we get to the end of the input. */ %option noyywrap /* * The type for the state we keep for the scanner (and parser). */ %option extra-type="ascend_state_t *" /* * Prefix scanner routines with "ascend" rather than "yy", so this scanner * can coexist with other scanners. */ %option prefix="ascend" /* * We have to override the memory allocators so that we don't get * "unused argument" warnings from the yyscanner argument (which * we don't use, as we have a global memory allocator). * * We provide, as macros, our own versions of the routines generated by Flex, * which just call malloc()/realloc()/free() (as the Flex versions do), * discarding the extra argument. */ %option noyyalloc %option noyyrealloc %option noyyfree %{ /* ascend_scanner.l * * Wiretap Library * Copyright (c) 1998 by Gilbert Ramirez * * SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include "wtap-int.h" #include "ascendtext.h" #include "ascend-int.h" #include "ascend.h" #include "file_wrappers.h" /* * Disable diagnostics in the code generated by Flex. */ DIAG_OFF_FLEX #define YY_INPUT(buf,result,max_size) { \ ascend_state_t *parser_state = ascendget_extra(yyscanner); \ int c = file_getc(parser_state->fh); \ if (c == EOF) { \ parser_state->err = file_error(parser_state->fh, \ &parser_state->err_info); \ if (parser_state->err == 0) \ parser_state->err = WTAP_ERR_SHORT_READ; \ result = YY_NULL; \ } else { \ buf[0] = c; \ result = 1; \ } \ } #define NO_USER "" #ifndef HAVE_UNISTD_H #define YY_NO_UNISTD_H #endif /* * Sleazy hack to suppress compiler warnings in yy_fatal_error(). */ #define YY_EXIT_FAILURE ((void)yyscanner, 2) /* * Macros for the allocators, to discard the extra argument. */ #define ascendalloc(size, yyscanner) (void *)malloc(size) #define ascendrealloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) #define ascendfree(ptr, yyscanner) free((char *)ptr) %} D [0-9] H [A-Fa-f0-9] PPP_XPFX PPP-OUT PPP_RPFX PPP-IN ISDN_XPFX PRI-XMIT- ISDN_RPFX PRI-RCV- WAN_XPFX XMIT[\-:]* WAN_RPFX RECV[\-:]* ETHER_PFX ETHER WDD_DATE "Date:" WDD_TIME "Time:" WDD_CAUSE "Cause an attempt to place call to " WDD_CALLNUM [^\n\r\t ]+ WDD_CHUNK "WD_DIALOUT_DISP: chunk" WDD_TYPE "type "[^\n\r\t ]+ %s sc_gen_task %s sc_gen_time_s %s sc_gen_time_u %s sc_gen_octets %s sc_gen_counter %s sc_gen_byte %s sc_wds_user %s sc_wds_sess %s sc_wdd_date_d %s sc_wdd_date_m %s sc_wdd_date_y %s sc_wdd_time %s sc_wdd_time_h %s sc_wdd_time_m %s sc_wdd_time_s %s sc_wdd_cause %s sc_wdd_callnum %s sc_wdd_chunk %s sc_wdd_chunknum %s sc_wdd_type %s sc_chardisp %s sc_isdn_call %s sc_ether_direction %% {ETHER_PFX} { BEGIN(sc_ether_direction); yylval->d = ASCEND_PFX_ETHER; return ETHER_PREFIX; } {ISDN_XPFX} { BEGIN(sc_isdn_call); yylval->d = ASCEND_PFX_ISDN_X; return ISDN_PREFIX; } {ISDN_RPFX} { BEGIN(sc_isdn_call); yylval->d = ASCEND_PFX_ISDN_R; return ISDN_PREFIX; } {WAN_XPFX} { BEGIN(sc_wds_user); yylval->d = ASCEND_PFX_WDS_X; return WDS_PREFIX; } {WAN_RPFX} { BEGIN(sc_wds_user); yylval->d = ASCEND_PFX_WDS_R; return WDS_PREFIX; } {PPP_XPFX} { BEGIN(sc_wds_user); yylval->d = ASCEND_PFX_WDS_X; return WDS_PREFIX; } {PPP_RPFX} { BEGIN(sc_wds_user); yylval->d = ASCEND_PFX_WDS_R; return WDS_PREFIX; } /* * If we allow an arbitrary non-zero number of non-left-parentheses after * "ETHER", that means that some file that has ETHER followed by a lot of * text (see, for example, tpncp/tpncp.dat in the source tree) can cause * either an infinite loop or a loop that take forever to finish, as the * scanner keeps swallowing characters. Limit it to 20 characters. * * XXX - any reason to require at least two of them? */ [^\(]{2,20} { BEGIN(sc_gen_task); return STRING; } /* * If we allow an arbitrary non-zero number of non-slash, non-left-parentheses, * non-colon characters after "PRI-XMIT", that means that some file that has * PRI-XMIT= followed by a lot of text can cause either an infinite loop or * a loop that take forever to finish, as the scanner keeps swallowing * characters. Limit it to 20 characters. */ [^\/\(:]{1,20} { BEGIN(sc_gen_task); return DECNUM; } [^:]{2,20} { char *atcopy = g_strdup(yytext); char colon = input(yyscanner); char after = input(yyscanner); int retval = STRING; unput(after); unput(colon); if (after != '(' && after != ' ') { BEGIN(sc_wds_sess); if (yyextra->pseudo_header != NULL) { g_strlcpy(yyextra->pseudo_header->user, atcopy, ASCEND_MAX_STR_LEN); } } else { /* We have a version 7 file */ BEGIN(sc_gen_task); if (yyextra->pseudo_header != NULL) { g_strlcpy(yyextra->pseudo_header->user, NO_USER, ASCEND_MAX_STR_LEN); } /* Are valid values ever > 2^32? If so we need to adjust YYSTYPE and a lot of */ /* upstream code accordingly. */ yylval->d = (guint32) strtoul(yytext, NULL, 10); retval = DECNUM; } g_free (atcopy); return retval; } {D}* { BEGIN(sc_gen_task); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } (0x|0X)?{H}{2,8} { BEGIN(sc_gen_time_s); yylval->d = (guint32) strtoul(yytext, NULL, 16); return HEXNUM; } \"[A-Za-z0-9_ ]+\" { return STRING; } {D}{1,10} { BEGIN(sc_gen_time_u); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {D}{1,6} { char *atcopy = g_strdup(yytext); BEGIN(sc_gen_octets); /* only want the most significant 2 digits. convert to usecs */ if (strlen(atcopy) > 2) atcopy[2] = '\0'; yylval->d = (guint32) strtoul(atcopy, NULL, 10) * 10000; g_free(atcopy); return DECNUM; } {D}{1,10} { BEGIN(sc_gen_counter); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } "["{H}{4}"]:" { BEGIN(sc_gen_byte); return COUNTER; } {H}{2} { yylval->b = (guint8)(guint32) strtoul(yytext, NULL, 16); return HEXBYTE; } " "{4} { BEGIN(sc_chardisp); } .* { BEGIN(sc_gen_byte); } {WDD_DATE} { BEGIN(sc_wdd_date_d); return WDD_DATE; } {D}{2} { BEGIN(sc_wdd_date_m); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {D}{2} { BEGIN(sc_wdd_date_y); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {D}{4} { BEGIN(sc_wdd_time); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {WDD_TIME} { BEGIN(sc_wdd_time_h); return KEYWORD; } {D}{2} { BEGIN(sc_wdd_time_m); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {D}{2} { BEGIN(sc_wdd_time_s); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {D}{2} { BEGIN(sc_wdd_cause); yylval->d = (guint32) strtoul(yytext, NULL, 10); return DECNUM; } {WDD_CAUSE} { BEGIN(sc_wdd_callnum); return KEYWORD; } {WDD_CALLNUM} { BEGIN(sc_wdd_chunk); if (yyextra->pseudo_header != NULL) { g_strlcpy(yyextra->pseudo_header->call_num, yytext, ASCEND_MAX_STR_LEN); } return STRING; } {WDD_CHUNK} { BEGIN(sc_wdd_chunknum); return WDD_CHUNK; } {H}{1,8} { BEGIN(sc_wdd_type); yylval->d = (guint32) strtoul(yytext, NULL, 16); return HEXNUM; } {WDD_TYPE} { BEGIN(sc_gen_task); return KEYWORD; } \/{D}+ { return SLASH_SUFFIX; } (0x|0X)?{H}+ { return HEXNUM; } task:|task|at|time:|octets { return KEYWORD; } <> { yyterminate(); } (.|\n) ; %% /* * Turn diagnostics back on, so we check the code that we've written. */ DIAG_ON_FLEX