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 * The language we're scanning is case-insensitive. 28 */ 29 %option caseless 30 31 /* 32 * We use start condition stacks. 33 */ 34 %option stack 35 36 /* 37 * We want to stop processing when we get to the end of the input. 38 */ 39 %option noyywrap 40 41 /* 42 * The type for the state we keep for a scanner. 43 */ 44 %option extra-type="DiamDict_scanner_state_t *" 45 46 /* 47 * Prefix scanner routines with "DiamDict_" rather than "yy", so this scanner 48 * can coexist with other scanners. 49 */ 50 %option prefix="DiamDict_" 51 52 %option outfile="diam_dict.c" 53 54 /* 55 * We have to override the memory allocators so that we don't get 56 * "unused argument" warnings from the yyscanner argument (which 57 * we don't use, as we have a global memory allocator). 58 * 59 * We provide, as macros, our own versions of the routines generated by Flex, 60 * which just call malloc()/realloc()/free() (as the Flex versions do), 61 * discarding the extra argument. 62 */ 63 %option noyyalloc 64 %option noyyrealloc 65 %option noyyfree 66 67 %{ 68 /* 69 ** diam_dict.h 70 ** Diameter Dictionary Import Routines 71 ** 72 ** (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org> 73 ** 74 ** This library is free software; you can redistribute it and/or 75 ** modify it under the terms of the GNU Library General Public 76 ** License as published by the Free Software Foundation; either 77 ** version 2 of the License, or (at your option) any later version. 78 ** 79 ** This library is distributed in the hope that it will be useful, 80 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 81 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 82 ** Library General Public License for more details. 83 ** 84 ** You should have received a copy of the GNU Library General Public 85 ** License along with this library; if not, write to the Free Software 86 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, 87 ** Boston, MA 02110-1301, USA. 88 ** 89 ** See draft-frascone-xml-dictionary for the syntax of the 90 ** dictionary. 91 */ 92 93 #include <glib.h> 94 #include <stdio.h> 95 #include <string.h> 96 #include <errno.h> 97 #include <stdlib.h> 98 #include <stdarg.h> 99 #include "diam_dict.h" 100 #include <epan/to_str.h> 101 #include <wsutil/file_util.h> 102 103 /* 104 * Disable diagnostics in the code generated by Flex. 105 */ 106 DIAG_OFF_FLEX 107 108 typedef struct entity_t { 109 char* name; 110 char* file; 111 struct entity_t* next; 112 } entity_t; 113 114 #define ATTR_UINT(cont) do { D(("attr_uint " #cont "\t" )); yyextra->attr_uint = &(cont); yy_push_state(GET_UINT_ATTR, yyscanner); } while(0) 115 #define ATTR_STR(cont) do { D(("attr_str " #cont "\t" )); yyextra->attr_str = &(cont); yy_push_state(GET_ATTR, yyscanner); } while(0) 116 #define IGNORE() do { D(("ignore: %s\t",yytext)); yy_push_state(IGNORE_ATTR, yyscanner); } while(0) 117 118 #define D(args) ddict_debug args 119 120 #define MAX_INCLUDE_DEPTH 10 121 #define YY_INPUT(buf,result,max_size) { result = yyextra->current_yyinput(buf,max_size,yyscanner); } 122 #define YY_USER_INIT { \ 123 DiamDict_scanner_state_t *scanner_state = DiamDict_get_extra(yyscanner); \ 124 BEGIN(scanner_state->start_state); \ 125 } 126 #define ECHO 127 #define APPEND(txt,len) append_to_buffer(txt,len,yyextra) 128 129 typedef struct { 130 const char* sys_dir; 131 132 char* write_ptr; 133 char* read_ptr; 134 135 char* strbuf; 136 unsigned size_strbuf; 137 unsigned len_strbuf; 138 139 ddict_t* dict; 140 141 ddict_application_t* appl; 142 ddict_avp_t* avp; 143 ddict_enum_t* enumitem; 144 ddict_gavp_t* gavp; 145 ddict_typedefn_t* typedefn; 146 ddict_cmd_t* cmd; 147 ddict_vendor_t* vnd; 148 ddict_xmlpi_t* xmlpi; 149 150 ddict_application_t* last_appl; 151 ddict_avp_t* last_avp; 152 ddict_enum_t* last_enumitem; 153 ddict_gavp_t* last_gavp; 154 ddict_typedefn_t* last_typedefn; 155 ddict_cmd_t* last_cmd; 156 ddict_vendor_t* last_vnd; 157 ddict_xmlpi_t* last_xmlpi; 158 159 entity_t *ents; 160 161 char** attr_str; 162 unsigned* attr_uint; 163 164 size_t (*current_yyinput)(char*,size_t,yyscan_t); 165 int (*current_close)(FILE *fh); 166 167 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; 168 int include_stack_ptr; 169 170 int start_state; 171 } DiamDict_scanner_state_t; 172 173 static void ddict_debug(const char* fmt, ...) G_GNUC_PRINTF(1, 2); 174 static void append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep); 175 static FILE* ddict_open(const char*, const char*); 176 177 /* 178 * Sleazy hack to suppress compiler warnings in yy_fatal_error(). 179 */ 180 #define YY_EXIT_FAILURE ((void)yyscanner, 2) 181 182 /* 183 * Macros for the allocators, to discard the extra argument. 184 */ 185 #define DiamDict_alloc(size, yyscanner) (void *)malloc(size) 186 #define DiamDict_realloc(ptr, size, yyscanner) (void *)realloc((char *)(ptr), (size)) 187 #define DiamDict_free(ptr, yyscanner) free((char *)ptr) 188 189 %} 190 191 192 xmlpi_start [[:blank:] \r\n]*<\?[[:blank:] \r\n]* 193 xmlpi_end [[:blank:] \r\n]*\?>[[:blank:] \r\n]* 194 xmlpi_key_attr [[:blank:] \r\n]*key[[:blank:] \r\n]*=[[:blank:] \r\n]*\042 195 xmlpi_value_attr [[:blank:] \r\n]*value[[:blank:] \r\n]*=[[:blank:] \r\n]*\042 196 197 comment_start [[:blank:] \r\n]*<!--[[:blank:] \r\n]* 198 comment_end [[:blank:] \r\n]*-->[[:blank:] \r\n]* 199 open_tag [[:blank:] \r\n]*<[[:blank:] \r\n]* 200 end_tag [[:blank:] \r\n]*\/>[[:blank:] \r\n]* 201 close_tag [[:blank:] \r\n]*>[[:blank:] \r\n]* 202 open_closetag [[:blank:] \r\n]*<\/[[:blank:] \r\n]* 203 equals [[:blank:] \r\n]*=[[:blank:] \r\n]* 204 whitespace [[:blank:] \r\n]* 205 dquoted \042[^\042]*\042 206 207 doctype [[:blank:] \r\n]*<!DOCTYPE[^\[]*\[[[:blank:] \r\n]* 208 doctype_end [[:blank:] \r\n]*\][[:blank:] \r\n]*>[[:blank:] \r\n]* 209 210 start_entity [[:blank:] \r\n]*<\!ENTITY[[:blank:] \r\n]* 211 system [[:blank:] \r\n]*SYSTEM[[:blank:] \r\n]*\042 212 entityname [a-z0-9-]+ 213 ndquot [^\042]+ 214 end_entity \042[[:blank:] \r\n]*>[[:blank:] \r\n]* 215 216 entity \&[a-z0-9-]+; 217 218 any . 219 220 221 222 223 stop > 224 stop_end \/> 225 dquot \042 226 number [-]?[0-9]* 227 228 dictionary_start <dictionary> 229 dictionary_end <\/dictionary> 230 231 base_start <base[^>*]*> 232 base_end <\/base> 233 234 application_start <application 235 application_end<\/application> 236 237 command_start <command 238 command_end<\/command> 239 240 typedefn_start <typedefn 241 242 avp_start <avp 243 avp_end <\/avp> 244 245 type_start <type 246 enum_start <enum 247 248 grouped_start <grouped> 249 grouped_end <\/grouped> 250 251 vendor_start <vendor 252 vendor_end<\/vendor> 253 254 gavp_start <gavp 255 256 ignored_attr [a-z0-9-]+= 257 ignored_quoted \042[^\042]*\042 258 259 name_attr name=\042 260 id_attr id=\042 261 code_attr code=\042 262 vendor_attr vendor-id=\042 263 typename_attr type-name=\042 264 typeparent_attr type-parent=\042 265 description_attr description=\042 266 267 268 269 %S LOADING LOADING_COMMENT LOADING_XMLPI ENTITY GET_SYSTEM GET_FILE END_ENTITY 270 %S GET_ATTR GET_UINT_ATTR END_ATTR OUTSIDE IN_DICT IN_APPL IN_AVP APPL_ATTRS IGNORE_ATTR 271 %S TYPE_ATTRS GAVP_ATTRS ENUM_ATTRS AVP_ATTRS VENDOR_ATTRS COMMAND_ATTRS TYPEDEFN_ATTRS 272 %S XMLPI_ATTRS XMLPI_GETKEY XMLPI_GETVAL XMLPI_ENDATTR 273 %% 274 <LOADING>{doctype} ; 275 <LOADING>{doctype_end} ; 276 277 <LOADING>{comment_start} BEGIN LOADING_COMMENT; 278 <LOADING_COMMENT>. ; 279 <LOADING_COMMENT>{comment_end} BEGIN LOADING; 280 281 <LOADING>{xmlpi_start} BEGIN LOADING_XMLPI; 282 <LOADING_XMLPI>{whitespace} ; 283 <LOADING_XMLPI>{entityname} { 284 yyextra->xmlpi = g_new(ddict_xmlpi_t,1); 285 yyextra->xmlpi->name = g_strdup(yytext); 286 yyextra->xmlpi->key = NULL; 287 yyextra->xmlpi->value = NULL; 288 yyextra->xmlpi->next = NULL; 289 290 if (!yyextra->dict->xmlpis) 291 yyextra->last_xmlpi = yyextra->dict->xmlpis = yyextra->xmlpi; 292 else 293 yyextra->last_xmlpi = yyextra->last_xmlpi->next = yyextra->xmlpi; 294 295 BEGIN XMLPI_ATTRS; 296 } 297 298 <XMLPI_ATTRS>{xmlpi_key_attr} BEGIN XMLPI_GETKEY; 299 <XMLPI_GETKEY>{ndquot} { yyextra->xmlpi->key = g_strdup(yytext); BEGIN XMLPI_ATTRS; } 300 301 <XMLPI_ATTRS>{xmlpi_value_attr} BEGIN XMLPI_GETVAL; 302 <XMLPI_GETVAL>{ndquot} { yyextra->xmlpi->value = g_strdup(yytext); BEGIN XMLPI_ATTRS; } 303 304 <XMLPI_ATTRS>. 305 <XMLPI_ATTRS>{xmlpi_end} BEGIN LOADING; 306 307 308 <LOADING>{start_entity} BEGIN ENTITY; 309 <ENTITY>{entityname} { 310 entity_t* e = g_new(entity_t,1); 311 e->name = g_strdup(yytext); 312 e->next = yyextra->ents; 313 yyextra->ents = e; 314 BEGIN GET_SYSTEM; 315 }; 316 <GET_SYSTEM>{system} BEGIN GET_FILE; 317 <GET_FILE>{ndquot} { 318 yyextra->ents->file = g_strdup(yytext); 319 BEGIN END_ENTITY; 320 } 321 <END_ENTITY>{end_entity} BEGIN LOADING; 322 323 <LOADING>{open_tag} APPEND("<",1); 324 325 <LOADING>{close_tag} APPEND(">",1); 326 327 <LOADING>{end_tag} APPEND("/>",2); 328 329 <LOADING>{open_closetag} APPEND("</",2); 330 331 <LOADING>{whitespace} APPEND(" ",1); 332 333 <LOADING>{dquoted} APPEND(yytext, (unsigned) yyleng); 334 335 <LOADING>{equals} APPEND("=",1); 336 337 <LOADING>{any} APPEND(yytext, (unsigned) yyleng); 338 339 <LOADING>{entity} { 340 char* p = ++yytext; 341 entity_t* e; 342 343 while(*p != ';') p++; 344 345 *p = '\0'; 346 347 D(("looking for entity: %s\n",yytext)); 348 349 if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) { 350 fprintf(stderr, "included files nested to deeply\n"); 351 yyterminate(); 352 } 353 354 for (e = yyextra->ents; e; e = e->next) { 355 if (strcmp(e->name,yytext) == 0) { 356 yyin = ddict_open(yyextra->sys_dir,e->file); 357 D(("entity: %s filename: %s yyin: %p\n",e->name,e->file,(void*)yyin)); 358 if (!yyin) { 359 if (errno) 360 fprintf(stderr, "Could not open file: '%s', error: %s\n", e->file, g_strerror(errno) ); 361 else 362 fprintf(stderr, "Could not open file: '%s', error unknown (errno == 0)\n", e->file ); 363 yyterminate(); 364 } else { 365 yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER; 366 yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner); 367 BEGIN LOADING; 368 } 369 break; 370 } 371 } 372 373 if (!e) { 374 fprintf(stderr, "Could not find entity: '%s'\n", yytext ); 375 yyterminate(); 376 } 377 378 } 379 380 <<EOF>> { 381 if (!yyin) yyterminate(); 382 383 yyextra->current_close(yyin); 384 D(("closing: %p %i\n",(void*)yyin,yyextra->include_stack_ptr)); 385 386 if ( --yyextra->include_stack_ptr < 0 ) { 387 D(("DONE READING\n")); 388 yyin = NULL; 389 yyterminate(); 390 } else { 391 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner); 392 yy_switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner); 393 BEGIN LOADING; 394 } 395 } 396 397 398 <GET_ATTR>{ndquot} { 399 *(yyextra->attr_str) = g_strdup(yytext); 400 D(("%s\n",yytext)); 401 yyextra->attr_str = NULL; 402 BEGIN END_ATTR; 403 } 404 405 <GET_UINT_ATTR>{number} { 406 *(yyextra->attr_uint) = (unsigned) strtoul(yytext,NULL,10); 407 D(("%s\n",yytext);); 408 yyextra->attr_uint = NULL; 409 BEGIN END_ATTR; 410 } 411 412 <END_ATTR>{dquot} { yy_pop_state(yyscanner); } 413 414 <IGNORE_ATTR>. { 415 /* XXX: should go?*/ 416 D(("{%s}",yytext)); 417 } 418 419 <IGNORE_ATTR>{ignored_quoted} { 420 D(("=>%s<=\n",yytext)); 421 yy_pop_state(yyscanner); 422 } 423 424 <OUTSIDE>{dictionary_start} { 425 D(("dictionary_start\n")); 426 427 BEGIN IN_DICT; 428 } 429 430 <IN_DICT>{base_start} { 431 D(("base_start\n")); 432 BEGIN IN_APPL; 433 } 434 435 <IN_DICT>{application_start} { 436 D(("application_start\n")); 437 438 yyextra->appl = g_new(ddict_application_t,1); 439 yyextra->appl->name = NULL; 440 yyextra->appl->code = 0; 441 yyextra->appl->next = NULL; 442 443 if (!yyextra->dict->applications) 444 yyextra->last_appl = yyextra->dict->applications = yyextra->appl; 445 else 446 yyextra->last_appl = yyextra->last_appl->next = yyextra->appl; 447 448 BEGIN APPL_ATTRS; 449 } 450 451 <APPL_ATTRS>{name_attr} { ATTR_STR(yyextra->appl->name); } 452 <APPL_ATTRS>{id_attr} { ATTR_UINT(yyextra->appl->code); } 453 454 <APPL_ATTRS>{stop} BEGIN IN_APPL; 455 <APPL_ATTRS>{stop_end} BEGIN IN_DICT; 456 457 <IN_APPL>{command_end} ; 458 459 <IN_APPL>{command_start} { 460 D(("command_start\n")); 461 462 yyextra->cmd = g_new(ddict_cmd_t,1); 463 yyextra->cmd->name = NULL; 464 yyextra->cmd->vendor = NULL; 465 yyextra->cmd->code = 0; 466 yyextra->cmd->next = NULL; 467 468 if (!yyextra->dict->cmds) 469 yyextra->last_cmd = yyextra->dict->cmds = yyextra->cmd; 470 else 471 yyextra->last_cmd = yyextra->last_cmd->next = yyextra->cmd; 472 473 BEGIN COMMAND_ATTRS; 474 } 475 476 <COMMAND_ATTRS>{name_attr} { ATTR_STR(yyextra->cmd->name); } 477 <COMMAND_ATTRS>{vendor_attr} { ATTR_STR(yyextra->cmd->vendor); } 478 <COMMAND_ATTRS>{code_attr} { ATTR_UINT(yyextra->cmd->code); } 479 <COMMAND_ATTRS>{stop} | 480 <COMMAND_ATTRS>{stop_end} { BEGIN IN_APPL; } 481 482 <IN_DICT>{vendor_start} { 483 D(("vendor_start\n")); 484 485 yyextra->vnd = g_new(ddict_vendor_t,1); 486 yyextra->vnd->name = NULL; 487 yyextra->vnd->code = 0; 488 yyextra->vnd->next = NULL; 489 490 if (!yyextra->dict->vendors) 491 yyextra->last_vnd = yyextra->dict->vendors = yyextra->vnd; 492 else 493 yyextra->last_vnd = yyextra->last_vnd->next = yyextra->vnd; 494 495 BEGIN VENDOR_ATTRS; 496 } 497 498 <VENDOR_ATTRS>{name_attr} { ATTR_STR(yyextra->vnd->desc); } 499 <VENDOR_ATTRS>{vendor_attr} { ATTR_STR(yyextra->vnd->name); } 500 <VENDOR_ATTRS>{code_attr} { ATTR_UINT(yyextra->vnd->code); } 501 <VENDOR_ATTRS>{stop} { BEGIN IN_APPL; } 502 <VENDOR_ATTRS>{stop_end} { BEGIN IN_DICT; } 503 504 <IN_APPL>{typedefn_start} { 505 D(("typedefn_start\n")); 506 507 yyextra->typedefn = g_new(ddict_typedefn_t,1); 508 yyextra->typedefn->name = NULL; 509 yyextra->typedefn->parent = NULL; 510 yyextra->typedefn->next = NULL; 511 512 if (!yyextra->dict->typedefns) 513 yyextra->last_typedefn = yyextra->dict->typedefns = yyextra->typedefn; 514 else 515 yyextra->last_typedefn = yyextra->last_typedefn->next = yyextra->typedefn; 516 517 BEGIN TYPEDEFN_ATTRS; 518 } 519 520 <TYPEDEFN_ATTRS>{typename_attr} { ATTR_STR(yyextra->typedefn->name); } 521 <TYPEDEFN_ATTRS>{typeparent_attr} { ATTR_STR(yyextra->typedefn->parent); } 522 <TYPEDEFN_ATTRS>{stop} | 523 <TYPEDEFN_ATTRS>{stop_end} { BEGIN IN_APPL; } 524 525 526 <IN_APPL>{avp_start} { 527 D(("avp_start\n")); 528 529 yyextra->avp = g_new(ddict_avp_t,1); 530 yyextra->avp->name = NULL; 531 yyextra->avp->description = NULL; 532 yyextra->avp->vendor = NULL; 533 yyextra->avp->code = 0; 534 yyextra->avp->type = NULL; 535 yyextra->avp->enums = NULL; 536 yyextra->avp->gavps = NULL; 537 yyextra->avp->next = NULL; 538 539 if (! yyextra->dict->avps ) 540 yyextra->last_avp = yyextra->dict->avps = yyextra->avp; 541 else 542 yyextra->last_avp = yyextra->last_avp->next = yyextra->avp; 543 544 BEGIN AVP_ATTRS; 545 } 546 547 <AVP_ATTRS>{name_attr} { ATTR_STR(yyextra->avp->name); } 548 <AVP_ATTRS>{description_attr} { ATTR_STR(yyextra->avp->description); } 549 <AVP_ATTRS>{vendor_attr} { ATTR_STR(yyextra->avp->vendor); } 550 <AVP_ATTRS>{code_attr} { ATTR_UINT(yyextra->avp->code); } 551 <AVP_ATTRS>{stop} { BEGIN IN_AVP; } 552 <AVP_ATTRS>{stop_end} { BEGIN IN_APPL; } 553 554 555 <IN_AVP>{grouped_start} { yyextra->avp->type = g_strdup("Grouped"); }; 556 <IN_AVP>{grouped_end} ; 557 558 <IN_AVP>{type_start} { BEGIN TYPE_ATTRS; } 559 <TYPE_ATTRS>{typename_attr} { ATTR_STR(yyextra->avp->type); } 560 561 <IN_AVP>{gavp_start} { 562 D(("gavp_start\n")); 563 564 yyextra->gavp = g_new(ddict_gavp_t,1); 565 yyextra->gavp->name = NULL; 566 yyextra->gavp->code = 0; 567 yyextra->gavp->next = NULL; 568 569 if (!yyextra->avp->gavps) 570 yyextra->last_gavp = yyextra->avp->gavps = yyextra->gavp; 571 else 572 yyextra->last_gavp = yyextra->last_gavp->next = yyextra->gavp; 573 574 BEGIN GAVP_ATTRS; 575 } 576 577 578 <GAVP_ATTRS>{name_attr} { ATTR_STR(yyextra->gavp->name); } 579 580 581 <IN_AVP>{enum_start} { 582 D(("enum_start\n")); 583 584 yyextra->enumitem = g_new(ddict_enum_t,1); 585 yyextra->enumitem->name = NULL; 586 yyextra->enumitem->code = 0; 587 yyextra->enumitem->next = NULL; 588 589 if (!yyextra->avp->enums) 590 yyextra->last_enumitem = yyextra->avp->enums = yyextra->enumitem; 591 else 592 yyextra->last_enumitem = yyextra->last_enumitem->next = yyextra->enumitem; 593 594 BEGIN ENUM_ATTRS; 595 } 596 597 598 <ENUM_ATTRS>{name_attr} { ATTR_STR(yyextra->enumitem->name); } 599 <ENUM_ATTRS>{code_attr} { ATTR_UINT(yyextra->enumitem->code); } 600 601 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop} { BEGIN IN_AVP; } 602 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop_end} { BEGIN IN_AVP; } 603 604 <IN_AVP>{avp_end} { D(("avp_end\n")); BEGIN IN_APPL; } 605 606 <IN_APPL>{application_end} { 607 D(("application_end\n")); BEGIN IN_DICT; 608 } 609 <IN_APPL>{stop_end} { 610 D(("application_stop_end\n")); BEGIN IN_DICT; 611 } 612 <IN_APPL>{vendor_end} { 613 D(("vendor_end\n")); BEGIN IN_DICT; 614 } 615 <IN_APPL>{base_end} { 616 D(("base_end\n")); BEGIN IN_DICT; 617 } 618 619 <IN_DICT>{dictionary_end} { 620 yyterminate(); 621 } 622 623 <AVP_ATTRS,ENUM_ATTRS,GAVP_ATTRS,TYPE_ATTRS,TYPEDEFN_ATTRS,VENDOR_ATTRS,APPL_ATTRS,COMMAND_ATTRS>{ignored_attr} IGNORE(); 624 625 <OUTSIDE>. ; 626 627 %% 628 629 /* 630 * Turn diagnostics back on, so we check the code that we've written. 631 */ 632 DIAG_ON_FLEX 633 634 static int debugging = 0; 635 636 static void ddict_debug(const char* fmt, ...) { 637 va_list ap; 638 639 va_start(ap, fmt); 640 if (debugging) vfprintf(stderr, fmt, ap); 641 va_end(ap); 642 643 fflush(stderr); 644 } 645 646 /* 647 * Sleazy hack to avoid unused function warnings for yy_top_state. 648 */ 649 extern void ddict_unused(yyscan_t yyscanner); 650 651 void 652 ddict_unused(yyscan_t yyscanner) 653 { 654 yy_top_state(yyscanner); 655 } 656 657 static void 658 append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep) 659 { 660 661 if (statep->strbuf == NULL) { 662 statep->strbuf = (char*)g_malloc(statep->size_strbuf); 663 statep->read_ptr = statep->strbuf; 664 statep->write_ptr = statep->strbuf; 665 } 666 667 if (statep->len_strbuf + len >= statep->size_strbuf) { 668 statep->strbuf = (char*)g_realloc(statep->strbuf,statep->size_strbuf *= 2); 669 statep->read_ptr = statep->strbuf; 670 } 671 672 statep->write_ptr = statep->strbuf + statep->len_strbuf; 673 memcpy(statep->write_ptr, txt, len + 1); 674 statep->len_strbuf += len; 675 } 676 677 static size_t 678 file_input(char* buf, size_t max, yyscan_t scanner) 679 { 680 FILE *in = yyget_in(scanner); 681 size_t read_cnt; 682 683 read_cnt = fread(buf,1,max,in); 684 685 if ( read_cnt == max ) { 686 return max; 687 } else if (read_cnt > 0) { 688 return read_cnt; 689 } else { 690 return YY_NULL; 691 } 692 } 693 694 695 static size_t 696 string_input(char* buf, size_t max, yyscan_t scanner) 697 { 698 DiamDict_scanner_state_t *statep = yyget_extra(scanner); 699 700 if (statep->read_ptr >= statep->write_ptr ) { 701 return YY_NULL; 702 } else if ( statep->read_ptr + max > statep->write_ptr ) { 703 max = statep->write_ptr - statep->read_ptr; 704 } 705 706 memcpy(buf,statep->read_ptr,max); 707 statep->read_ptr += max; 708 709 return max; 710 } 711 712 /* 713 * If we're reading from a string, yyin is set to stdin, and we don't 714 * want to close that. 715 */ 716 static int 717 string_close(FILE *fh _U_) 718 { 719 return 0; 720 } 721 722 static FILE * 723 ddict_open(const char* system_directory, const char* filename) 724 { 725 FILE* fh; 726 char* fname; 727 if (system_directory) { 728 fname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", 729 system_directory,filename); 730 } else { 731 fname = g_strdup(filename); 732 } 733 734 fh = ws_fopen(fname,"r"); 735 736 D(("fname: %s fh: %p\n",fname,(void*)fh)); 737 738 g_free(fname); 739 740 741 return fh; 742 } 743 744 ddict_t * 745 ddict_scan(const char* system_directory, const char* filename, int dbg) 746 { 747 DiamDict_scanner_state_t state; 748 FILE *in; 749 yyscan_t scanner; 750 751 debugging = dbg; 752 753 state.sys_dir = system_directory; 754 755 state.write_ptr = NULL; 756 state.read_ptr = NULL; 757 758 state.strbuf = NULL; 759 state.size_strbuf = 8192; 760 state.len_strbuf = 0; 761 762 state.dict = g_new(ddict_t,1); 763 state.dict->applications = NULL; 764 state.dict->vendors = NULL; 765 state.dict->cmds = NULL; 766 state.dict->typedefns = NULL; 767 state.dict->avps = NULL; 768 state.dict->xmlpis = NULL; 769 770 state.appl = NULL; 771 state.avp = NULL; 772 state.enumitem = NULL; 773 state.gavp = NULL; 774 state.typedefn = NULL; 775 state.cmd = NULL; 776 state.vnd = NULL; 777 state.xmlpi = NULL; 778 779 state.last_appl = NULL; 780 state.last_avp = NULL; 781 state.last_enumitem = NULL; 782 state.last_gavp = NULL; 783 state.last_typedefn = NULL; 784 state.last_cmd = NULL; 785 state.last_vnd = NULL; 786 state.last_xmlpi = NULL; 787 788 state.ents = NULL; 789 790 state.attr_str = NULL; 791 state.attr_uint = NULL; 792 793 /* 794 * Pass 1. 795 * 796 * Reads the file, does some work, and stores a modified version 797 * of the file contents in memory. 798 */ 799 state.current_yyinput = file_input; 800 state.current_close = fclose; 801 state.include_stack_ptr = 0; 802 803 in = ddict_open(system_directory,filename); 804 805 if (in == NULL) { 806 D(("unable to open %s: %s\n", filename, g_strerror(errno))); 807 g_free(state.dict); 808 return NULL; 809 } 810 811 if (DiamDict_lex_init(&scanner) != 0) { 812 /* Note: cannot be reached since memory allocation failure terminates early */ 813 D(("Can't initialize scanner: %s\n", g_strerror(errno))); 814 fclose(in); 815 g_free(state.dict); 816 return NULL; 817 } 818 819 DiamDict_set_in(in, scanner); 820 821 /* Associate the state with the scanner */ 822 DiamDict_set_extra(&state, scanner); 823 824 state.start_state = LOADING; 825 DiamDict_lex(scanner); 826 827 DiamDict_lex_destroy(scanner); 828 /* 829 * XXX - can the lexical analyzer terminate without closing 830 * all open input files? 831 */ 832 833 D(("\n---------------\n%s\n------- %u -------\n",state.strbuf,state.len_strbuf)); 834 835 /* 836 * Pass 2. 837 * 838 * Reads the modified version of the file contents and does the 839 * rest of the work. 840 */ 841 state.current_yyinput = string_input; 842 state.current_close = string_close; 843 844 if (DiamDict_lex_init(&scanner) != 0) { 845 /* Note: cannot be reached since memory allocation failure terminates early */ 846 D(("Can't initialize scanner: %s\n", g_strerror(errno))); 847 g_free(state.dict); 848 g_free(state.strbuf); 849 return NULL; 850 } 851 852 /* Associate the state with the scanner */ 853 DiamDict_set_extra(&state, scanner); 854 855 state.start_state = OUTSIDE; 856 DiamDict_lex(scanner); 857 858 DiamDict_lex_destroy(scanner); 859 { 860 entity_t *e, *en; 861 862 for (e = state.ents; e; e = en) { 863 en = e->next; 864 g_free(e->name); 865 g_free(e->file); 866 g_free(e); 867 } 868 } 869 g_free(state.strbuf); 870 871 return state.dict; 872 } 873 874 void 875 ddict_free(ddict_t* d) 876 { 877 ddict_application_t *p, *pn; 878 ddict_vendor_t *v, *vn; 879 ddict_cmd_t *c, *cn; 880 ddict_typedefn_t *t, *tn; 881 ddict_avp_t *a, *an; 882 ddict_xmlpi_t *x, *xn; 883 884 #define FREE_NAMEANDOBJ(n) do { g_free(n->name); g_free(n); } while(0) 885 886 for (p = d->applications; p; p = pn ) { 887 pn = p->next; 888 FREE_NAMEANDOBJ(p); 889 } 890 891 for (v = d->vendors; v; v = vn) { 892 vn = v->next; 893 g_free(v->desc); 894 FREE_NAMEANDOBJ(v); 895 } 896 897 for (c = d->cmds; c; c = cn ) { 898 cn = c->next; 899 g_free(c->vendor); 900 FREE_NAMEANDOBJ(c); 901 } 902 903 for (t = d->typedefns; t; t = tn) { 904 tn = t->next; 905 g_free(t->parent); 906 FREE_NAMEANDOBJ(t); 907 } 908 909 for (a = d->avps; a; a = an) { 910 ddict_gavp_t* g, *gn; 911 ddict_enum_t* e, *en; 912 an = a->next; 913 914 for (g = a->gavps; g; g = gn) { 915 gn = g->next; 916 FREE_NAMEANDOBJ(g); 917 } 918 919 for (e = a->enums; e; e = en) { 920 en = e->next; 921 FREE_NAMEANDOBJ(e); 922 } 923 924 g_free(a->vendor); 925 g_free(a->type); 926 g_free(a->description); 927 FREE_NAMEANDOBJ(a); 928 } 929 930 for (x = d->xmlpis; x; x = xn) { 931 xn = x->next; 932 g_free(x->key); 933 g_free(x->value); 934 FREE_NAMEANDOBJ(x); 935 } 936 937 g_free(d); 938 } 939 940 void 941 ddict_print(FILE* fh, ddict_t* d) 942 { 943 ddict_application_t* p; 944 ddict_vendor_t* v; 945 ddict_cmd_t* c; 946 ddict_typedefn_t* t; 947 ddict_avp_t* a; 948 949 950 for (p = d->applications; p; p = p->next) { 951 fprintf(fh,"Application: %s[%u]:\n", 952 p->name ? p->name : "-", 953 p->code); 954 } 955 956 for (v = d->vendors; v; v = v->next) { 957 fprintf(fh,"Vendor: %s[%u]:\n", 958 v->name ? v->name : "-", 959 v->code); 960 } 961 962 for (c = d->cmds; c; c = c->next) { 963 fprintf(fh,"Command: %s[%u] \n", 964 c->name ? c->name : "-", 965 c->code); 966 } 967 968 for (t = d->typedefns; t; t = t->next) { 969 fprintf(fh,"Type: %s -> %s \n", 970 t->name ? t->name : "-", 971 t->parent ? t->parent : "" ); 972 } 973 974 for (a = d->avps; a; a = a->next) { 975 ddict_gavp_t* g; 976 ddict_enum_t* e; 977 fprintf(fh,"AVP: %s[%u:%s] %s %s\n", 978 a->name ? a->name : "-", 979 a->code, 980 a->vendor ? a->vendor : "None", 981 a->type ? a->type : "-", 982 a->description ? a->description : ""); 983 984 for (g = a->gavps; g; g = g->next) { 985 fprintf(fh,"\tGAVP: %s\n", 986 g->name ? g->name : "-" ); 987 } 988 989 for (e = a->enums; e; e = e->next) { 990 fprintf(fh,"\tEnum: %s[%u]\n", 991 e->name ? e->name : "-", 992 e->code); 993 } 994 } 995 } 996 997 #ifdef TEST_DIAM_DICT_STANDALONE 998 int 999 main(int argc, char** argv) 1000 { 1001 ddict_t* d; 1002 char* dname = NULL; 1003 char* fname; 1004 int i = 1; 1005 1006 switch (argc) { 1007 case 3: 1008 dname = argv[i++]; 1009 case 2: 1010 fname = argv[i]; 1011 break; 1012 default: 1013 fprintf(stderr,"%s: usage [dictionary_dir] dictionary_filename\n",argv[0]); 1014 return 1; 1015 } 1016 1017 d = ddict_scan(dname,fname,1); 1018 if (d == NULL) { 1019 fprintf(stderr, "Can't open dictionary\n"); 1020 return 2; 1021 } 1022 1023 ddict_print(stdout, d); 1024 1025 return 0; 1026 } 1027 #endif 1028