X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fxml-support.c;h=c906b69fda0b6d79817296b6b54e9020d9a1a1da;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=930513de4b6426be832db5798ab2053b109973cd;hpb=618f726fcb851883a0094aa7fa17003889b7189f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/xml-support.c b/gdb/xml-support.c index 930513de4b..c906b69fda 100644 --- a/gdb/xml-support.c +++ b/gdb/xml-support.c @@ -1,6 +1,6 @@ /* Helper routines for parsing XML using Expat. - Copyright (C) 2006-2016 Free Software Foundation, Inc. + Copyright (C) 2006-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -19,12 +19,15 @@ #include "defs.h" #include "gdbcmd.h" +#include "xml-builtin.h" #include "xml-support.h" -#include "filestuff.h" +#include "gdbsupport/filestuff.h" #include "safe-ctype.h" +#include +#include /* Debugging flag. */ -static int debug_xml; +static bool debug_xml; /* The contents of this file are only useful if XML support is available. */ @@ -42,6 +45,12 @@ static int debug_xml; nesting. */ struct scope_level { + explicit scope_level (const gdb_xml_element *elements_ = NULL) + : elements (elements_), + element (NULL), + seen (0) + {} + /* Elements we allow at this level. */ const struct gdb_xml_element *elements; @@ -53,150 +62,215 @@ struct scope_level unsigned int seen; /* Body text accumulation. */ - struct obstack *body; + std::string body; }; -typedef struct scope_level scope_level_s; -DEF_VEC_O(scope_level_s); /* The parser itself, and our additional state. */ struct gdb_xml_parser { - XML_Parser expat_parser; /* The underlying expat parser. */ + gdb_xml_parser (const char *name, + const gdb_xml_element *elements, + void *user_data); + ~gdb_xml_parser(); + + /* Associate DTD_NAME, which must be the name of a compiled-in DTD, + with the parser. */ + void use_dtd (const char *dtd_name); + + /* Return the name of the expected / default DTD, if specified. */ + const char *dtd_name () + { return m_dtd_name; } + + /* Invoke the parser on BUFFER. BUFFER is the data to parse, which + should be NUL-terminated. + + The return value is 0 for success or -1 for error. It may throw, + but only if something unexpected goes wrong during parsing; parse + errors will be caught, warned about, and reported as failure. */ + int parse (const char *buffer); + + /* Issue a debugging message. */ + void vdebug (const char *format, va_list ap) + ATTRIBUTE_PRINTF (2, 0); + + /* Issue an error message, and stop parsing. */ + void verror (const char *format, va_list ap) + ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0); + + void body_text (const XML_Char *text, int length); + void start_element (const XML_Char *name, const XML_Char **attrs); + void end_element (const XML_Char *name); + + /* Return the name of this parser. */ + const char *name () + { return m_name; } + + /* Return the user's callback data, for handlers. */ + void *user_data () + { return m_user_data; }; + + /* Are we the special parser? */ + void set_is_xinclude (bool is_xinclude) + { m_is_xinclude = is_xinclude; } + + /* A thrown error, if any. */ + void set_error (gdb_exception &&error) + { + m_error = std::move (error); +#ifdef HAVE_XML_STOPPARSER + XML_StopParser (m_expat_parser, XML_FALSE); +#endif + } + + /* Return the underlying expat parser. */ + XML_Parser expat_parser () + { return m_expat_parser; } + +private: + /* The underlying expat parser. */ + XML_Parser m_expat_parser; + + /* Name of this parser. */ + const char *m_name; - const char *name; /* Name of this parser. */ - void *user_data; /* The user's callback data, for handlers. */ + /* The user's callback data, for handlers. */ + void *m_user_data; - VEC(scope_level_s) *scopes; /* Scoping stack. */ + /* Scoping stack. */ + std::vector m_scopes; - struct gdb_exception error; /* A thrown error, if any. */ - int last_line; /* The line of the thrown error, or 0. */ +/* A thrown error, if any. */ + struct gdb_exception m_error; - const char *dtd_name; /* The name of the expected / default DTD, - if specified. */ - int is_xinclude; /* Are we the special parser? */ + /* The line of the thrown error, or 0. */ + int m_last_line; + + /* The name of the expected / default DTD, if specified. */ + const char *m_dtd_name; + + /* Are we the special parser? */ + bool m_is_xinclude; }; /* Process some body text. We accumulate the text for later use; it's wrong to do anything with it immediately, because a single block of text might be broken up into multiple calls to this function. */ +void +gdb_xml_parser::body_text (const XML_Char *text, int length) +{ + if (m_error.reason < 0) + return; + + scope_level &scope = m_scopes.back (); + scope.body.append (text, length); +} + static void gdb_xml_body_text (void *data, const XML_Char *text, int length) { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - struct scope_level *scope = VEC_last (scope_level_s, parser->scopes); - if (parser->error.reason < 0) - return; - - if (scope->body == NULL) - { - scope->body = XCNEW (struct obstack); - obstack_init (scope->body); - } - - obstack_grow (scope->body, text, length); + parser->body_text (text, length); } /* Issue a debugging message from one of PARSER's handlers. */ void -gdb_xml_debug (struct gdb_xml_parser *parser, const char *format, ...) +gdb_xml_parser::vdebug (const char *format, va_list ap) { - int line = XML_GetCurrentLineNumber (parser->expat_parser); - va_list ap; - char *message; - - if (!debug_xml) - return; + int line = XML_GetCurrentLineNumber (m_expat_parser); - va_start (ap, format); - message = xstrvprintf (format, ap); + std::string message = string_vprintf (format, ap); if (line) fprintf_unfiltered (gdb_stderr, "%s (line %d): %s\n", - parser->name, line, message); + m_name, line, message.c_str ()); else fprintf_unfiltered (gdb_stderr, "%s: %s\n", - parser->name, message); - xfree (message); + m_name, message.c_str ()); +} + +void +gdb_xml_debug (struct gdb_xml_parser *parser, const char *format, ...) +{ + if (!debug_xml) + return; + + va_list ap; + va_start (ap, format); + parser->vdebug (format, ap); + va_end (ap); } /* Issue an error message from one of PARSER's handlers, and stop parsing. */ +void +gdb_xml_parser::verror (const char *format, va_list ap) +{ + int line = XML_GetCurrentLineNumber (m_expat_parser); + + m_last_line = line; + throw_verror (XML_PARSE_ERROR, format, ap); +} + void gdb_xml_error (struct gdb_xml_parser *parser, const char *format, ...) { - int line = XML_GetCurrentLineNumber (parser->expat_parser); va_list ap; - - parser->last_line = line; va_start (ap, format); - throw_verror (XML_PARSE_ERROR, format, ap); + parser->verror (format, ap); + va_end (ap); } /* Find the attribute named NAME in the set of parsed attributes ATTRIBUTES. Returns NULL if not found. */ struct gdb_xml_value * -xml_find_attribute (VEC(gdb_xml_value_s) *attributes, const char *name) +xml_find_attribute (std::vector &attributes, + const char *name) { - struct gdb_xml_value *value; - int ix; - - for (ix = 0; VEC_iterate (gdb_xml_value_s, attributes, ix, value); ix++) - if (strcmp (value->name, name) == 0) - return value; + for (gdb_xml_value &value : attributes) + if (strcmp (value.name, name) == 0) + return &value; return NULL; } -/* Clean up a vector of parsed attribute values. */ +/* Handle the start of an element. NAME is the element, and ATTRS are + the names and values of this element's attributes. */ -static void -gdb_xml_values_cleanup (void *data) +void +gdb_xml_parser::start_element (const XML_Char *name, + const XML_Char **attrs) { - VEC(gdb_xml_value_s) **values = (VEC(gdb_xml_value_s) **) data; - struct gdb_xml_value *value; - int ix; - - for (ix = 0; VEC_iterate (gdb_xml_value_s, *values, ix, value); ix++) - xfree (value->value); - VEC_free (gdb_xml_value_s, *values); -} - -/* Handle the start of an element. DATA is our local XML parser, NAME - is the element, and ATTRS are the names and values of this - element's attributes. */ + if (m_error.reason < 0) + return; -static void -gdb_xml_start_element (void *data, const XML_Char *name, - const XML_Char **attrs) -{ - struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - struct scope_level *scope; - struct scope_level new_scope; const struct gdb_xml_element *element; const struct gdb_xml_attribute *attribute; - VEC(gdb_xml_value_s) *attributes = NULL; unsigned int seen; - struct cleanup *back_to; /* Push an error scope. If we return or throw an exception before filling this in, it will tell us to ignore children of this - element. */ - VEC_reserve (scope_level_s, parser->scopes, 1); - scope = VEC_last (scope_level_s, parser->scopes); - memset (&new_scope, 0, sizeof (new_scope)); - VEC_quick_push (scope_level_s, parser->scopes, &new_scope); + element. Note we don't take a reference to the element yet + because further below we'll process the element which may recurse + back here and push more elements to the vector. When the + recursion unrolls all such elements will have been popped back + already, but if one of those pushes reallocates the vector, + previous element references will be invalidated. */ + m_scopes.emplace_back (); + + /* Get a reference to the current scope. */ + scope_level &scope = m_scopes[m_scopes.size () - 2]; - gdb_xml_debug (parser, _("Entering element <%s>"), name); + gdb_xml_debug (this, _("Entering element <%s>"), name); /* Find this element in the list of the current scope's allowed children. Record that we've seen it. */ seen = 1; - for (element = scope->elements; element && element->name; + for (element = scope.elements; element && element->name; element++, seen <<= 1) if (strcmp (element->name, name) == 0) break; @@ -206,27 +280,25 @@ gdb_xml_start_element (void *data, const XML_Char *name, /* If we're working on XInclude, can be the child of absolutely anything. Copy the previous scope's element list into the new scope even if there was no match. */ - if (parser->is_xinclude) + if (m_is_xinclude) { - struct scope_level *unknown_scope; - - XML_DefaultCurrent (parser->expat_parser); + XML_DefaultCurrent (m_expat_parser); - unknown_scope = VEC_last (scope_level_s, parser->scopes); - unknown_scope->elements = scope->elements; + scope_level &unknown_scope = m_scopes.back (); + unknown_scope.elements = scope.elements; return; } - gdb_xml_debug (parser, _("Element <%s> unknown"), name); + gdb_xml_debug (this, _("Element <%s> unknown"), name); return; } - if (!(element->flags & GDB_XML_EF_REPEATABLE) && (seen & scope->seen)) - gdb_xml_error (parser, _("Element <%s> only expected once"), name); + if (!(element->flags & GDB_XML_EF_REPEATABLE) && (seen & scope.seen)) + gdb_xml_error (this, _("Element <%s> only expected once"), name); - scope->seen |= seen; + scope.seen |= seen; - back_to = make_cleanup (gdb_xml_values_cleanup, &attributes); + std::vector attributes; for (attribute = element->attributes; attribute != NULL && attribute->name != NULL; @@ -235,7 +307,6 @@ gdb_xml_start_element (void *data, const XML_Char *name, const char *val = NULL; const XML_Char **p; void *parsed_value; - struct gdb_xml_value new_value; for (p = attrs; *p != NULL; p += 2) if (!strcmp (attribute->name, p[0])) @@ -246,14 +317,14 @@ gdb_xml_start_element (void *data, const XML_Char *name, if (*p != NULL && val == NULL) { - gdb_xml_debug (parser, _("Attribute \"%s\" missing a value"), + gdb_xml_debug (this, _("Attribute \"%s\" missing a value"), attribute->name); continue; } if (*p == NULL && !(attribute->flags & GDB_XML_AF_OPTIONAL)) { - gdb_xml_error (parser, _("Required attribute \"%s\" of " + gdb_xml_error (this, _("Required attribute \"%s\" of " "<%s> not specified"), attribute->name, element->name); continue; @@ -262,17 +333,15 @@ gdb_xml_start_element (void *data, const XML_Char *name, if (*p == NULL) continue; - gdb_xml_debug (parser, _("Parsing attribute %s=\"%s\""), + gdb_xml_debug (this, _("Parsing attribute %s=\"%s\""), attribute->name, val); if (attribute->handler) - parsed_value = attribute->handler (parser, attribute, val); + parsed_value = attribute->handler (this, attribute, val); else parsed_value = xstrdup (val); - new_value.name = attribute->name; - new_value.value = parsed_value; - VEC_safe_push (gdb_xml_value_s, attributes, &new_value); + attributes.emplace_back (attribute->name, parsed_value); } /* Check for unrecognized attributes. */ @@ -289,20 +358,21 @@ gdb_xml_start_element (void *data, const XML_Char *name, break; if (attribute == NULL || attribute->name == NULL) - gdb_xml_debug (parser, _("Ignoring unknown attribute %s"), *p); + gdb_xml_debug (this, _("Ignoring unknown attribute %s"), *p); } } /* Call the element handler if there is one. */ if (element->start_handler) - element->start_handler (parser, element, parser->user_data, attributes); + element->start_handler (this, element, m_user_data, attributes); - /* Fill in a new scope level. */ - scope = VEC_last (scope_level_s, parser->scopes); - scope->element = element; - scope->elements = element->children; - - do_cleanups (back_to); + /* Fill in a new scope level. Note that we must delay getting a + back reference till here because above we might have recursed, + which may have reallocated the vector which invalidates + iterators/pointers/references. */ + scope_level &new_scope = m_scopes.back (); + new_scope.element = element; + new_scope.elements = element->children; } /* Wrapper for gdb_xml_start_element, to prevent throwing exceptions @@ -314,79 +384,68 @@ gdb_xml_start_element_wrapper (void *data, const XML_Char *name, { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - if (parser->error.reason < 0) - return; - - TRY + try { - gdb_xml_start_element (data, name, attrs); + parser->start_element (name, attrs); } - CATCH (ex, RETURN_MASK_ALL) + catch (gdb_exception &ex) { - parser->error = ex; -#ifdef HAVE_XML_STOPPARSER - XML_StopParser (parser->expat_parser, XML_FALSE); -#endif + parser->set_error (std::move (ex)); } - END_CATCH } -/* Handle the end of an element. DATA is our local XML parser, and - NAME is the current element. */ +/* Handle the end of an element. NAME is the current element. */ -static void -gdb_xml_end_element (void *data, const XML_Char *name) +void +gdb_xml_parser::end_element (const XML_Char *name) { - struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - struct scope_level *scope = VEC_last (scope_level_s, parser->scopes); + if (m_error.reason < 0) + return; + + struct scope_level *scope = &m_scopes.back (); const struct gdb_xml_element *element; unsigned int seen; - gdb_xml_debug (parser, _("Leaving element <%s>"), name); + gdb_xml_debug (this, _("Leaving element <%s>"), name); for (element = scope->elements, seen = 1; element != NULL && element->name != NULL; element++, seen <<= 1) if ((scope->seen & seen) == 0 && (element->flags & GDB_XML_EF_OPTIONAL) == 0) - gdb_xml_error (parser, _("Required element <%s> is missing"), + gdb_xml_error (this, _("Required element <%s> is missing"), element->name); /* Call the element processor. */ if (scope->element != NULL && scope->element->end_handler) { - char *body; + const char *body; - if (scope->body == NULL) + if (scope->body.empty ()) body = ""; else { int length; - length = obstack_object_size (scope->body); - obstack_1grow (scope->body, '\0'); - body = (char *) obstack_finish (scope->body); + length = scope->body.size (); + body = scope->body.c_str (); /* Strip leading and trailing whitespace. */ - while (length > 0 && ISSPACE (body[length-1])) - body[--length] = '\0'; + while (length > 0 && ISSPACE (body[length - 1])) + length--; + scope->body.erase (length); while (*body && ISSPACE (*body)) body++; } - scope->element->end_handler (parser, scope->element, parser->user_data, - body); + scope->element->end_handler (this, scope->element, + m_user_data, body); } else if (scope->element == NULL) - XML_DefaultCurrent (parser->expat_parser); + XML_DefaultCurrent (m_expat_parser); /* Pop the scope level. */ - if (scope->body) - { - obstack_free (scope->body, NULL); - xfree (scope->body); - } - VEC_pop (scope_level_s, parser->scopes); + m_scopes.pop_back (); } /* Wrapper for gdb_xml_end_element, to prevent throwing exceptions @@ -397,85 +456,47 @@ gdb_xml_end_element_wrapper (void *data, const XML_Char *name) { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - if (parser->error.reason < 0) - return; - - TRY + try { - gdb_xml_end_element (data, name); + parser->end_element (name); } - CATCH (ex, RETURN_MASK_ALL) + catch (gdb_exception &ex) { - parser->error = ex; -#ifdef HAVE_XML_STOPPARSER - XML_StopParser (parser->expat_parser, XML_FALSE); -#endif + parser->set_error (std::move (ex)); } - END_CATCH } /* Free a parser and all its associated state. */ -static void -gdb_xml_cleanup (void *arg) +gdb_xml_parser::~gdb_xml_parser () { - struct gdb_xml_parser *parser = (struct gdb_xml_parser *) arg; - struct scope_level *scope; - int ix; - - XML_ParserFree (parser->expat_parser); - - /* Clean up the scopes. */ - for (ix = 0; VEC_iterate (scope_level_s, parser->scopes, ix, scope); ix++) - if (scope->body) - { - obstack_free (scope->body, NULL); - xfree (scope->body); - } - VEC_free (scope_level_s, parser->scopes); - - xfree (parser); + XML_ParserFree (m_expat_parser); } -/* Initialize a parser and store it to *PARSER_RESULT. Register a - cleanup to destroy the parser. */ +/* Initialize a parser. */ -static struct cleanup * -gdb_xml_create_parser_and_cleanup (const char *name, - const struct gdb_xml_element *elements, - void *user_data, - struct gdb_xml_parser **parser_result) +gdb_xml_parser::gdb_xml_parser (const char *name, + const gdb_xml_element *elements, + void *user_data) + : m_name (name), + m_user_data (user_data), + m_last_line (0), + m_dtd_name (NULL), + m_is_xinclude (false) { - struct gdb_xml_parser *parser; - struct scope_level start_scope; - struct cleanup *result; - - /* Initialize the parser. */ - parser = XCNEW (struct gdb_xml_parser); - parser->expat_parser = XML_ParserCreateNS (NULL, '!'); - if (parser->expat_parser == NULL) - { - xfree (parser); - malloc_failure (0); - } - - parser->name = name; + m_expat_parser = XML_ParserCreateNS (NULL, '!'); + if (m_expat_parser == NULL) + malloc_failure (0); - parser->user_data = user_data; - XML_SetUserData (parser->expat_parser, parser); + XML_SetUserData (m_expat_parser, this); /* Set the callbacks. */ - XML_SetElementHandler (parser->expat_parser, gdb_xml_start_element_wrapper, + XML_SetElementHandler (m_expat_parser, gdb_xml_start_element_wrapper, gdb_xml_end_element_wrapper); - XML_SetCharacterDataHandler (parser->expat_parser, gdb_xml_body_text); + XML_SetCharacterDataHandler (m_expat_parser, gdb_xml_body_text); /* Initialize the outer scope. */ - memset (&start_scope, 0, sizeof (start_scope)); - start_scope.elements = elements; - VEC_safe_push (scope_level_s, parser->scopes, &start_scope); - - *parser_result = parser; - return make_cleanup (gdb_xml_cleanup, parser); + m_scopes.emplace_back (elements); } /* External entity handler. The only external entities we support @@ -489,19 +510,20 @@ gdb_xml_fetch_external_entity (XML_Parser expat_parser, const XML_Char *systemId, const XML_Char *publicId) { - struct gdb_xml_parser *parser - = (struct gdb_xml_parser *) XML_GetUserData (expat_parser); XML_Parser entity_parser; const char *text; enum XML_Status status; if (systemId == NULL) { - text = fetch_xml_builtin (parser->dtd_name); + gdb_xml_parser *parser + = (gdb_xml_parser *) XML_GetUserData (expat_parser); + + text = fetch_xml_builtin (parser->dtd_name ()); if (text == NULL) internal_error (__FILE__, __LINE__, _("could not locate built-in DTD %s"), - parser->dtd_name); + parser->dtd_name ()); } else { @@ -510,7 +532,8 @@ gdb_xml_fetch_external_entity (XML_Parser expat_parser, return XML_STATUS_ERROR; } - entity_parser = XML_ExternalEntityParserCreate (expat_parser, context, NULL); + entity_parser = XML_ExternalEntityParserCreate (expat_parser, + context, NULL); /* Don't use our handlers for the contents of the DTD. Just let expat process it. */ @@ -526,23 +549,20 @@ gdb_xml_fetch_external_entity (XML_Parser expat_parser, return status; } -/* Associate DTD_NAME, which must be the name of a compiled-in DTD, - with PARSER. */ - void -gdb_xml_use_dtd (struct gdb_xml_parser *parser, const char *dtd_name) +gdb_xml_parser::use_dtd (const char *dtd_name) { enum XML_Error err; - parser->dtd_name = dtd_name; + m_dtd_name = dtd_name; - XML_SetParamEntityParsing (parser->expat_parser, + XML_SetParamEntityParsing (m_expat_parser, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); - XML_SetExternalEntityRefHandler (parser->expat_parser, + XML_SetExternalEntityRefHandler (m_expat_parser, gdb_xml_fetch_external_entity); /* Even if no DTD is provided, use the built-in DTD anyway. */ - err = XML_UseForeignDTD (parser->expat_parser, XML_TRUE); + err = XML_UseForeignDTD (m_expat_parser, XML_TRUE); if (err != XML_ERROR_NONE) internal_error (__FILE__, __LINE__, _("XML_UseForeignDTD failed: %s"), @@ -557,41 +577,41 @@ gdb_xml_use_dtd (struct gdb_xml_parser *parser, const char *dtd_name) errors will be caught, warned about, and reported as failure. */ int -gdb_xml_parse (struct gdb_xml_parser *parser, const char *buffer) +gdb_xml_parser::parse (const char *buffer) { enum XML_Status status; const char *error_string; - gdb_xml_debug (parser, _("Starting:\n%s"), buffer); + gdb_xml_debug (this, _("Starting:\n%s"), buffer); - status = XML_Parse (parser->expat_parser, buffer, strlen (buffer), 1); + status = XML_Parse (m_expat_parser, buffer, strlen (buffer), 1); - if (status == XML_STATUS_OK && parser->error.reason == 0) + if (status == XML_STATUS_OK && m_error.reason == 0) return 0; - if (parser->error.reason == RETURN_ERROR - && parser->error.error == XML_PARSE_ERROR) + if (m_error.reason == RETURN_ERROR + && m_error.error == XML_PARSE_ERROR) { - gdb_assert (parser->error.message != NULL); - error_string = parser->error.message; + gdb_assert (m_error.message != NULL); + error_string = m_error.what (); } else if (status == XML_STATUS_ERROR) { - enum XML_Error err = XML_GetErrorCode (parser->expat_parser); + enum XML_Error err = XML_GetErrorCode (m_expat_parser); error_string = XML_ErrorString (err); } else { - gdb_assert (parser->error.reason < 0); - throw_exception (parser->error); + gdb_assert (m_error.reason < 0); + throw_exception (std::move (m_error)); } - if (parser->last_line != 0) - warning (_("while parsing %s (at line %d): %s"), parser->name, - parser->last_line, error_string); + if (m_last_line != 0) + warning (_("while parsing %s (at line %d): %s"), m_name, + m_last_line, error_string); else - warning (_("while parsing %s: %s"), parser->name, error_string); + warning (_("while parsing %s: %s"), m_name, error_string); return -1; } @@ -601,19 +621,10 @@ gdb_xml_parse_quick (const char *name, const char *dtd_name, const struct gdb_xml_element *elements, const char *document, void *user_data) { - struct gdb_xml_parser *parser; - struct cleanup *back_to; - int result; - - back_to = gdb_xml_create_parser_and_cleanup (name, elements, - user_data, &parser); + gdb_xml_parser parser (name, elements, user_data); if (dtd_name != NULL) - gdb_xml_use_dtd (parser, dtd_name); - result = gdb_xml_parse (parser, document); - - do_cleanups (back_to); - - return result; + parser.use_dtd (dtd_name); + return parser.parse (document); } /* Parse a field VALSTR that we expect to contain an integer value. @@ -733,8 +744,18 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser, struct xinclude_parsing_data { - /* The obstack to build the output in. */ - struct obstack obstack; + xinclude_parsing_data (std::string &output_, + xml_fetch_another fetcher_, void *fetcher_baton_, + int include_depth_) + : output (output_), + skip_depth (0), + include_depth (include_depth_), + fetcher (fetcher_), + fetcher_baton (fetcher_baton_) + {} + + /* Where the output goes. */ + std::string &output; /* A count indicating whether we are in an element whose children should not be copied to the output, and if so, @@ -755,13 +776,12 @@ struct xinclude_parsing_data static void xinclude_start_include (struct gdb_xml_parser *parser, const struct gdb_xml_element *element, - void *user_data, VEC(gdb_xml_value_s) *attributes) + void *user_data, + std::vector &attributes) { struct xinclude_parsing_data *data = (struct xinclude_parsing_data *) user_data; - char *href = (char *) xml_find_attribute (attributes, "href")->value; - struct cleanup *back_to; - char *text, *output; + char *href = (char *) xml_find_attribute (attributes, "href")->value.get (); gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href); @@ -769,22 +789,17 @@ xinclude_start_include (struct gdb_xml_parser *parser, gdb_xml_error (parser, _("Maximum XInclude depth (%d) exceeded"), MAX_XINCLUDE_DEPTH); - text = data->fetcher (href, data->fetcher_baton); - if (text == NULL) + gdb::optional text + = data->fetcher (href, data->fetcher_baton); + if (!text) gdb_xml_error (parser, _("Could not load XML document \"%s\""), href); - back_to = make_cleanup (xfree, text); - output = xml_process_xincludes (parser->name, text, data->fetcher, - data->fetcher_baton, - data->include_depth + 1); - if (output == NULL) + if (!xml_process_xincludes (data->output, parser->name (), + text->data (), data->fetcher, + data->fetcher_baton, + data->include_depth + 1)) gdb_xml_error (parser, _("Parsing \"%s\" failed"), href); - obstack_grow (&data->obstack, output, strlen (output)); - xfree (output); - - do_cleanups (back_to); - data->skip_depth++; } @@ -803,8 +818,7 @@ static void XMLCALL xml_xinclude_default (void *data_, const XML_Char *s, int len) { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_; - struct xinclude_parsing_data *data - = (struct xinclude_parsing_data *) parser->user_data; + xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data (); /* If we are inside of e.g. xi:include or the DTD, don't save this string. */ @@ -813,7 +827,7 @@ xml_xinclude_default (void *data_, const XML_Char *s, int len) /* Otherwise just add it to the end of the document we're building up. */ - obstack_grow (&data->obstack, s, len); + data->output.append (s, len); } static void XMLCALL @@ -822,8 +836,7 @@ xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName, int has_internal_subset) { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_; - struct xinclude_parsing_data *data - = (struct xinclude_parsing_data *) parser->user_data; + xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data (); /* Don't print out the doctype, or the contents of the DTD internal subset, if any. */ @@ -834,8 +847,7 @@ static void XMLCALL xml_xinclude_end_doctype (void *data_) { struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_; - struct xinclude_parsing_data *data - = (struct xinclude_parsing_data *) parser->user_data; + xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data (); data->skip_depth--; } @@ -849,15 +861,6 @@ xml_xinclude_xml_decl (void *data_, const XML_Char *version, output. */ } -static void -xml_xinclude_cleanup (void *data_) -{ - struct xinclude_parsing_data *data = (struct xinclude_parsing_data *) data_; - - obstack_free (&data->obstack, NULL); - xfree (data); -} - const struct gdb_xml_attribute xinclude_attributes[] = { { "href", GDB_XML_AF_NONE, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } @@ -872,57 +875,41 @@ const struct gdb_xml_element xinclude_elements[] = { /* The main entry point for processing. */ -char * -xml_process_xincludes (const char *name, const char *text, +bool +xml_process_xincludes (std::string &result, + const char *name, const char *text, xml_fetch_another fetcher, void *fetcher_baton, int depth) { - struct gdb_xml_parser *parser; - struct xinclude_parsing_data *data; - struct cleanup *back_to; - char *result = NULL; + xinclude_parsing_data data (result, fetcher, fetcher_baton, depth); - data = XCNEW (struct xinclude_parsing_data); - obstack_init (&data->obstack); - back_to = make_cleanup (xml_xinclude_cleanup, data); + gdb_xml_parser parser (name, xinclude_elements, &data); + parser.set_is_xinclude (true); - gdb_xml_create_parser_and_cleanup (name, xinclude_elements, - data, &parser); - parser->is_xinclude = 1; - - data->include_depth = depth; - data->fetcher = fetcher; - data->fetcher_baton = fetcher_baton; - - XML_SetCharacterDataHandler (parser->expat_parser, NULL); - XML_SetDefaultHandler (parser->expat_parser, xml_xinclude_default); + XML_SetCharacterDataHandler (parser.expat_parser (), NULL); + XML_SetDefaultHandler (parser.expat_parser (), xml_xinclude_default); /* Always discard the XML version declarations; the only important thing this provides is encoding, and our result will have been converted to UTF-8. */ - XML_SetXmlDeclHandler (parser->expat_parser, xml_xinclude_xml_decl); + XML_SetXmlDeclHandler (parser.expat_parser (), xml_xinclude_xml_decl); if (depth > 0) /* Discard the doctype for included documents. */ - XML_SetDoctypeDeclHandler (parser->expat_parser, + XML_SetDoctypeDeclHandler (parser.expat_parser (), xml_xinclude_start_doctype, xml_xinclude_end_doctype); - gdb_xml_use_dtd (parser, "xinclude.dtd"); + parser.use_dtd ("xinclude.dtd"); - if (gdb_xml_parse (parser, text) == 0) + if (parser.parse (text) == 0) { - obstack_1grow (&data->obstack, '\0'); - result = xstrdup ((const char *) obstack_finish (&data->obstack)); - if (depth == 0) - gdb_xml_debug (parser, _("XInclude processing succeeded.")); + gdb_xml_debug (&parser, _("XInclude processing succeeded.")); + return true; } - else - result = NULL; - do_cleanups (back_to); - return result; + return false; } #endif /* HAVE_LIBEXPAT */ @@ -933,7 +920,7 @@ xml_process_xincludes (const char *name, const char *text, const char * fetch_xml_builtin (const char *filename) { - const char *(*p)[2]; + const char *const (*p)[2]; for (p = xml_builtin; (*p)[0]; p++) if (strcmp ((*p)[0], filename) == 0) @@ -980,111 +967,51 @@ show_debug_xml (struct ui_file *file, int from_tty, fprintf_filtered (file, _("XML debugging is %s.\n"), value); } -void -obstack_xml_printf (struct obstack *obstack, const char *format, ...) -{ - va_list ap; - const char *f; - const char *prev; - int percent = 0; - - va_start (ap, format); - - prev = format; - for (f = format; *f; f++) - { - if (percent) - { - switch (*f) - { - case 's': - { - char *p; - char *a = va_arg (ap, char *); - - obstack_grow (obstack, prev, f - prev - 1); - p = xml_escape_text (a); - obstack_grow_str (obstack, p); - xfree (p); - prev = f + 1; - } - break; - } - percent = 0; - } - else if (*f == '%') - percent = 1; - } - - obstack_grow_str (obstack, prev); - va_end (ap); -} - -char * +gdb::optional xml_fetch_content_from_file (const char *filename, void *baton) { const char *dirname = (const char *) baton; - FILE *file; - struct cleanup *back_to; - char *text; - size_t len, offset; + gdb_file_up file; if (dirname && *dirname) { char *fullname = concat (dirname, "/", filename, (char *) NULL); - if (fullname == NULL) - malloc_failure (0); - file = gdb_fopen_cloexec (fullname, FOPEN_RT); + file = gdb_fopen_cloexec (fullname, FOPEN_RB); xfree (fullname); } else - file = gdb_fopen_cloexec (filename, FOPEN_RT); + file = gdb_fopen_cloexec (filename, FOPEN_RB); if (file == NULL) - return NULL; - - back_to = make_cleanup_fclose (file); + return {}; - /* Read in the whole file, one chunk at a time. */ - len = 4096; - offset = 0; - text = (char *) xmalloc (len); - make_cleanup (free_current_contents, &text); - while (1) - { - size_t bytes_read; + /* Read in the whole file. */ - /* Continue reading where the last read left off. Leave at least - one byte so that we can NUL-terminate the result. */ - bytes_read = fread (text + offset, 1, len - offset - 1, file); - if (ferror (file)) - { - warning (_("Read error from \"%s\""), filename); - do_cleanups (back_to); - return NULL; - } + size_t len; - offset += bytes_read; + if (fseek (file.get (), 0, SEEK_END) == -1) + perror_with_name (_("seek to end of file")); + len = ftell (file.get ()); + rewind (file.get ()); - if (feof (file)) - break; + gdb::char_vector text (len + 1); - len = len * 2; - text = (char *) xrealloc (text, len); + if (fread (text.data (), 1, len, file.get ()) != len + || ferror (file.get ())) + { + warning (_("Read error from \"%s\""), filename); + return {}; } - fclose (file); - discard_cleanups (back_to); - - text[offset] = '\0'; + text.back () = '\0'; return text; } -void _initialize_xml_support (void); - +void _initialize_xml_support (); +void _initialize_xml_support (); void -_initialize_xml_support (void) +_initialize_xml_support () { add_setshow_boolean_cmd ("xml", class_maintenance, &debug_xml, _("Set XML parser debugging."),