%top { /* Include this before everything else, for various large-file definitions */ #include "config.h" #include } /* * We want a reentrant scanner. */ %option reentrant /* * We don't use input, so don't generate code for it. */ %option noinput /* * We don't use unput, so don't generate code for it. */ %option nounput /* * 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 a scanner. */ %option extra-type="Dtd_PreParse_scanner_state_t *" /* * The language we're scanning is case-insensitive. */ %option caseless /* * Prefix scanner routines with "Dtd_PreParse_" rather than "yy", so this * scanner can coexist with other scanners. */ %option prefix="Dtd_PreParse_" %option outfile="dtd_preparse.c" /* * 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 %{ /* * dtd_preparse.l * * an XML dissector for wireshark * * DTD Preparser - import a dtd file into a GString * including files, removing comments * and resolving %entities; * * Copyright 2004, Luis E. Garcia Ontanon * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "dtd.h" #include /* * Disable diagnostics in the code generated by Flex. */ DIAG_OFF_FLEX() #define ECHO g_string_append(yyextra->current,yytext); struct _dtd_preparse_scanner_state { const char* dtd_dirname; const char* filename; unsigned linenum; GString* error; GHashTable* entities; GString* current; GString* output; char* entity_name; }; static const char* replace_entity(Dtd_PreParse_scanner_state_t* state, char* s); #define YY_USER_INIT { \ BEGIN OUTSIDE; \ } /* * Flex (v 2.5.35) uses this symbol to "exclude" unistd.h */ #ifdef _WIN32 #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 Dtd_PreParse_alloc(size, yyscanner) (void *)malloc(size) #define Dtd_PreParse_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) #define Dtd_PreParse_free(ptr, yyscanner) free((char *)ptr) %} xmlpi_start "" xmlpi_chars . comment_start "" special_start "" entity_start "current) g_string_append_printf(yyextra->current,"%s\n%s\n",replace_entity(yyextra, yytext),dtd_location(yyextra)); {whitespace} if (yyextra->current) g_string_append(yyextra->current," "); {xmlpi_start} { g_string_append(yyextra->current,yytext); BEGIN XMLPI; } {xmlpi_chars} { g_string_append(yyextra->current,yytext); } {newline} { g_string_append(yyextra->current,yytext); } {xmlpi_stop} { g_string_append(yyextra->current,yytext); BEGIN OUTSIDE; } {comment_start} { yyextra->current = NULL; BEGIN IN_COMMENT; } [^-]? | [-] ; {comment_stop} { yyextra->current = yyextra->output; BEGIN OUTSIDE; } {newline} { yyextra->linenum++; if (yyextra->current) g_string_append_printf(yyextra->current,"%s\n",dtd_location(yyextra)); } {entity_start} { BEGIN IN_ENTITY; } {name} { yyextra->entity_name = ws_strdup_printf("%%%s;",yytext); BEGIN NAMED_ENTITY; } {quote} { yyextra->current = g_string_new(dtd_location(yyextra)); BEGIN IN_QUOTE; } {quote} { g_hash_table_insert(yyextra->entities,yyextra->entity_name,yyextra->current); BEGIN ENTITY_DONE; } {percent} | {non_quote} | {escaped_quote} g_string_append(yyextra->current,yytext); {system} { g_string_append_printf(yyextra->error,"at %s:%u: file inclusion is not supported!", yyextra->filename, yyextra->linenum); yyterminate(); } {special_stop} { yyextra->current = yyextra->output; g_string_append(yyextra->current,"\n"); BEGIN OUTSIDE; } %% /* * Turn diagnostics back on, so we check the code that we've written. */ DIAG_ON_FLEX() static const char* replace_entity(Dtd_PreParse_scanner_state_t* state, char* entity) { GString* replacement; *entity = '%'; replacement = (GString*)g_hash_table_lookup(state->entities,entity); if (replacement) { return replacement->str; } else { g_string_append_printf(state->error,"dtd_preparse: in file '%s': entity %s does not exists\n", state->filename, entity); return ""; } } const char* dtd_location(Dtd_PreParse_scanner_state_t* state) { static char* loc = NULL; g_free(loc); if (!state) return NULL; loc = ws_strdup_printf("", state->filename, state->linenum); return loc; } static gboolean free_gstring_hash_items(void *k,void *v,void *p _U_) { g_free(k); g_string_free((GString*)v,true); return true; } extern GString* dtd_preparse(const char* dname,const char* fname, GString* err) { char* fullname = ws_strdup_printf("%s%c%s",dname,G_DIR_SEPARATOR,fname); FILE *in; yyscan_t scanner; Dtd_PreParse_scanner_state_t state; in = ws_fopen(fullname,"r"); if (!in) { if (err) g_string_append_printf(err, "Could not open file: '%s', error: %s",fullname,g_strerror(errno)); g_free(fullname); return NULL; } if (Dtd_PreParse_lex_init(&scanner) != 0) { if (err) g_string_append_printf(err, "Can't initialize scanner: %s", strerror(errno)); fclose(in); g_free(fullname); return NULL; } Dtd_PreParse_set_in(in, scanner); state.dtd_dirname = dname; state.filename = fname; state.linenum = 1; state.error = err; state.entities = g_hash_table_new(g_str_hash,g_str_equal); state.current = state.output = g_string_new(dtd_location(&state)); state.entity_name = NULL; /* Associate the state with the scanner */ Dtd_PreParse_set_extra(&state, scanner); Dtd_PreParse_lex(scanner); Dtd_PreParse_lex_destroy(scanner); fclose(in); g_hash_table_foreach_remove(state.entities,free_gstring_hash_items,NULL); g_hash_table_destroy(state.entities); g_free(fullname); return state.output; }