%include { /* dtd_parser.lemon * XML dissector for wireshark * XML's DTD grammar * * Copyright 2005, Luis E. Garcia Ontanon * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include "dtd.h" #include "dtd_parse.h" static dtd_named_list_t* dtd_named_list_new(char* name, GPtrArray* list) { dtd_named_list_t* nl = g_new(dtd_named_list_t,1); nl->name = name; nl->list = list; return nl; } static GPtrArray* g_ptr_array_join(GPtrArray* a, GPtrArray* b){ while(b->len > 0) { g_ptr_array_add(a,g_ptr_array_remove_index_fast(b,0)); } g_ptr_array_free(b,true); return a; } DIAG_OFF_LEMON() } /* end of %include */ %code { DIAG_ON_LEMON() } %name DtdParse %extra_argument { dtd_build_data_t *bd } %token_destructor { (void) bd; /* Mark unused, similar to Q_UNUSED */ if ($$) { g_free($$->text); g_free($$->location); g_free($$); } } %syntax_error { if (!TOKEN) g_string_append_printf(bd->error,"syntax error at end of file"); else g_string_append_printf(bd->error,"syntax error in %s at or before '%s': \n", TOKEN->location,TOKEN->text); } %parse_failure { g_string_append_printf(bd->error,"DTD parsing failure\n"); } %token_prefix TOKEN_ %token_type { dtd_token_data_t* } dtd ::= doctype. dtd ::= dtd_parts. doctype ::= TAG_START DOCTYPE_KW NAME(Name) OPEN_BRACKET dtd_parts CLOSE_BRACKET TAG_STOP. { dtd_named_list_t* root; GPtrArray* root_elems = g_ptr_array_new(); unsigned i; char *name; if(! bd->proto_name) { bd->proto_name = Name->text; } g_free(bd->proto_root); bd->proto_root = Name->text; name = g_ascii_strdown(bd->proto_name, -1); g_free(bd->proto_name); bd->proto_name = name; for( i = 0; i< bd->elements->len; i++) { dtd_named_list_t* el = (dtd_named_list_t*)g_ptr_array_index(bd->elements,i); g_ptr_array_add(root_elems,g_strdup(el->name)); } root = dtd_named_list_new(g_strdup(Name->text),root_elems); g_ptr_array_add(bd->elements,root); g_free(Name->location); g_free(Name); } dtd_parts ::= dtd_parts element(Element). { g_ptr_array_add(bd->elements,Element); } dtd_parts ::= dtd_parts attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); } dtd_parts ::= element(Element). { g_ptr_array_add(bd->elements,Element); } dtd_parts ::= attlist(Attlist). { g_ptr_array_add(bd->attributes,Attlist); } %type attlist { dtd_named_list_t* } attlist(A) ::= TAG_START ATTLIST_KW NAME(B) attrib_list(TheList) TAG_STOP. { A = dtd_named_list_new(g_ascii_strdown(B->text, -1),TheList); g_free(B->text); g_free(B->location); g_free(B); } %type element { dtd_named_list_t* } element(A) ::= TAG_START ELEMENT_KW NAME(B) sub_elements(C) TAG_STOP. { A = dtd_named_list_new(g_ascii_strdown(B->text, -1),C); g_free(B->text); g_free(B->location); g_free(B); } %type attrib_list { GPtrArray* } attrib_list(A) ::= attrib_list(B) attrib(C). { g_ptr_array_add(B,C); A = B; } attrib_list(A) ::= attrib(B). { A = g_ptr_array_new(); g_ptr_array_add(A,B); } %type attrib { char* } attrib(A) ::= NAME(B) att_type att_default. { A = g_ascii_strdown(B->text, -1); g_free(B->text); g_free(B->location); g_free(B); } att_type ::= ATT_TYPE. att_type ::= enumeration. att_default ::= ATT_DEF. att_default ::= ATT_DEF_WITH_VALUE QUOTED. att_default ::= QUOTED. att_default ::= IMPLIED_KW. att_default ::= REQUIRED_KW. enumeration ::= OPEN_PARENS enum_list CLOSE_PARENS. enum_list ::= enum_list PIPE enum_item. enum_list ::= enum_item. enum_list ::= enumeration. enum_list ::= enum_list PIPE enumeration. enum_item ::= NAME. enum_item ::= QUOTED. %type sub_elements { GPtrArray* } sub_elements(A) ::= sub_elements(B) STAR. {A=B;} sub_elements(A) ::= sub_elements(B) PLUS. {A=B;} sub_elements(A) ::= sub_elements(B) QUESTION. {A=B;} sub_elements(A) ::= OPEN_PARENS ELEM_DATA CLOSE_PARENS. { A = g_ptr_array_new(); } sub_elements(A) ::= OPEN_PARENS element_list(B) COMMA ELEM_DATA CLOSE_PARENS. { A = B; } sub_elements(A) ::= OPEN_PARENS element_list(B) PIPE ELEM_DATA CLOSE_PARENS. { A = B; } sub_elements(A) ::= OPEN_PARENS element_list(B) CLOSE_PARENS. { A = B; } sub_elements(A) ::= EMPTY_KW. { A = g_ptr_array_new(); } %type element_list { GPtrArray* } element_list(A) ::= element_list(B) COMMA element_child(C). { g_ptr_array_add(B,C); A = B; } element_list(A) ::= element_list(B) PIPE element_child(C). { g_ptr_array_add(B,C); A = B; } element_list(A) ::= element_child(B). { A = g_ptr_array_new(); g_ptr_array_add(A,B); } element_list(A) ::= sub_elements(B). { A = B; } element_list(A) ::= element_list(B) COMMA sub_elements(C). { A = g_ptr_array_join(B,C); } element_list(A) ::= element_list(B) PIPE sub_elements(C). { A = g_ptr_array_join(B,C); } %type element_child { char* } element_child(A) ::= NAME(B). { A = g_ascii_strdown(B->text, -1); g_free(B->text); g_free(B->location); g_free(B); } element_child(A) ::= NAME(B) STAR. { A = g_ascii_strdown(B->text, -1); g_free(B->text); g_free(B->location); g_free(B); } element_child(A) ::= NAME(B) QUESTION. { A = g_ascii_strdown(B->text, -1); g_free(B->text); g_free(B->location); g_free(B); } element_child(A) ::= NAME(B) PLUS. { A = g_ascii_strdown(B->text, -1); g_free(B->text); g_free(B->location); g_free(B); }