15796c8dcSSimon Schubert /* Helper routines for parsing XML using Expat. 25796c8dcSSimon Schubert 3*c50c785cSJohn Marino Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 4*c50c785cSJohn Marino Free Software Foundation, Inc. 55796c8dcSSimon Schubert 65796c8dcSSimon Schubert This file is part of GDB. 75796c8dcSSimon Schubert 85796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify 95796c8dcSSimon Schubert it under the terms of the GNU General Public License as published by 105796c8dcSSimon Schubert the Free Software Foundation; either version 3 of the License, or 115796c8dcSSimon Schubert (at your option) any later version. 125796c8dcSSimon Schubert 135796c8dcSSimon Schubert This program is distributed in the hope that it will be useful, 145796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of 155796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 165796c8dcSSimon Schubert GNU General Public License for more details. 175796c8dcSSimon Schubert 185796c8dcSSimon Schubert You should have received a copy of the GNU General Public License 195796c8dcSSimon Schubert along with this program. If not, see <http://www.gnu.org/licenses/>. */ 205796c8dcSSimon Schubert 215796c8dcSSimon Schubert #include "defs.h" 225796c8dcSSimon Schubert #include "gdbcmd.h" 235796c8dcSSimon Schubert #include "exceptions.h" 245796c8dcSSimon Schubert #include "xml-support.h" 255796c8dcSSimon Schubert 265796c8dcSSimon Schubert #include "gdb_string.h" 275796c8dcSSimon Schubert #include "safe-ctype.h" 285796c8dcSSimon Schubert 295796c8dcSSimon Schubert /* Debugging flag. */ 305796c8dcSSimon Schubert static int debug_xml; 315796c8dcSSimon Schubert 325796c8dcSSimon Schubert /* The contents of this file are only useful if XML support is 335796c8dcSSimon Schubert available. */ 345796c8dcSSimon Schubert #ifdef HAVE_LIBEXPAT 355796c8dcSSimon Schubert 365796c8dcSSimon Schubert #include "gdb_expat.h" 375796c8dcSSimon Schubert 385796c8dcSSimon Schubert /* The maximum depth of <xi:include> nesting. No need to be miserly, 395796c8dcSSimon Schubert we just want to avoid running out of stack on loops. */ 405796c8dcSSimon Schubert #define MAX_XINCLUDE_DEPTH 30 415796c8dcSSimon Schubert 425796c8dcSSimon Schubert /* Simplified XML parser infrastructure. */ 435796c8dcSSimon Schubert 445796c8dcSSimon Schubert /* A parsing level -- used to keep track of the current element 455796c8dcSSimon Schubert nesting. */ 465796c8dcSSimon Schubert struct scope_level 475796c8dcSSimon Schubert { 485796c8dcSSimon Schubert /* Elements we allow at this level. */ 495796c8dcSSimon Schubert const struct gdb_xml_element *elements; 505796c8dcSSimon Schubert 515796c8dcSSimon Schubert /* The element which we are within. */ 525796c8dcSSimon Schubert const struct gdb_xml_element *element; 535796c8dcSSimon Schubert 545796c8dcSSimon Schubert /* Mask of which elements we've seen at this level (used for 555796c8dcSSimon Schubert optional and repeatable checking). */ 565796c8dcSSimon Schubert unsigned int seen; 575796c8dcSSimon Schubert 585796c8dcSSimon Schubert /* Body text accumulation. */ 595796c8dcSSimon Schubert struct obstack *body; 605796c8dcSSimon Schubert }; 615796c8dcSSimon Schubert typedef struct scope_level scope_level_s; 625796c8dcSSimon Schubert DEF_VEC_O(scope_level_s); 635796c8dcSSimon Schubert 645796c8dcSSimon Schubert /* The parser itself, and our additional state. */ 655796c8dcSSimon Schubert struct gdb_xml_parser 665796c8dcSSimon Schubert { 675796c8dcSSimon Schubert XML_Parser expat_parser; /* The underlying expat parser. */ 685796c8dcSSimon Schubert 695796c8dcSSimon Schubert const char *name; /* Name of this parser. */ 705796c8dcSSimon Schubert void *user_data; /* The user's callback data, for handlers. */ 715796c8dcSSimon Schubert 725796c8dcSSimon Schubert VEC(scope_level_s) *scopes; /* Scoping stack. */ 735796c8dcSSimon Schubert 745796c8dcSSimon Schubert struct gdb_exception error; /* A thrown error, if any. */ 755796c8dcSSimon Schubert int last_line; /* The line of the thrown error, or 0. */ 765796c8dcSSimon Schubert 775796c8dcSSimon Schubert const char *dtd_name; /* The name of the expected / default DTD, 785796c8dcSSimon Schubert if specified. */ 795796c8dcSSimon Schubert int is_xinclude; /* Are we the special <xi:include> parser? */ 805796c8dcSSimon Schubert }; 815796c8dcSSimon Schubert 825796c8dcSSimon Schubert /* Process some body text. We accumulate the text for later use; it's 835796c8dcSSimon Schubert wrong to do anything with it immediately, because a single block of 845796c8dcSSimon Schubert text might be broken up into multiple calls to this function. */ 855796c8dcSSimon Schubert 865796c8dcSSimon Schubert static void 875796c8dcSSimon Schubert gdb_xml_body_text (void *data, const XML_Char *text, int length) 885796c8dcSSimon Schubert { 895796c8dcSSimon Schubert struct gdb_xml_parser *parser = data; 905796c8dcSSimon Schubert struct scope_level *scope = VEC_last (scope_level_s, parser->scopes); 915796c8dcSSimon Schubert 925796c8dcSSimon Schubert if (parser->error.reason < 0) 935796c8dcSSimon Schubert return; 945796c8dcSSimon Schubert 955796c8dcSSimon Schubert if (scope->body == NULL) 965796c8dcSSimon Schubert { 975796c8dcSSimon Schubert scope->body = XZALLOC (struct obstack); 985796c8dcSSimon Schubert obstack_init (scope->body); 995796c8dcSSimon Schubert } 1005796c8dcSSimon Schubert 1015796c8dcSSimon Schubert obstack_grow (scope->body, text, length); 1025796c8dcSSimon Schubert } 1035796c8dcSSimon Schubert 1045796c8dcSSimon Schubert /* Issue a debugging message from one of PARSER's handlers. */ 1055796c8dcSSimon Schubert 1065796c8dcSSimon Schubert void 1075796c8dcSSimon Schubert gdb_xml_debug (struct gdb_xml_parser *parser, const char *format, ...) 1085796c8dcSSimon Schubert { 1095796c8dcSSimon Schubert int line = XML_GetCurrentLineNumber (parser->expat_parser); 1105796c8dcSSimon Schubert va_list ap; 1115796c8dcSSimon Schubert char *message; 1125796c8dcSSimon Schubert 1135796c8dcSSimon Schubert if (!debug_xml) 1145796c8dcSSimon Schubert return; 1155796c8dcSSimon Schubert 1165796c8dcSSimon Schubert va_start (ap, format); 1175796c8dcSSimon Schubert message = xstrvprintf (format, ap); 1185796c8dcSSimon Schubert if (line) 1195796c8dcSSimon Schubert fprintf_unfiltered (gdb_stderr, "%s (line %d): %s\n", 1205796c8dcSSimon Schubert parser->name, line, message); 1215796c8dcSSimon Schubert else 1225796c8dcSSimon Schubert fprintf_unfiltered (gdb_stderr, "%s: %s\n", 1235796c8dcSSimon Schubert parser->name, message); 1245796c8dcSSimon Schubert xfree (message); 1255796c8dcSSimon Schubert } 1265796c8dcSSimon Schubert 1275796c8dcSSimon Schubert /* Issue an error message from one of PARSER's handlers, and stop 1285796c8dcSSimon Schubert parsing. */ 1295796c8dcSSimon Schubert 1305796c8dcSSimon Schubert void 1315796c8dcSSimon Schubert gdb_xml_error (struct gdb_xml_parser *parser, const char *format, ...) 1325796c8dcSSimon Schubert { 1335796c8dcSSimon Schubert int line = XML_GetCurrentLineNumber (parser->expat_parser); 1345796c8dcSSimon Schubert va_list ap; 1355796c8dcSSimon Schubert 1365796c8dcSSimon Schubert parser->last_line = line; 1375796c8dcSSimon Schubert va_start (ap, format); 1385796c8dcSSimon Schubert throw_verror (XML_PARSE_ERROR, format, ap); 1395796c8dcSSimon Schubert } 1405796c8dcSSimon Schubert 141*c50c785cSJohn Marino /* Find the attribute named NAME in the set of parsed attributes 142*c50c785cSJohn Marino ATTRIBUTES. Returns NULL if not found. */ 143*c50c785cSJohn Marino 144*c50c785cSJohn Marino struct gdb_xml_value * 145*c50c785cSJohn Marino xml_find_attribute (VEC(gdb_xml_value_s) *attributes, const char *name) 146*c50c785cSJohn Marino { 147*c50c785cSJohn Marino struct gdb_xml_value *value; 148*c50c785cSJohn Marino int ix; 149*c50c785cSJohn Marino 150*c50c785cSJohn Marino for (ix = 0; VEC_iterate (gdb_xml_value_s, attributes, ix, value); ix++) 151*c50c785cSJohn Marino if (strcmp (value->name, name) == 0) 152*c50c785cSJohn Marino return value; 153*c50c785cSJohn Marino 154*c50c785cSJohn Marino return NULL; 155*c50c785cSJohn Marino } 156*c50c785cSJohn Marino 1575796c8dcSSimon Schubert /* Clean up a vector of parsed attribute values. */ 1585796c8dcSSimon Schubert 1595796c8dcSSimon Schubert static void 1605796c8dcSSimon Schubert gdb_xml_values_cleanup (void *data) 1615796c8dcSSimon Schubert { 1625796c8dcSSimon Schubert VEC(gdb_xml_value_s) **values = data; 1635796c8dcSSimon Schubert struct gdb_xml_value *value; 1645796c8dcSSimon Schubert int ix; 1655796c8dcSSimon Schubert 1665796c8dcSSimon Schubert for (ix = 0; VEC_iterate (gdb_xml_value_s, *values, ix, value); ix++) 1675796c8dcSSimon Schubert xfree (value->value); 1685796c8dcSSimon Schubert VEC_free (gdb_xml_value_s, *values); 1695796c8dcSSimon Schubert } 1705796c8dcSSimon Schubert 1715796c8dcSSimon Schubert /* Handle the start of an element. DATA is our local XML parser, NAME 1725796c8dcSSimon Schubert is the element, and ATTRS are the names and values of this 1735796c8dcSSimon Schubert element's attributes. */ 1745796c8dcSSimon Schubert 1755796c8dcSSimon Schubert static void 1765796c8dcSSimon Schubert gdb_xml_start_element (void *data, const XML_Char *name, 1775796c8dcSSimon Schubert const XML_Char **attrs) 1785796c8dcSSimon Schubert { 1795796c8dcSSimon Schubert struct gdb_xml_parser *parser = data; 1805796c8dcSSimon Schubert struct scope_level *scope; 1815796c8dcSSimon Schubert struct scope_level new_scope; 1825796c8dcSSimon Schubert const struct gdb_xml_element *element; 1835796c8dcSSimon Schubert const struct gdb_xml_attribute *attribute; 1845796c8dcSSimon Schubert VEC(gdb_xml_value_s) *attributes = NULL; 1855796c8dcSSimon Schubert unsigned int seen; 1865796c8dcSSimon Schubert struct cleanup *back_to; 1875796c8dcSSimon Schubert 1885796c8dcSSimon Schubert /* Push an error scope. If we return or throw an exception before 1895796c8dcSSimon Schubert filling this in, it will tell us to ignore children of this 1905796c8dcSSimon Schubert element. */ 1915796c8dcSSimon Schubert VEC_reserve (scope_level_s, parser->scopes, 1); 1925796c8dcSSimon Schubert scope = VEC_last (scope_level_s, parser->scopes); 1935796c8dcSSimon Schubert memset (&new_scope, 0, sizeof (new_scope)); 1945796c8dcSSimon Schubert VEC_quick_push (scope_level_s, parser->scopes, &new_scope); 1955796c8dcSSimon Schubert 1965796c8dcSSimon Schubert gdb_xml_debug (parser, _("Entering element <%s>"), name); 1975796c8dcSSimon Schubert 1985796c8dcSSimon Schubert /* Find this element in the list of the current scope's allowed 1995796c8dcSSimon Schubert children. Record that we've seen it. */ 2005796c8dcSSimon Schubert 2015796c8dcSSimon Schubert seen = 1; 2025796c8dcSSimon Schubert for (element = scope->elements; element && element->name; 2035796c8dcSSimon Schubert element++, seen <<= 1) 2045796c8dcSSimon Schubert if (strcmp (element->name, name) == 0) 2055796c8dcSSimon Schubert break; 2065796c8dcSSimon Schubert 2075796c8dcSSimon Schubert if (element == NULL || element->name == NULL) 2085796c8dcSSimon Schubert { 2095796c8dcSSimon Schubert /* If we're working on XInclude, <xi:include> can be the child 2105796c8dcSSimon Schubert of absolutely anything. Copy the previous scope's element 2115796c8dcSSimon Schubert list into the new scope even if there was no match. */ 2125796c8dcSSimon Schubert if (parser->is_xinclude) 2135796c8dcSSimon Schubert { 2145796c8dcSSimon Schubert struct scope_level *unknown_scope; 2155796c8dcSSimon Schubert 2165796c8dcSSimon Schubert XML_DefaultCurrent (parser->expat_parser); 2175796c8dcSSimon Schubert 2185796c8dcSSimon Schubert unknown_scope = VEC_last (scope_level_s, parser->scopes); 2195796c8dcSSimon Schubert unknown_scope->elements = scope->elements; 2205796c8dcSSimon Schubert return; 2215796c8dcSSimon Schubert } 2225796c8dcSSimon Schubert 2235796c8dcSSimon Schubert gdb_xml_debug (parser, _("Element <%s> unknown"), name); 2245796c8dcSSimon Schubert return; 2255796c8dcSSimon Schubert } 2265796c8dcSSimon Schubert 2275796c8dcSSimon Schubert if (!(element->flags & GDB_XML_EF_REPEATABLE) && (seen & scope->seen)) 2285796c8dcSSimon Schubert gdb_xml_error (parser, _("Element <%s> only expected once"), name); 2295796c8dcSSimon Schubert 2305796c8dcSSimon Schubert scope->seen |= seen; 2315796c8dcSSimon Schubert 2325796c8dcSSimon Schubert back_to = make_cleanup (gdb_xml_values_cleanup, &attributes); 2335796c8dcSSimon Schubert 2345796c8dcSSimon Schubert for (attribute = element->attributes; 2355796c8dcSSimon Schubert attribute != NULL && attribute->name != NULL; 2365796c8dcSSimon Schubert attribute++) 2375796c8dcSSimon Schubert { 2385796c8dcSSimon Schubert const char *val = NULL; 2395796c8dcSSimon Schubert const XML_Char **p; 2405796c8dcSSimon Schubert void *parsed_value; 2415796c8dcSSimon Schubert struct gdb_xml_value new_value; 2425796c8dcSSimon Schubert 2435796c8dcSSimon Schubert for (p = attrs; *p != NULL; p += 2) 2445796c8dcSSimon Schubert if (!strcmp (attribute->name, p[0])) 2455796c8dcSSimon Schubert { 2465796c8dcSSimon Schubert val = p[1]; 2475796c8dcSSimon Schubert break; 2485796c8dcSSimon Schubert } 2495796c8dcSSimon Schubert 2505796c8dcSSimon Schubert if (*p != NULL && val == NULL) 2515796c8dcSSimon Schubert { 2525796c8dcSSimon Schubert gdb_xml_debug (parser, _("Attribute \"%s\" missing a value"), 2535796c8dcSSimon Schubert attribute->name); 2545796c8dcSSimon Schubert continue; 2555796c8dcSSimon Schubert } 2565796c8dcSSimon Schubert 2575796c8dcSSimon Schubert if (*p == NULL && !(attribute->flags & GDB_XML_AF_OPTIONAL)) 2585796c8dcSSimon Schubert { 2595796c8dcSSimon Schubert gdb_xml_error (parser, _("Required attribute \"%s\" of " 2605796c8dcSSimon Schubert "<%s> not specified"), 2615796c8dcSSimon Schubert attribute->name, element->name); 2625796c8dcSSimon Schubert continue; 2635796c8dcSSimon Schubert } 2645796c8dcSSimon Schubert 2655796c8dcSSimon Schubert if (*p == NULL) 2665796c8dcSSimon Schubert continue; 2675796c8dcSSimon Schubert 2685796c8dcSSimon Schubert gdb_xml_debug (parser, _("Parsing attribute %s=\"%s\""), 2695796c8dcSSimon Schubert attribute->name, val); 2705796c8dcSSimon Schubert 2715796c8dcSSimon Schubert if (attribute->handler) 2725796c8dcSSimon Schubert parsed_value = attribute->handler (parser, attribute, val); 2735796c8dcSSimon Schubert else 2745796c8dcSSimon Schubert parsed_value = xstrdup (val); 2755796c8dcSSimon Schubert 2765796c8dcSSimon Schubert new_value.name = attribute->name; 2775796c8dcSSimon Schubert new_value.value = parsed_value; 2785796c8dcSSimon Schubert VEC_safe_push (gdb_xml_value_s, attributes, &new_value); 2795796c8dcSSimon Schubert } 2805796c8dcSSimon Schubert 2815796c8dcSSimon Schubert /* Check for unrecognized attributes. */ 2825796c8dcSSimon Schubert if (debug_xml) 2835796c8dcSSimon Schubert { 2845796c8dcSSimon Schubert const XML_Char **p; 2855796c8dcSSimon Schubert 2865796c8dcSSimon Schubert for (p = attrs; *p != NULL; p += 2) 2875796c8dcSSimon Schubert { 2885796c8dcSSimon Schubert for (attribute = element->attributes; 2895796c8dcSSimon Schubert attribute != NULL && attribute->name != NULL; 2905796c8dcSSimon Schubert attribute++) 2915796c8dcSSimon Schubert if (strcmp (attribute->name, *p) == 0) 2925796c8dcSSimon Schubert break; 2935796c8dcSSimon Schubert 2945796c8dcSSimon Schubert if (attribute == NULL || attribute->name == NULL) 2955796c8dcSSimon Schubert gdb_xml_debug (parser, _("Ignoring unknown attribute %s"), *p); 2965796c8dcSSimon Schubert } 2975796c8dcSSimon Schubert } 2985796c8dcSSimon Schubert 2995796c8dcSSimon Schubert /* Call the element handler if there is one. */ 3005796c8dcSSimon Schubert if (element->start_handler) 3015796c8dcSSimon Schubert element->start_handler (parser, element, parser->user_data, attributes); 3025796c8dcSSimon Schubert 3035796c8dcSSimon Schubert /* Fill in a new scope level. */ 3045796c8dcSSimon Schubert scope = VEC_last (scope_level_s, parser->scopes); 3055796c8dcSSimon Schubert scope->element = element; 3065796c8dcSSimon Schubert scope->elements = element->children; 3075796c8dcSSimon Schubert 3085796c8dcSSimon Schubert do_cleanups (back_to); 3095796c8dcSSimon Schubert } 3105796c8dcSSimon Schubert 3115796c8dcSSimon Schubert /* Wrapper for gdb_xml_start_element, to prevent throwing exceptions 3125796c8dcSSimon Schubert through expat. */ 3135796c8dcSSimon Schubert 3145796c8dcSSimon Schubert static void 3155796c8dcSSimon Schubert gdb_xml_start_element_wrapper (void *data, const XML_Char *name, 3165796c8dcSSimon Schubert const XML_Char **attrs) 3175796c8dcSSimon Schubert { 3185796c8dcSSimon Schubert struct gdb_xml_parser *parser = data; 3195796c8dcSSimon Schubert volatile struct gdb_exception ex; 3205796c8dcSSimon Schubert 3215796c8dcSSimon Schubert if (parser->error.reason < 0) 3225796c8dcSSimon Schubert return; 3235796c8dcSSimon Schubert 3245796c8dcSSimon Schubert TRY_CATCH (ex, RETURN_MASK_ALL) 3255796c8dcSSimon Schubert { 3265796c8dcSSimon Schubert gdb_xml_start_element (data, name, attrs); 3275796c8dcSSimon Schubert } 3285796c8dcSSimon Schubert if (ex.reason < 0) 3295796c8dcSSimon Schubert { 3305796c8dcSSimon Schubert parser->error = ex; 3315796c8dcSSimon Schubert #ifdef HAVE_XML_STOPPARSER 3325796c8dcSSimon Schubert XML_StopParser (parser->expat_parser, XML_FALSE); 3335796c8dcSSimon Schubert #endif 3345796c8dcSSimon Schubert } 3355796c8dcSSimon Schubert } 3365796c8dcSSimon Schubert 3375796c8dcSSimon Schubert /* Handle the end of an element. DATA is our local XML parser, and 3385796c8dcSSimon Schubert NAME is the current element. */ 3395796c8dcSSimon Schubert 3405796c8dcSSimon Schubert static void 3415796c8dcSSimon Schubert gdb_xml_end_element (void *data, const XML_Char *name) 3425796c8dcSSimon Schubert { 3435796c8dcSSimon Schubert struct gdb_xml_parser *parser = data; 3445796c8dcSSimon Schubert struct scope_level *scope = VEC_last (scope_level_s, parser->scopes); 3455796c8dcSSimon Schubert const struct gdb_xml_element *element; 3465796c8dcSSimon Schubert unsigned int seen; 3475796c8dcSSimon Schubert 3485796c8dcSSimon Schubert gdb_xml_debug (parser, _("Leaving element <%s>"), name); 3495796c8dcSSimon Schubert 3505796c8dcSSimon Schubert for (element = scope->elements, seen = 1; 3515796c8dcSSimon Schubert element != NULL && element->name != NULL; 3525796c8dcSSimon Schubert element++, seen <<= 1) 3535796c8dcSSimon Schubert if ((scope->seen & seen) == 0 3545796c8dcSSimon Schubert && (element->flags & GDB_XML_EF_OPTIONAL) == 0) 3555796c8dcSSimon Schubert gdb_xml_error (parser, _("Required element <%s> is missing"), 3565796c8dcSSimon Schubert element->name); 3575796c8dcSSimon Schubert 3585796c8dcSSimon Schubert /* Call the element processor. */ 3595796c8dcSSimon Schubert if (scope->element != NULL && scope->element->end_handler) 3605796c8dcSSimon Schubert { 3615796c8dcSSimon Schubert char *body; 3625796c8dcSSimon Schubert 3635796c8dcSSimon Schubert if (scope->body == NULL) 3645796c8dcSSimon Schubert body = ""; 3655796c8dcSSimon Schubert else 3665796c8dcSSimon Schubert { 3675796c8dcSSimon Schubert int length; 3685796c8dcSSimon Schubert 3695796c8dcSSimon Schubert length = obstack_object_size (scope->body); 3705796c8dcSSimon Schubert obstack_1grow (scope->body, '\0'); 3715796c8dcSSimon Schubert body = obstack_finish (scope->body); 3725796c8dcSSimon Schubert 3735796c8dcSSimon Schubert /* Strip leading and trailing whitespace. */ 3745796c8dcSSimon Schubert while (length > 0 && ISSPACE (body[length-1])) 3755796c8dcSSimon Schubert body[--length] = '\0'; 3765796c8dcSSimon Schubert while (*body && ISSPACE (*body)) 3775796c8dcSSimon Schubert body++; 3785796c8dcSSimon Schubert } 3795796c8dcSSimon Schubert 3805796c8dcSSimon Schubert scope->element->end_handler (parser, scope->element, parser->user_data, 3815796c8dcSSimon Schubert body); 3825796c8dcSSimon Schubert } 3835796c8dcSSimon Schubert else if (scope->element == NULL) 3845796c8dcSSimon Schubert XML_DefaultCurrent (parser->expat_parser); 3855796c8dcSSimon Schubert 3865796c8dcSSimon Schubert /* Pop the scope level. */ 3875796c8dcSSimon Schubert if (scope->body) 3885796c8dcSSimon Schubert { 3895796c8dcSSimon Schubert obstack_free (scope->body, NULL); 3905796c8dcSSimon Schubert xfree (scope->body); 3915796c8dcSSimon Schubert } 3925796c8dcSSimon Schubert VEC_pop (scope_level_s, parser->scopes); 3935796c8dcSSimon Schubert } 3945796c8dcSSimon Schubert 3955796c8dcSSimon Schubert /* Wrapper for gdb_xml_end_element, to prevent throwing exceptions 3965796c8dcSSimon Schubert through expat. */ 3975796c8dcSSimon Schubert 3985796c8dcSSimon Schubert static void 3995796c8dcSSimon Schubert gdb_xml_end_element_wrapper (void *data, const XML_Char *name) 4005796c8dcSSimon Schubert { 4015796c8dcSSimon Schubert struct gdb_xml_parser *parser = data; 4025796c8dcSSimon Schubert volatile struct gdb_exception ex; 4035796c8dcSSimon Schubert 4045796c8dcSSimon Schubert if (parser->error.reason < 0) 4055796c8dcSSimon Schubert return; 4065796c8dcSSimon Schubert 4075796c8dcSSimon Schubert TRY_CATCH (ex, RETURN_MASK_ALL) 4085796c8dcSSimon Schubert { 4095796c8dcSSimon Schubert gdb_xml_end_element (data, name); 4105796c8dcSSimon Schubert } 4115796c8dcSSimon Schubert if (ex.reason < 0) 4125796c8dcSSimon Schubert { 4135796c8dcSSimon Schubert parser->error = ex; 4145796c8dcSSimon Schubert #ifdef HAVE_XML_STOPPARSER 4155796c8dcSSimon Schubert XML_StopParser (parser->expat_parser, XML_FALSE); 4165796c8dcSSimon Schubert #endif 4175796c8dcSSimon Schubert } 4185796c8dcSSimon Schubert } 4195796c8dcSSimon Schubert 4205796c8dcSSimon Schubert /* Free a parser and all its associated state. */ 4215796c8dcSSimon Schubert 4225796c8dcSSimon Schubert static void 4235796c8dcSSimon Schubert gdb_xml_cleanup (void *arg) 4245796c8dcSSimon Schubert { 4255796c8dcSSimon Schubert struct gdb_xml_parser *parser = arg; 4265796c8dcSSimon Schubert struct scope_level *scope; 4275796c8dcSSimon Schubert int ix; 4285796c8dcSSimon Schubert 4295796c8dcSSimon Schubert XML_ParserFree (parser->expat_parser); 4305796c8dcSSimon Schubert 4315796c8dcSSimon Schubert /* Clean up the scopes. */ 4325796c8dcSSimon Schubert for (ix = 0; VEC_iterate (scope_level_s, parser->scopes, ix, scope); ix++) 4335796c8dcSSimon Schubert if (scope->body) 4345796c8dcSSimon Schubert { 4355796c8dcSSimon Schubert obstack_free (scope->body, NULL); 4365796c8dcSSimon Schubert xfree (scope->body); 4375796c8dcSSimon Schubert } 4385796c8dcSSimon Schubert VEC_free (scope_level_s, parser->scopes); 4395796c8dcSSimon Schubert 4405796c8dcSSimon Schubert xfree (parser); 4415796c8dcSSimon Schubert } 4425796c8dcSSimon Schubert 4435796c8dcSSimon Schubert /* Initialize and return a parser. Register a cleanup to destroy the 4445796c8dcSSimon Schubert parser. */ 4455796c8dcSSimon Schubert 446*c50c785cSJohn Marino static struct gdb_xml_parser * 447*c50c785cSJohn Marino gdb_xml_create_parser_and_cleanup_1 (const char *name, 4485796c8dcSSimon Schubert const struct gdb_xml_element *elements, 449*c50c785cSJohn Marino void *user_data, struct cleanup **old_chain) 4505796c8dcSSimon Schubert { 4515796c8dcSSimon Schubert struct gdb_xml_parser *parser; 4525796c8dcSSimon Schubert struct scope_level start_scope; 453*c50c785cSJohn Marino struct cleanup *dummy; 4545796c8dcSSimon Schubert 4555796c8dcSSimon Schubert /* Initialize the parser. */ 4565796c8dcSSimon Schubert parser = XZALLOC (struct gdb_xml_parser); 4575796c8dcSSimon Schubert parser->expat_parser = XML_ParserCreateNS (NULL, '!'); 4585796c8dcSSimon Schubert if (parser->expat_parser == NULL) 4595796c8dcSSimon Schubert { 4605796c8dcSSimon Schubert xfree (parser); 4615796c8dcSSimon Schubert nomem (0); 4625796c8dcSSimon Schubert } 4635796c8dcSSimon Schubert 4645796c8dcSSimon Schubert parser->name = name; 4655796c8dcSSimon Schubert 4665796c8dcSSimon Schubert parser->user_data = user_data; 4675796c8dcSSimon Schubert XML_SetUserData (parser->expat_parser, parser); 4685796c8dcSSimon Schubert 4695796c8dcSSimon Schubert /* Set the callbacks. */ 4705796c8dcSSimon Schubert XML_SetElementHandler (parser->expat_parser, gdb_xml_start_element_wrapper, 4715796c8dcSSimon Schubert gdb_xml_end_element_wrapper); 4725796c8dcSSimon Schubert XML_SetCharacterDataHandler (parser->expat_parser, gdb_xml_body_text); 4735796c8dcSSimon Schubert 4745796c8dcSSimon Schubert /* Initialize the outer scope. */ 4755796c8dcSSimon Schubert memset (&start_scope, 0, sizeof (start_scope)); 4765796c8dcSSimon Schubert start_scope.elements = elements; 4775796c8dcSSimon Schubert VEC_safe_push (scope_level_s, parser->scopes, &start_scope); 4785796c8dcSSimon Schubert 479*c50c785cSJohn Marino if (old_chain == NULL) 480*c50c785cSJohn Marino old_chain = &dummy; 4815796c8dcSSimon Schubert 482*c50c785cSJohn Marino *old_chain = make_cleanup (gdb_xml_cleanup, parser); 4835796c8dcSSimon Schubert return parser; 4845796c8dcSSimon Schubert } 4855796c8dcSSimon Schubert 486*c50c785cSJohn Marino /* Initialize and return a parser. Register a cleanup to destroy the 487*c50c785cSJohn Marino parser. */ 488*c50c785cSJohn Marino 489*c50c785cSJohn Marino struct gdb_xml_parser * 490*c50c785cSJohn Marino gdb_xml_create_parser_and_cleanup (const char *name, 491*c50c785cSJohn Marino const struct gdb_xml_element *elements, 492*c50c785cSJohn Marino void *user_data) 493*c50c785cSJohn Marino { 494*c50c785cSJohn Marino struct cleanup *old_chain; 495*c50c785cSJohn Marino 496*c50c785cSJohn Marino return gdb_xml_create_parser_and_cleanup_1 (name, elements, user_data, 497*c50c785cSJohn Marino &old_chain); 498*c50c785cSJohn Marino } 499*c50c785cSJohn Marino 5005796c8dcSSimon Schubert /* External entity handler. The only external entities we support 5015796c8dcSSimon Schubert are those compiled into GDB (we do not fetch entities from the 5025796c8dcSSimon Schubert target). */ 5035796c8dcSSimon Schubert 5045796c8dcSSimon Schubert static int XMLCALL 5055796c8dcSSimon Schubert gdb_xml_fetch_external_entity (XML_Parser expat_parser, 5065796c8dcSSimon Schubert const XML_Char *context, 5075796c8dcSSimon Schubert const XML_Char *base, 5085796c8dcSSimon Schubert const XML_Char *systemId, 5095796c8dcSSimon Schubert const XML_Char *publicId) 5105796c8dcSSimon Schubert { 5115796c8dcSSimon Schubert struct gdb_xml_parser *parser = XML_GetUserData (expat_parser); 5125796c8dcSSimon Schubert XML_Parser entity_parser; 5135796c8dcSSimon Schubert const char *text; 5145796c8dcSSimon Schubert enum XML_Status status; 5155796c8dcSSimon Schubert 5165796c8dcSSimon Schubert if (systemId == NULL) 5175796c8dcSSimon Schubert { 5185796c8dcSSimon Schubert text = fetch_xml_builtin (parser->dtd_name); 5195796c8dcSSimon Schubert if (text == NULL) 520*c50c785cSJohn Marino internal_error (__FILE__, __LINE__, 521*c50c785cSJohn Marino _("could not locate built-in DTD %s"), 5225796c8dcSSimon Schubert parser->dtd_name); 5235796c8dcSSimon Schubert } 5245796c8dcSSimon Schubert else 5255796c8dcSSimon Schubert { 5265796c8dcSSimon Schubert text = fetch_xml_builtin (systemId); 5275796c8dcSSimon Schubert if (text == NULL) 5285796c8dcSSimon Schubert return XML_STATUS_ERROR; 5295796c8dcSSimon Schubert } 5305796c8dcSSimon Schubert 5315796c8dcSSimon Schubert entity_parser = XML_ExternalEntityParserCreate (expat_parser, context, NULL); 5325796c8dcSSimon Schubert 5335796c8dcSSimon Schubert /* Don't use our handlers for the contents of the DTD. Just let expat 5345796c8dcSSimon Schubert process it. */ 5355796c8dcSSimon Schubert XML_SetElementHandler (entity_parser, NULL, NULL); 5365796c8dcSSimon Schubert XML_SetDoctypeDeclHandler (entity_parser, NULL, NULL); 5375796c8dcSSimon Schubert XML_SetXmlDeclHandler (entity_parser, NULL); 5385796c8dcSSimon Schubert XML_SetDefaultHandler (entity_parser, NULL); 5395796c8dcSSimon Schubert XML_SetUserData (entity_parser, NULL); 5405796c8dcSSimon Schubert 5415796c8dcSSimon Schubert status = XML_Parse (entity_parser, text, strlen (text), 1); 5425796c8dcSSimon Schubert 5435796c8dcSSimon Schubert XML_ParserFree (entity_parser); 5445796c8dcSSimon Schubert return status; 5455796c8dcSSimon Schubert } 5465796c8dcSSimon Schubert 5475796c8dcSSimon Schubert /* Associate DTD_NAME, which must be the name of a compiled-in DTD, 5485796c8dcSSimon Schubert with PARSER. */ 5495796c8dcSSimon Schubert 5505796c8dcSSimon Schubert void 5515796c8dcSSimon Schubert gdb_xml_use_dtd (struct gdb_xml_parser *parser, const char *dtd_name) 5525796c8dcSSimon Schubert { 5535796c8dcSSimon Schubert enum XML_Error err; 5545796c8dcSSimon Schubert 5555796c8dcSSimon Schubert parser->dtd_name = dtd_name; 5565796c8dcSSimon Schubert 5575796c8dcSSimon Schubert XML_SetParamEntityParsing (parser->expat_parser, 5585796c8dcSSimon Schubert XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); 5595796c8dcSSimon Schubert XML_SetExternalEntityRefHandler (parser->expat_parser, 5605796c8dcSSimon Schubert gdb_xml_fetch_external_entity); 5615796c8dcSSimon Schubert 5625796c8dcSSimon Schubert /* Even if no DTD is provided, use the built-in DTD anyway. */ 5635796c8dcSSimon Schubert err = XML_UseForeignDTD (parser->expat_parser, XML_TRUE); 5645796c8dcSSimon Schubert if (err != XML_ERROR_NONE) 5655796c8dcSSimon Schubert internal_error (__FILE__, __LINE__, 566*c50c785cSJohn Marino _("XML_UseForeignDTD failed: %s"), 567*c50c785cSJohn Marino XML_ErrorString (err)); 5685796c8dcSSimon Schubert } 5695796c8dcSSimon Schubert 5705796c8dcSSimon Schubert /* Invoke PARSER on BUFFER. BUFFER is the data to parse, which 5715796c8dcSSimon Schubert should be NUL-terminated. 5725796c8dcSSimon Schubert 5735796c8dcSSimon Schubert The return value is 0 for success or -1 for error. It may throw, 5745796c8dcSSimon Schubert but only if something unexpected goes wrong during parsing; parse 5755796c8dcSSimon Schubert errors will be caught, warned about, and reported as failure. */ 5765796c8dcSSimon Schubert 5775796c8dcSSimon Schubert int 5785796c8dcSSimon Schubert gdb_xml_parse (struct gdb_xml_parser *parser, const char *buffer) 5795796c8dcSSimon Schubert { 5805796c8dcSSimon Schubert enum XML_Status status; 5815796c8dcSSimon Schubert const char *error_string; 5825796c8dcSSimon Schubert 5835796c8dcSSimon Schubert gdb_xml_debug (parser, _("Starting:\n%s"), buffer); 5845796c8dcSSimon Schubert 5855796c8dcSSimon Schubert status = XML_Parse (parser->expat_parser, buffer, strlen (buffer), 1); 5865796c8dcSSimon Schubert 5875796c8dcSSimon Schubert if (status == XML_STATUS_OK && parser->error.reason == 0) 5885796c8dcSSimon Schubert return 0; 5895796c8dcSSimon Schubert 5905796c8dcSSimon Schubert if (parser->error.reason == RETURN_ERROR 5915796c8dcSSimon Schubert && parser->error.error == XML_PARSE_ERROR) 5925796c8dcSSimon Schubert { 5935796c8dcSSimon Schubert gdb_assert (parser->error.message != NULL); 5945796c8dcSSimon Schubert error_string = parser->error.message; 5955796c8dcSSimon Schubert } 5965796c8dcSSimon Schubert else if (status == XML_STATUS_ERROR) 5975796c8dcSSimon Schubert { 5985796c8dcSSimon Schubert enum XML_Error err = XML_GetErrorCode (parser->expat_parser); 599cf7f2e2dSJohn Marino 6005796c8dcSSimon Schubert error_string = XML_ErrorString (err); 6015796c8dcSSimon Schubert } 6025796c8dcSSimon Schubert else 6035796c8dcSSimon Schubert { 6045796c8dcSSimon Schubert gdb_assert (parser->error.reason < 0); 6055796c8dcSSimon Schubert throw_exception (parser->error); 6065796c8dcSSimon Schubert } 6075796c8dcSSimon Schubert 6085796c8dcSSimon Schubert if (parser->last_line != 0) 6095796c8dcSSimon Schubert warning (_("while parsing %s (at line %d): %s"), parser->name, 6105796c8dcSSimon Schubert parser->last_line, error_string); 6115796c8dcSSimon Schubert else 6125796c8dcSSimon Schubert warning (_("while parsing %s: %s"), parser->name, error_string); 6135796c8dcSSimon Schubert 6145796c8dcSSimon Schubert return -1; 6155796c8dcSSimon Schubert } 6165796c8dcSSimon Schubert 617*c50c785cSJohn Marino int 618*c50c785cSJohn Marino gdb_xml_parse_quick (const char *name, const char *dtd_name, 619*c50c785cSJohn Marino const struct gdb_xml_element *elements, 620*c50c785cSJohn Marino const char *document, void *user_data) 621*c50c785cSJohn Marino { 622*c50c785cSJohn Marino struct gdb_xml_parser *parser; 623*c50c785cSJohn Marino struct cleanup *back_to; 624*c50c785cSJohn Marino int result; 625*c50c785cSJohn Marino 626*c50c785cSJohn Marino parser = gdb_xml_create_parser_and_cleanup_1 (name, elements, 627*c50c785cSJohn Marino user_data, &back_to); 628*c50c785cSJohn Marino if (dtd_name != NULL) 629*c50c785cSJohn Marino gdb_xml_use_dtd (parser, dtd_name); 630*c50c785cSJohn Marino result = gdb_xml_parse (parser, document); 631*c50c785cSJohn Marino 632*c50c785cSJohn Marino do_cleanups (back_to); 633*c50c785cSJohn Marino 634*c50c785cSJohn Marino return result; 635*c50c785cSJohn Marino } 636*c50c785cSJohn Marino 6375796c8dcSSimon Schubert /* Parse a field VALSTR that we expect to contain an integer value. 6385796c8dcSSimon Schubert The integer is returned in *VALP. The string is parsed with an 6395796c8dcSSimon Schubert equivalent to strtoul. 6405796c8dcSSimon Schubert 6415796c8dcSSimon Schubert Returns 0 for success, -1 for error. */ 6425796c8dcSSimon Schubert 6435796c8dcSSimon Schubert static int 6445796c8dcSSimon Schubert xml_parse_unsigned_integer (const char *valstr, ULONGEST *valp) 6455796c8dcSSimon Schubert { 6465796c8dcSSimon Schubert const char *endptr; 6475796c8dcSSimon Schubert ULONGEST result; 6485796c8dcSSimon Schubert 6495796c8dcSSimon Schubert if (*valstr == '\0') 6505796c8dcSSimon Schubert return -1; 6515796c8dcSSimon Schubert 6525796c8dcSSimon Schubert result = strtoulst (valstr, &endptr, 0); 6535796c8dcSSimon Schubert if (*endptr != '\0') 6545796c8dcSSimon Schubert return -1; 6555796c8dcSSimon Schubert 6565796c8dcSSimon Schubert *valp = result; 6575796c8dcSSimon Schubert return 0; 6585796c8dcSSimon Schubert } 6595796c8dcSSimon Schubert 6605796c8dcSSimon Schubert /* Parse an integer string into a ULONGEST and return it, or call 6615796c8dcSSimon Schubert gdb_xml_error if it could not be parsed. */ 6625796c8dcSSimon Schubert 6635796c8dcSSimon Schubert ULONGEST 6645796c8dcSSimon Schubert gdb_xml_parse_ulongest (struct gdb_xml_parser *parser, const char *value) 6655796c8dcSSimon Schubert { 6665796c8dcSSimon Schubert ULONGEST result; 6675796c8dcSSimon Schubert 6685796c8dcSSimon Schubert if (xml_parse_unsigned_integer (value, &result) != 0) 6695796c8dcSSimon Schubert gdb_xml_error (parser, _("Can't convert \"%s\" to an integer"), value); 6705796c8dcSSimon Schubert 6715796c8dcSSimon Schubert return result; 6725796c8dcSSimon Schubert } 6735796c8dcSSimon Schubert 6745796c8dcSSimon Schubert /* Parse an integer attribute into a ULONGEST. */ 6755796c8dcSSimon Schubert 6765796c8dcSSimon Schubert void * 6775796c8dcSSimon Schubert gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser, 6785796c8dcSSimon Schubert const struct gdb_xml_attribute *attribute, 6795796c8dcSSimon Schubert const char *value) 6805796c8dcSSimon Schubert { 6815796c8dcSSimon Schubert ULONGEST result; 6825796c8dcSSimon Schubert void *ret; 6835796c8dcSSimon Schubert 6845796c8dcSSimon Schubert if (xml_parse_unsigned_integer (value, &result) != 0) 6855796c8dcSSimon Schubert gdb_xml_error (parser, _("Can't convert %s=\"%s\" to an integer"), 6865796c8dcSSimon Schubert attribute->name, value); 6875796c8dcSSimon Schubert 6885796c8dcSSimon Schubert ret = xmalloc (sizeof (result)); 6895796c8dcSSimon Schubert memcpy (ret, &result, sizeof (result)); 6905796c8dcSSimon Schubert return ret; 6915796c8dcSSimon Schubert } 6925796c8dcSSimon Schubert 6935796c8dcSSimon Schubert /* A handler_data for yes/no boolean values. */ 6945796c8dcSSimon Schubert 6955796c8dcSSimon Schubert const struct gdb_xml_enum gdb_xml_enums_boolean[] = { 6965796c8dcSSimon Schubert { "yes", 1 }, 6975796c8dcSSimon Schubert { "no", 0 }, 6985796c8dcSSimon Schubert { NULL, 0 } 6995796c8dcSSimon Schubert }; 7005796c8dcSSimon Schubert 7015796c8dcSSimon Schubert /* Map NAME to VALUE. A struct gdb_xml_enum * should be saved as the 7025796c8dcSSimon Schubert value of handler_data when using gdb_xml_parse_attr_enum to parse a 7035796c8dcSSimon Schubert fixed list of possible strings. The list is terminated by an entry 7045796c8dcSSimon Schubert with NAME == NULL. */ 7055796c8dcSSimon Schubert 7065796c8dcSSimon Schubert void * 7075796c8dcSSimon Schubert gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser, 7085796c8dcSSimon Schubert const struct gdb_xml_attribute *attribute, 7095796c8dcSSimon Schubert const char *value) 7105796c8dcSSimon Schubert { 7115796c8dcSSimon Schubert const struct gdb_xml_enum *enums = attribute->handler_data; 7125796c8dcSSimon Schubert void *ret; 7135796c8dcSSimon Schubert 7145796c8dcSSimon Schubert for (enums = attribute->handler_data; enums->name != NULL; enums++) 7155796c8dcSSimon Schubert if (strcasecmp (enums->name, value) == 0) 7165796c8dcSSimon Schubert break; 7175796c8dcSSimon Schubert 7185796c8dcSSimon Schubert if (enums->name == NULL) 7195796c8dcSSimon Schubert gdb_xml_error (parser, _("Unknown attribute value %s=\"%s\""), 7205796c8dcSSimon Schubert attribute->name, value); 7215796c8dcSSimon Schubert 7225796c8dcSSimon Schubert ret = xmalloc (sizeof (enums->value)); 7235796c8dcSSimon Schubert memcpy (ret, &enums->value, sizeof (enums->value)); 7245796c8dcSSimon Schubert return ret; 7255796c8dcSSimon Schubert } 7265796c8dcSSimon Schubert 7275796c8dcSSimon Schubert 7285796c8dcSSimon Schubert /* XInclude processing. This is done as a separate step from actually 7295796c8dcSSimon Schubert parsing the document, so that we can produce a single combined XML 7305796c8dcSSimon Schubert document - e.g. to hand to a front end or to simplify comparing two 7315796c8dcSSimon Schubert documents. We make extensive use of XML_DefaultCurrent, to pass 7325796c8dcSSimon Schubert input text directly into the output without reformatting or 7335796c8dcSSimon Schubert requoting it. 7345796c8dcSSimon Schubert 7355796c8dcSSimon Schubert We output the DOCTYPE declaration for the first document unchanged, 7365796c8dcSSimon Schubert if present, and discard DOCTYPEs from included documents. Only the 7375796c8dcSSimon Schubert one we pass through here is used when we feed the result back to 7385796c8dcSSimon Schubert expat. The XInclude standard explicitly does not discuss 7395796c8dcSSimon Schubert validation of the result; we choose to apply the same DTD applied 7405796c8dcSSimon Schubert to the outermost document. 7415796c8dcSSimon Schubert 7425796c8dcSSimon Schubert We can not simply include the external DTD subset in the document 7435796c8dcSSimon Schubert as an internal subset, because <!IGNORE> and <!INCLUDE> are valid 7445796c8dcSSimon Schubert only in external subsets. But if we do not pass the DTD into the 7455796c8dcSSimon Schubert output at all, default values will not be filled in. 7465796c8dcSSimon Schubert 7475796c8dcSSimon Schubert We don't pass through any <?xml> declaration because we generate 7485796c8dcSSimon Schubert UTF-8, not whatever the input encoding was. */ 7495796c8dcSSimon Schubert 7505796c8dcSSimon Schubert struct xinclude_parsing_data 7515796c8dcSSimon Schubert { 7525796c8dcSSimon Schubert /* The obstack to build the output in. */ 7535796c8dcSSimon Schubert struct obstack obstack; 7545796c8dcSSimon Schubert 7555796c8dcSSimon Schubert /* A count indicating whether we are in an element whose 7565796c8dcSSimon Schubert children should not be copied to the output, and if so, 7575796c8dcSSimon Schubert how deep we are nested. This is used for anything inside 7585796c8dcSSimon Schubert an xi:include, and for the DTD. */ 7595796c8dcSSimon Schubert int skip_depth; 7605796c8dcSSimon Schubert 7615796c8dcSSimon Schubert /* The number of <xi:include> elements currently being processed, 7625796c8dcSSimon Schubert to detect loops. */ 7635796c8dcSSimon Schubert int include_depth; 7645796c8dcSSimon Schubert 7655796c8dcSSimon Schubert /* A function to call to obtain additional features, and its 7665796c8dcSSimon Schubert baton. */ 7675796c8dcSSimon Schubert xml_fetch_another fetcher; 7685796c8dcSSimon Schubert void *fetcher_baton; 7695796c8dcSSimon Schubert }; 7705796c8dcSSimon Schubert 7715796c8dcSSimon Schubert static void 7725796c8dcSSimon Schubert xinclude_start_include (struct gdb_xml_parser *parser, 7735796c8dcSSimon Schubert const struct gdb_xml_element *element, 7745796c8dcSSimon Schubert void *user_data, VEC(gdb_xml_value_s) *attributes) 7755796c8dcSSimon Schubert { 7765796c8dcSSimon Schubert struct xinclude_parsing_data *data = user_data; 777*c50c785cSJohn Marino char *href = xml_find_attribute (attributes, "href")->value; 7785796c8dcSSimon Schubert struct cleanup *back_to; 7795796c8dcSSimon Schubert char *text, *output; 7805796c8dcSSimon Schubert 7815796c8dcSSimon Schubert gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href); 7825796c8dcSSimon Schubert 7835796c8dcSSimon Schubert if (data->include_depth > MAX_XINCLUDE_DEPTH) 7845796c8dcSSimon Schubert gdb_xml_error (parser, _("Maximum XInclude depth (%d) exceeded"), 7855796c8dcSSimon Schubert MAX_XINCLUDE_DEPTH); 7865796c8dcSSimon Schubert 7875796c8dcSSimon Schubert text = data->fetcher (href, data->fetcher_baton); 7885796c8dcSSimon Schubert if (text == NULL) 7895796c8dcSSimon Schubert gdb_xml_error (parser, _("Could not load XML document \"%s\""), href); 7905796c8dcSSimon Schubert back_to = make_cleanup (xfree, text); 7915796c8dcSSimon Schubert 7925796c8dcSSimon Schubert output = xml_process_xincludes (parser->name, text, data->fetcher, 7935796c8dcSSimon Schubert data->fetcher_baton, 7945796c8dcSSimon Schubert data->include_depth + 1); 7955796c8dcSSimon Schubert if (output == NULL) 7965796c8dcSSimon Schubert gdb_xml_error (parser, _("Parsing \"%s\" failed"), href); 7975796c8dcSSimon Schubert 7985796c8dcSSimon Schubert obstack_grow (&data->obstack, output, strlen (output)); 7995796c8dcSSimon Schubert xfree (output); 8005796c8dcSSimon Schubert 8015796c8dcSSimon Schubert do_cleanups (back_to); 8025796c8dcSSimon Schubert 8035796c8dcSSimon Schubert data->skip_depth++; 8045796c8dcSSimon Schubert } 8055796c8dcSSimon Schubert 8065796c8dcSSimon Schubert static void 8075796c8dcSSimon Schubert xinclude_end_include (struct gdb_xml_parser *parser, 8085796c8dcSSimon Schubert const struct gdb_xml_element *element, 8095796c8dcSSimon Schubert void *user_data, const char *body_text) 8105796c8dcSSimon Schubert { 8115796c8dcSSimon Schubert struct xinclude_parsing_data *data = user_data; 8125796c8dcSSimon Schubert 8135796c8dcSSimon Schubert data->skip_depth--; 8145796c8dcSSimon Schubert } 8155796c8dcSSimon Schubert 8165796c8dcSSimon Schubert static void XMLCALL 8175796c8dcSSimon Schubert xml_xinclude_default (void *data_, const XML_Char *s, int len) 8185796c8dcSSimon Schubert { 8195796c8dcSSimon Schubert struct gdb_xml_parser *parser = data_; 8205796c8dcSSimon Schubert struct xinclude_parsing_data *data = parser->user_data; 8215796c8dcSSimon Schubert 8225796c8dcSSimon Schubert /* If we are inside of e.g. xi:include or the DTD, don't save this 8235796c8dcSSimon Schubert string. */ 8245796c8dcSSimon Schubert if (data->skip_depth) 8255796c8dcSSimon Schubert return; 8265796c8dcSSimon Schubert 8275796c8dcSSimon Schubert /* Otherwise just add it to the end of the document we're building 8285796c8dcSSimon Schubert up. */ 8295796c8dcSSimon Schubert obstack_grow (&data->obstack, s, len); 8305796c8dcSSimon Schubert } 8315796c8dcSSimon Schubert 8325796c8dcSSimon Schubert static void XMLCALL 8335796c8dcSSimon Schubert xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName, 8345796c8dcSSimon Schubert const XML_Char *sysid, const XML_Char *pubid, 8355796c8dcSSimon Schubert int has_internal_subset) 8365796c8dcSSimon Schubert { 8375796c8dcSSimon Schubert struct gdb_xml_parser *parser = data_; 8385796c8dcSSimon Schubert struct xinclude_parsing_data *data = parser->user_data; 8395796c8dcSSimon Schubert 8405796c8dcSSimon Schubert /* Don't print out the doctype, or the contents of the DTD internal 8415796c8dcSSimon Schubert subset, if any. */ 8425796c8dcSSimon Schubert data->skip_depth++; 8435796c8dcSSimon Schubert } 8445796c8dcSSimon Schubert 8455796c8dcSSimon Schubert static void XMLCALL 8465796c8dcSSimon Schubert xml_xinclude_end_doctype (void *data_) 8475796c8dcSSimon Schubert { 8485796c8dcSSimon Schubert struct gdb_xml_parser *parser = data_; 8495796c8dcSSimon Schubert struct xinclude_parsing_data *data = parser->user_data; 8505796c8dcSSimon Schubert 8515796c8dcSSimon Schubert data->skip_depth--; 8525796c8dcSSimon Schubert } 8535796c8dcSSimon Schubert 8545796c8dcSSimon Schubert static void XMLCALL 8555796c8dcSSimon Schubert xml_xinclude_xml_decl (void *data_, const XML_Char *version, 8565796c8dcSSimon Schubert const XML_Char *encoding, int standalone) 8575796c8dcSSimon Schubert { 8585796c8dcSSimon Schubert /* Do nothing - this function prevents the default handler from 8595796c8dcSSimon Schubert being called, thus suppressing the XML declaration from the 8605796c8dcSSimon Schubert output. */ 8615796c8dcSSimon Schubert } 8625796c8dcSSimon Schubert 8635796c8dcSSimon Schubert static void 8645796c8dcSSimon Schubert xml_xinclude_cleanup (void *data_) 8655796c8dcSSimon Schubert { 8665796c8dcSSimon Schubert struct xinclude_parsing_data *data = data_; 8675796c8dcSSimon Schubert 8685796c8dcSSimon Schubert obstack_free (&data->obstack, NULL); 8695796c8dcSSimon Schubert xfree (data); 8705796c8dcSSimon Schubert } 8715796c8dcSSimon Schubert 8725796c8dcSSimon Schubert const struct gdb_xml_attribute xinclude_attributes[] = { 8735796c8dcSSimon Schubert { "href", GDB_XML_AF_NONE, NULL, NULL }, 8745796c8dcSSimon Schubert { NULL, GDB_XML_AF_NONE, NULL, NULL } 8755796c8dcSSimon Schubert }; 8765796c8dcSSimon Schubert 8775796c8dcSSimon Schubert const struct gdb_xml_element xinclude_elements[] = { 8785796c8dcSSimon Schubert { "http://www.w3.org/2001/XInclude!include", xinclude_attributes, NULL, 8795796c8dcSSimon Schubert GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, 8805796c8dcSSimon Schubert xinclude_start_include, xinclude_end_include }, 8815796c8dcSSimon Schubert { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 8825796c8dcSSimon Schubert }; 8835796c8dcSSimon Schubert 8845796c8dcSSimon Schubert /* The main entry point for <xi:include> processing. */ 8855796c8dcSSimon Schubert 8865796c8dcSSimon Schubert char * 8875796c8dcSSimon Schubert xml_process_xincludes (const char *name, const char *text, 8885796c8dcSSimon Schubert xml_fetch_another fetcher, void *fetcher_baton, 8895796c8dcSSimon Schubert int depth) 8905796c8dcSSimon Schubert { 8915796c8dcSSimon Schubert struct gdb_xml_parser *parser; 8925796c8dcSSimon Schubert struct xinclude_parsing_data *data; 8935796c8dcSSimon Schubert struct cleanup *back_to; 8945796c8dcSSimon Schubert char *result = NULL; 8955796c8dcSSimon Schubert 8965796c8dcSSimon Schubert data = XZALLOC (struct xinclude_parsing_data); 8975796c8dcSSimon Schubert obstack_init (&data->obstack); 8985796c8dcSSimon Schubert back_to = make_cleanup (xml_xinclude_cleanup, data); 8995796c8dcSSimon Schubert 9005796c8dcSSimon Schubert parser = gdb_xml_create_parser_and_cleanup (name, xinclude_elements, data); 9015796c8dcSSimon Schubert parser->is_xinclude = 1; 9025796c8dcSSimon Schubert 9035796c8dcSSimon Schubert data->include_depth = depth; 9045796c8dcSSimon Schubert data->fetcher = fetcher; 9055796c8dcSSimon Schubert data->fetcher_baton = fetcher_baton; 9065796c8dcSSimon Schubert 9075796c8dcSSimon Schubert XML_SetCharacterDataHandler (parser->expat_parser, NULL); 9085796c8dcSSimon Schubert XML_SetDefaultHandler (parser->expat_parser, xml_xinclude_default); 9095796c8dcSSimon Schubert 9105796c8dcSSimon Schubert /* Always discard the XML version declarations; the only important 9115796c8dcSSimon Schubert thing this provides is encoding, and our result will have been 9125796c8dcSSimon Schubert converted to UTF-8. */ 9135796c8dcSSimon Schubert XML_SetXmlDeclHandler (parser->expat_parser, xml_xinclude_xml_decl); 9145796c8dcSSimon Schubert 9155796c8dcSSimon Schubert if (depth > 0) 9165796c8dcSSimon Schubert /* Discard the doctype for included documents. */ 9175796c8dcSSimon Schubert XML_SetDoctypeDeclHandler (parser->expat_parser, 9185796c8dcSSimon Schubert xml_xinclude_start_doctype, 9195796c8dcSSimon Schubert xml_xinclude_end_doctype); 9205796c8dcSSimon Schubert 9215796c8dcSSimon Schubert gdb_xml_use_dtd (parser, "xinclude.dtd"); 9225796c8dcSSimon Schubert 9235796c8dcSSimon Schubert if (gdb_xml_parse (parser, text) == 0) 9245796c8dcSSimon Schubert { 9255796c8dcSSimon Schubert obstack_1grow (&data->obstack, '\0'); 9265796c8dcSSimon Schubert result = xstrdup (obstack_finish (&data->obstack)); 9275796c8dcSSimon Schubert 9285796c8dcSSimon Schubert if (depth == 0) 9295796c8dcSSimon Schubert gdb_xml_debug (parser, _("XInclude processing succeeded.")); 9305796c8dcSSimon Schubert } 9315796c8dcSSimon Schubert else 9325796c8dcSSimon Schubert result = NULL; 9335796c8dcSSimon Schubert 9345796c8dcSSimon Schubert do_cleanups (back_to); 9355796c8dcSSimon Schubert return result; 9365796c8dcSSimon Schubert } 9375796c8dcSSimon Schubert #endif /* HAVE_LIBEXPAT */ 9385796c8dcSSimon Schubert 9395796c8dcSSimon Schubert 9405796c8dcSSimon Schubert /* Return an XML document which was compiled into GDB, from 9415796c8dcSSimon Schubert the given FILENAME, or NULL if the file was not compiled in. */ 9425796c8dcSSimon Schubert 9435796c8dcSSimon Schubert const char * 9445796c8dcSSimon Schubert fetch_xml_builtin (const char *filename) 9455796c8dcSSimon Schubert { 9465796c8dcSSimon Schubert const char *(*p)[2]; 9475796c8dcSSimon Schubert 9485796c8dcSSimon Schubert for (p = xml_builtin; (*p)[0]; p++) 9495796c8dcSSimon Schubert if (strcmp ((*p)[0], filename) == 0) 9505796c8dcSSimon Schubert return (*p)[1]; 9515796c8dcSSimon Schubert 9525796c8dcSSimon Schubert return NULL; 9535796c8dcSSimon Schubert } 9545796c8dcSSimon Schubert 9555796c8dcSSimon Schubert /* A to_xfer_partial helper function which reads XML files which were 9565796c8dcSSimon Schubert compiled into GDB. The target may call this function from its own 9575796c8dcSSimon Schubert to_xfer_partial handler, after converting object and annex to the 9585796c8dcSSimon Schubert appropriate filename. */ 9595796c8dcSSimon Schubert 9605796c8dcSSimon Schubert LONGEST 9615796c8dcSSimon Schubert xml_builtin_xfer_partial (const char *filename, 9625796c8dcSSimon Schubert gdb_byte *readbuf, const gdb_byte *writebuf, 9635796c8dcSSimon Schubert ULONGEST offset, LONGEST len) 9645796c8dcSSimon Schubert { 9655796c8dcSSimon Schubert const char *buf; 9665796c8dcSSimon Schubert LONGEST len_avail; 9675796c8dcSSimon Schubert 9685796c8dcSSimon Schubert gdb_assert (readbuf != NULL && writebuf == NULL); 9695796c8dcSSimon Schubert gdb_assert (filename != NULL); 9705796c8dcSSimon Schubert 9715796c8dcSSimon Schubert buf = fetch_xml_builtin (filename); 9725796c8dcSSimon Schubert if (buf == NULL) 9735796c8dcSSimon Schubert return -1; 9745796c8dcSSimon Schubert 9755796c8dcSSimon Schubert len_avail = strlen (buf); 9765796c8dcSSimon Schubert if (offset >= len_avail) 9775796c8dcSSimon Schubert return 0; 9785796c8dcSSimon Schubert 9795796c8dcSSimon Schubert if (len > len_avail - offset) 9805796c8dcSSimon Schubert len = len_avail - offset; 9815796c8dcSSimon Schubert memcpy (readbuf, buf + offset, len); 9825796c8dcSSimon Schubert return len; 9835796c8dcSSimon Schubert } 9845796c8dcSSimon Schubert 9855796c8dcSSimon Schubert 9865796c8dcSSimon Schubert static void 9875796c8dcSSimon Schubert show_debug_xml (struct ui_file *file, int from_tty, 9885796c8dcSSimon Schubert struct cmd_list_element *c, const char *value) 9895796c8dcSSimon Schubert { 9905796c8dcSSimon Schubert fprintf_filtered (file, _("XML debugging is %s.\n"), value); 9915796c8dcSSimon Schubert } 9925796c8dcSSimon Schubert 9935796c8dcSSimon Schubert /* Return a malloc allocated string with special characters from TEXT 9945796c8dcSSimon Schubert replaced by entity references. */ 9955796c8dcSSimon Schubert 9965796c8dcSSimon Schubert char * 9975796c8dcSSimon Schubert xml_escape_text (const char *text) 9985796c8dcSSimon Schubert { 9995796c8dcSSimon Schubert char *result; 10005796c8dcSSimon Schubert int i, special; 10015796c8dcSSimon Schubert 10025796c8dcSSimon Schubert /* Compute the length of the result. */ 10035796c8dcSSimon Schubert for (i = 0, special = 0; text[i] != '\0'; i++) 10045796c8dcSSimon Schubert switch (text[i]) 10055796c8dcSSimon Schubert { 10065796c8dcSSimon Schubert case '\'': 10075796c8dcSSimon Schubert case '\"': 10085796c8dcSSimon Schubert special += 5; 10095796c8dcSSimon Schubert break; 10105796c8dcSSimon Schubert case '&': 10115796c8dcSSimon Schubert special += 4; 10125796c8dcSSimon Schubert break; 10135796c8dcSSimon Schubert case '<': 10145796c8dcSSimon Schubert case '>': 10155796c8dcSSimon Schubert special += 3; 10165796c8dcSSimon Schubert break; 10175796c8dcSSimon Schubert default: 10185796c8dcSSimon Schubert break; 10195796c8dcSSimon Schubert } 10205796c8dcSSimon Schubert 10215796c8dcSSimon Schubert /* Expand the result. */ 10225796c8dcSSimon Schubert result = xmalloc (i + special + 1); 10235796c8dcSSimon Schubert for (i = 0, special = 0; text[i] != '\0'; i++) 10245796c8dcSSimon Schubert switch (text[i]) 10255796c8dcSSimon Schubert { 10265796c8dcSSimon Schubert case '\'': 10275796c8dcSSimon Schubert strcpy (result + i + special, "'"); 10285796c8dcSSimon Schubert special += 5; 10295796c8dcSSimon Schubert break; 10305796c8dcSSimon Schubert case '\"': 10315796c8dcSSimon Schubert strcpy (result + i + special, """); 10325796c8dcSSimon Schubert special += 5; 10335796c8dcSSimon Schubert break; 10345796c8dcSSimon Schubert case '&': 10355796c8dcSSimon Schubert strcpy (result + i + special, "&"); 10365796c8dcSSimon Schubert special += 4; 10375796c8dcSSimon Schubert break; 10385796c8dcSSimon Schubert case '<': 10395796c8dcSSimon Schubert strcpy (result + i + special, "<"); 10405796c8dcSSimon Schubert special += 3; 10415796c8dcSSimon Schubert break; 10425796c8dcSSimon Schubert case '>': 10435796c8dcSSimon Schubert strcpy (result + i + special, ">"); 10445796c8dcSSimon Schubert special += 3; 10455796c8dcSSimon Schubert break; 10465796c8dcSSimon Schubert default: 10475796c8dcSSimon Schubert result[i + special] = text[i]; 10485796c8dcSSimon Schubert break; 10495796c8dcSSimon Schubert } 10505796c8dcSSimon Schubert result[i + special] = '\0'; 10515796c8dcSSimon Schubert 10525796c8dcSSimon Schubert return result; 10535796c8dcSSimon Schubert } 10545796c8dcSSimon Schubert 10555796c8dcSSimon Schubert void 10565796c8dcSSimon Schubert obstack_xml_printf (struct obstack *obstack, const char *format, ...) 10575796c8dcSSimon Schubert { 10585796c8dcSSimon Schubert va_list ap; 10595796c8dcSSimon Schubert const char *f; 10605796c8dcSSimon Schubert const char *prev; 10615796c8dcSSimon Schubert int percent = 0; 10625796c8dcSSimon Schubert 10635796c8dcSSimon Schubert va_start (ap, format); 10645796c8dcSSimon Schubert 10655796c8dcSSimon Schubert prev = format; 10665796c8dcSSimon Schubert for (f = format; *f; f++) 10675796c8dcSSimon Schubert { 10685796c8dcSSimon Schubert if (percent) 10695796c8dcSSimon Schubert { 10705796c8dcSSimon Schubert switch (*f) 10715796c8dcSSimon Schubert { 10725796c8dcSSimon Schubert case 's': 10735796c8dcSSimon Schubert { 10745796c8dcSSimon Schubert char *p; 10755796c8dcSSimon Schubert char *a = va_arg (ap, char *); 1076cf7f2e2dSJohn Marino 10775796c8dcSSimon Schubert obstack_grow (obstack, prev, f - prev - 1); 10785796c8dcSSimon Schubert p = xml_escape_text (a); 10795796c8dcSSimon Schubert obstack_grow_str (obstack, p); 10805796c8dcSSimon Schubert xfree (p); 10815796c8dcSSimon Schubert prev = f + 1; 10825796c8dcSSimon Schubert } 10835796c8dcSSimon Schubert break; 10845796c8dcSSimon Schubert } 10855796c8dcSSimon Schubert percent = 0; 10865796c8dcSSimon Schubert } 10875796c8dcSSimon Schubert else if (*f == '%') 10885796c8dcSSimon Schubert percent = 1; 10895796c8dcSSimon Schubert } 10905796c8dcSSimon Schubert 10915796c8dcSSimon Schubert obstack_grow_str (obstack, prev); 10925796c8dcSSimon Schubert va_end (ap); 10935796c8dcSSimon Schubert } 10945796c8dcSSimon Schubert 10955796c8dcSSimon Schubert char * 10965796c8dcSSimon Schubert xml_fetch_content_from_file (const char *filename, void *baton) 10975796c8dcSSimon Schubert { 10985796c8dcSSimon Schubert const char *dirname = baton; 10995796c8dcSSimon Schubert FILE *file; 11005796c8dcSSimon Schubert struct cleanup *back_to; 11015796c8dcSSimon Schubert char *text; 11025796c8dcSSimon Schubert size_t len, offset; 11035796c8dcSSimon Schubert 11045796c8dcSSimon Schubert if (dirname && *dirname) 11055796c8dcSSimon Schubert { 11065796c8dcSSimon Schubert char *fullname = concat (dirname, "/", filename, (char *) NULL); 1107cf7f2e2dSJohn Marino 11085796c8dcSSimon Schubert if (fullname == NULL) 11095796c8dcSSimon Schubert nomem (0); 11105796c8dcSSimon Schubert file = fopen (fullname, FOPEN_RT); 11115796c8dcSSimon Schubert xfree (fullname); 11125796c8dcSSimon Schubert } 11135796c8dcSSimon Schubert else 11145796c8dcSSimon Schubert file = fopen (filename, FOPEN_RT); 11155796c8dcSSimon Schubert 11165796c8dcSSimon Schubert if (file == NULL) 11175796c8dcSSimon Schubert return NULL; 11185796c8dcSSimon Schubert 11195796c8dcSSimon Schubert back_to = make_cleanup_fclose (file); 11205796c8dcSSimon Schubert 11215796c8dcSSimon Schubert /* Read in the whole file, one chunk at a time. */ 11225796c8dcSSimon Schubert len = 4096; 11235796c8dcSSimon Schubert offset = 0; 11245796c8dcSSimon Schubert text = xmalloc (len); 11255796c8dcSSimon Schubert make_cleanup (free_current_contents, &text); 11265796c8dcSSimon Schubert while (1) 11275796c8dcSSimon Schubert { 11285796c8dcSSimon Schubert size_t bytes_read; 11295796c8dcSSimon Schubert 11305796c8dcSSimon Schubert /* Continue reading where the last read left off. Leave at least 11315796c8dcSSimon Schubert one byte so that we can NUL-terminate the result. */ 11325796c8dcSSimon Schubert bytes_read = fread (text + offset, 1, len - offset - 1, file); 11335796c8dcSSimon Schubert if (ferror (file)) 11345796c8dcSSimon Schubert { 11355796c8dcSSimon Schubert warning (_("Read error from \"%s\""), filename); 11365796c8dcSSimon Schubert do_cleanups (back_to); 11375796c8dcSSimon Schubert return NULL; 11385796c8dcSSimon Schubert } 11395796c8dcSSimon Schubert 11405796c8dcSSimon Schubert offset += bytes_read; 11415796c8dcSSimon Schubert 11425796c8dcSSimon Schubert if (feof (file)) 11435796c8dcSSimon Schubert break; 11445796c8dcSSimon Schubert 11455796c8dcSSimon Schubert len = len * 2; 11465796c8dcSSimon Schubert text = xrealloc (text, len); 11475796c8dcSSimon Schubert } 11485796c8dcSSimon Schubert 11495796c8dcSSimon Schubert fclose (file); 11505796c8dcSSimon Schubert discard_cleanups (back_to); 11515796c8dcSSimon Schubert 11525796c8dcSSimon Schubert text[offset] = '\0'; 11535796c8dcSSimon Schubert return text; 11545796c8dcSSimon Schubert } 11555796c8dcSSimon Schubert 11565796c8dcSSimon Schubert void _initialize_xml_support (void); 11575796c8dcSSimon Schubert 11585796c8dcSSimon Schubert void 11595796c8dcSSimon Schubert _initialize_xml_support (void) 11605796c8dcSSimon Schubert { 11615796c8dcSSimon Schubert add_setshow_boolean_cmd ("xml", class_maintenance, &debug_xml, 11625796c8dcSSimon Schubert _("Set XML parser debugging."), 11635796c8dcSSimon Schubert _("Show XML parser debugging."), 11645796c8dcSSimon Schubert _("When set, debugging messages for XML parsers " 11655796c8dcSSimon Schubert "are displayed."), 11665796c8dcSSimon Schubert NULL, show_debug_xml, 11675796c8dcSSimon Schubert &setdebuglist, &showdebuglist); 11685796c8dcSSimon Schubert } 1169