1 %top { 2 /* Include this before everything else, for various large-file definitions */ 3 #include "config.h" 4 } 5 6 /* 7 * We want a reentrant scanner. 8 */ 9 %option reentrant 10 11 /* 12 * We don't use input, so don't generate code for it. 13 */ 14 %option noinput 15 16 /* 17 * We don't use unput, so don't generate code for it. 18 */ 19 %option nounput 20 21 /* 22 * We don't read interactively from the terminal. 23 */ 24 %option never-interactive 25 26 /* 27 * We want to stop processing when we get to the end of the input. 28 */ 29 %option noyywrap 30 31 /* 32 * The type for the state we keep for a scanner. 33 */ 34 %option extra-type="Dtd_PreParse_scanner_state_t *" 35 36 /* 37 * The language we're scanning is case-insensitive. 38 */ 39 %option caseless 40 41 /* 42 * Prefix scanner routines with "Dtd_PreParse_" rather than "yy", so this 43 * scanner can coexist with other scanners. 44 */ 45 %option prefix="Dtd_PreParse_" 46 47 %option outfile="dtd_preparse.c" 48 49 /* 50 * We have to override the memory allocators so that we don't get 51 * "unused argument" warnings from the yyscanner argument (which 52 * we don't use, as we have a global memory allocator). 53 * 54 * We provide, as macros, our own versions of the routines generated by Flex, 55 * which just call malloc()/realloc()/free() (as the Flex versions do), 56 * discarding the extra argument. 57 */ 58 %option noyyalloc 59 %option noyyrealloc 60 %option noyyfree 61 62 %{ 63 /* 64 * dtd_preparse.l 65 * 66 * an XML dissector for wireshark 67 * 68 * DTD Preparser - import a dtd file into a GString 69 * including files, removing comments 70 * and resolving %entities; 71 * 72 * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org> 73 * 74 * Wireshark - Network traffic analyzer 75 * By Gerald Combs <gerald@wireshark.org> 76 * Copyright 1998 Gerald Combs 77 * 78 * This program is free software; you can redistribute it and/or 79 * modify it under the terms of the GNU General Public License 80 * as published by the Free Software Foundation; either version 2 81 * of the License, or (at your option) any later version. 82 * 83 * This program is distributed in the hope that it will be useful, 84 * but WITHOUT ANY WARRANTY; without even the implied warranty of 85 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 86 * GNU General Public License for more details. 87 * 88 * You should have received a copy of the GNU General Public License 89 * along with this program; if not, write to the Free Software 90 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 91 */ 92 93 #include <glib.h> 94 #include <string.h> 95 #include <errno.h> 96 #include <stdio.h> 97 #include "dtd.h" 98 #include <wsutil/file_util.h> 99 100 /* 101 * Disable diagnostics in the code generated by Flex. 102 */ 103 DIAG_OFF_FLEX 104 105 #define ECHO g_string_append(yyextra->current,yytext); 106 107 struct _dtd_preparse_scanner_state { 108 const gchar* dtd_dirname; 109 const gchar* filename; 110 guint linenum; 111 112 GString* error; 113 114 GHashTable* entities; 115 GString* current; 116 GString* output; 117 gchar* entity_name; 118 }; 119 120 static const gchar* replace_entity(Dtd_PreParse_scanner_state_t* state, gchar* s); 121 122 #define YY_USER_INIT { \ 123 BEGIN OUTSIDE; \ 124 } 125 126 /* 127 * Flex (v 2.5.35) uses this symbol to "exclude" unistd.h 128 */ 129 #ifdef _WIN32 130 #define YY_NO_UNISTD_H 131 #endif 132 133 /* 134 * Sleazy hack to suppress compiler warnings in yy_fatal_error(). 135 */ 136 #define YY_EXIT_FAILURE ((void)yyscanner, 2) 137 138 /* 139 * Macros for the allocators, to discard the extra argument. 140 */ 141 #define Dtd_PreParse_alloc(size, yyscanner) (void *)malloc(size) 142 #define Dtd_PreParse_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) 143 #define Dtd_PreParse_free(ptr, yyscanner) free((char *)ptr) 144 145 %} 146 xmlpi_start "<?" 147 xmlpi_stop "?>" 148 xmlpi_chars . 149 150 comment_start "<!--" 151 comment_stop "-->" 152 special_start "<!" 153 special_stop ">" 154 155 entity_start "<!"[[:blank:]\n]*entity[[:blank:]\n]*"%" 156 system SYSTEM 157 filename [^"]+ 158 159 160 name [A-Za-z][-:A-Za-z0-9_\.]* 161 162 quote "\"" 163 percent [%] 164 escaped_quote "\\\"" 165 non_quote [^"%]+ 166 167 avoid_editor_bug ["] 168 169 entity [%&][A-Za-z][-A-Za-z0-9_]*; 170 171 whitespace [[blank:]]+ 172 newline \n 173 %START OUTSIDE IN_COMMENT IN_ENTITY NAMED_ENTITY IN_QUOTE ENTITY_DONE XMLPI 174 %% 175 176 177 {entity} if (yyextra->current) g_string_append_printf(yyextra->current,"%s\n%s\n",replace_entity(yyextra, yytext),dtd_location(yyextra)); 178 179 {whitespace} if (yyextra->current) g_string_append(yyextra->current," "); 180 181 <OUTSIDE>{xmlpi_start} { g_string_append(yyextra->current,yytext); BEGIN XMLPI; } 182 <XMLPI>{xmlpi_chars} { g_string_append(yyextra->current,yytext); } 183 <XMLPI>{newline} { g_string_append(yyextra->current,yytext); } 184 <XMLPI>{xmlpi_stop} { g_string_append(yyextra->current,yytext); BEGIN OUTSIDE; } 185 186 <OUTSIDE>{comment_start} { yyextra->current = NULL; BEGIN IN_COMMENT; } 187 <IN_COMMENT>[^-]? | 188 <IN_COMMENT>[-] ; 189 <IN_COMMENT>{comment_stop} { yyextra->current = yyextra->output; BEGIN OUTSIDE; } 190 191 {newline} { 192 yyextra->linenum++; 193 if (yyextra->current) g_string_append_printf(yyextra->current,"%s\n",dtd_location(yyextra)); 194 } 195 196 197 <OUTSIDE>{entity_start} { BEGIN IN_ENTITY; } 198 <IN_ENTITY>{name} { yyextra->entity_name = g_strdup_printf("%%%s;",yytext); BEGIN NAMED_ENTITY; } 199 <NAMED_ENTITY>{quote} { yyextra->current = g_string_new(dtd_location(yyextra)); BEGIN IN_QUOTE; } 200 <IN_QUOTE>{quote} { g_hash_table_insert(yyextra->entities,yyextra->entity_name,yyextra->current); BEGIN ENTITY_DONE; } 201 <IN_QUOTE>{percent} | 202 <IN_QUOTE>{non_quote} | 203 <IN_QUOTE>{escaped_quote} g_string_append(yyextra->current,yytext); 204 <NAMED_ENTITY>{system} { 205 g_string_append_printf(yyextra->error,"at %s:%u: file inclusion is not supported!", yyextra->filename, yyextra->linenum); 206 yyterminate(); 207 } 208 <ENTITY_DONE>{special_stop} { yyextra->current = yyextra->output; g_string_append(yyextra->current,"\n"); BEGIN OUTSIDE; } 209 210 %% 211 212 /* 213 * Turn diagnostics back on, so we check the code that we've written. 214 */ 215 DIAG_ON_FLEX 216 217 static const gchar* replace_entity(Dtd_PreParse_scanner_state_t* state, gchar* entity) { 218 GString* replacement; 219 220 *entity = '%'; 221 222 replacement = (GString*)g_hash_table_lookup(state->entities,entity); 223 224 if (replacement) { 225 return replacement->str; 226 } else { 227 g_string_append_printf(state->error,"dtd_preparse: in file '%s': entity %s does not exists\n", state->filename, entity); 228 return ""; 229 } 230 231 } 232 233 const gchar* dtd_location(Dtd_PreParse_scanner_state_t* state) { 234 static gchar* loc = NULL; 235 236 g_free(loc); 237 238 if (!state) return NULL; 239 240 loc = g_strdup_printf("<? wireshark:location %s:%u ?>", state->filename, state->linenum); 241 242 return loc; 243 } 244 245 static gboolean free_gstring_hash_items(gpointer k,gpointer v,gpointer p _U_) { 246 g_free(k); 247 g_string_free((GString*)v,TRUE); 248 return TRUE; 249 } 250 251 extern GString* dtd_preparse(const gchar* dname,const gchar* fname, GString* err) { 252 gchar* fullname = g_strdup_printf("%s%c%s",dname,G_DIR_SEPARATOR,fname); 253 FILE *in; 254 yyscan_t scanner; 255 Dtd_PreParse_scanner_state_t state; 256 257 in = ws_fopen(fullname,"r"); 258 259 if (!in) { 260 if (err) 261 g_string_append_printf(err, "Could not open file: '%s', error: %s",fullname,g_strerror(errno)); 262 g_free(fullname); 263 return NULL; 264 } 265 266 if (Dtd_PreParse_lex_init(&scanner) != 0) { 267 if (err) 268 g_string_append_printf(err, "Can't initialize scanner: %s", 269 strerror(errno)); 270 fclose(in); 271 g_free(fullname); 272 return NULL; 273 } 274 275 Dtd_PreParse_set_in(in, scanner); 276 277 state.dtd_dirname = dname; 278 state.filename = fname; 279 state.linenum = 1; 280 281 state.error = err; 282 283 state.entities = g_hash_table_new(g_str_hash,g_str_equal); 284 state.current = state.output = g_string_new(dtd_location(&state)); 285 state.entity_name = NULL; 286 287 /* Associate the state with the scanner */ 288 Dtd_PreParse_set_extra(&state, scanner); 289 290 Dtd_PreParse_lex(scanner); 291 292 Dtd_PreParse_lex_destroy(scanner); 293 fclose(in); 294 295 g_hash_table_foreach_remove(state.entities,free_gstring_hash_items,NULL); 296 g_hash_table_destroy(state.entities); 297 298 g_free(fullname); 299 300 return state.output; 301 } 302