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=b5e8b507f4e8c90d8bd465e1140eebb27d590b4c;hpb=a109c7c1042127edfe32cbc50f315c3dc40f8607;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/xml-support.c b/gdb/xml-support.c index b5e8b507f4..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, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2006-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -19,14 +19,15 @@ #include "defs.h" #include "gdbcmd.h" -#include "exceptions.h" +#include "xml-builtin.h" #include "xml-support.h" - -#include "gdb_string.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. */ @@ -44,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; @@ -55,134 +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; - const char *name; /* Name of this parser. */ - void *user_data; /* The user's callback data, for handlers. */ + /* Name of this parser. */ + const char *m_name; - VEC(scope_level_s) *scopes; /* Scoping stack. */ + /* The user's callback data, for handlers. */ + void *m_user_data; - struct gdb_exception error; /* A thrown error, if any. */ - int last_line; /* The line of the thrown error, or 0. */ + /* Scoping stack. */ + std::vector m_scopes; - const char *dtd_name; /* The name of the expected / default DTD, - if specified. */ - int is_xinclude; /* Are we the special parser? */ +/* A thrown error, if any. */ + struct gdb_exception m_error; + + /* 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. */ -static void -gdb_xml_body_text (void *data, const XML_Char *text, int length) +void +gdb_xml_parser::body_text (const XML_Char *text, int length) { - struct gdb_xml_parser *parser = data; - struct scope_level *scope = VEC_last (scope_level_s, parser->scopes); - - if (parser->error.reason < 0) + if (m_error.reason < 0) return; - if (scope->body == NULL) - { - scope->body = XZALLOC (struct obstack); - obstack_init (scope->body); - } + 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; - 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; + int line = XML_GetCurrentLineNumber (m_expat_parser); - if (!debug_xml) - return; - - 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); } -/* Clean up a vector of parsed attribute values. */ +/* Find the attribute named NAME in the set of parsed attributes + ATTRIBUTES. Returns NULL if not found. */ -static void -gdb_xml_values_cleanup (void *data) +struct gdb_xml_value * +xml_find_attribute (std::vector &attributes, + const char *name) { - VEC(gdb_xml_value_s) **values = data; - struct gdb_xml_value *value; - int ix; + for (gdb_xml_value &value : attributes) + if (strcmp (value.name, name) == 0) + return &value; - for (ix = 0; VEC_iterate (gdb_xml_value_s, *values, ix, value); ix++) - xfree (value->value); - VEC_free (gdb_xml_value_s, *values); + return NULL; } -/* 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. */ +/* 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_start_element (void *data, const XML_Char *name, - const XML_Char **attrs) +void +gdb_xml_parser::start_element (const XML_Char *name, + const XML_Char **attrs) { - struct gdb_xml_parser *parser = data; - struct scope_level *scope; - struct scope_level new_scope; + if (m_error.reason < 0) + return; + 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 (); - gdb_xml_debug (parser, _("Entering element <%s>"), name); + /* Get a reference to the current scope. */ + scope_level &scope = m_scopes[m_scopes.size () - 2]; + + 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; @@ -192,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; @@ -221,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])) @@ -232,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; @@ -248,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. */ @@ -275,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 @@ -298,81 +382,70 @@ static void gdb_xml_start_element_wrapper (void *data, const XML_Char *name, const XML_Char **attrs) { - struct gdb_xml_parser *parser = data; - volatile struct gdb_exception ex; - - if (parser->error.reason < 0) - return; + struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - TRY_CATCH (ex, RETURN_MASK_ALL) + try { - gdb_xml_start_element (data, name, attrs); + parser->start_element (name, attrs); } - if (ex.reason < 0) + 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)); } } -/* 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 = 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. */ + /* 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 = 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 @@ -381,86 +454,49 @@ gdb_xml_end_element (void *data, const XML_Char *name) static void gdb_xml_end_element_wrapper (void *data, const XML_Char *name) { - struct gdb_xml_parser *parser = data; - volatile struct gdb_exception ex; - - if (parser->error.reason < 0) - return; + struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data; - TRY_CATCH (ex, RETURN_MASK_ALL) + try { - gdb_xml_end_element (data, name); + parser->end_element (name); } - if (ex.reason < 0) + 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)); } } /* 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 = 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 and return a parser. Register a cleanup to destroy the - parser. */ +/* Initialize a parser. */ -struct gdb_xml_parser * -gdb_xml_create_parser_and_cleanup (const char *name, - const struct gdb_xml_element *elements, - void *user_data) +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; + m_expat_parser = XML_ParserCreateNS (NULL, '!'); + if (m_expat_parser == NULL) + malloc_failure (0); - /* Initialize the parser. */ - parser = XZALLOC (struct gdb_xml_parser); - parser->expat_parser = XML_ParserCreateNS (NULL, '!'); - if (parser->expat_parser == NULL) - { - xfree (parser); - nomem (0); - } - - parser->name = name; - - 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); - - make_cleanup (gdb_xml_cleanup, parser); - - return parser; + m_scopes.emplace_back (elements); } /* External entity handler. The only external entities we support @@ -474,17 +510,20 @@ gdb_xml_fetch_external_entity (XML_Parser expat_parser, const XML_Char *systemId, const XML_Char *publicId) { - struct gdb_xml_parser *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); + internal_error (__FILE__, __LINE__, + _("could not locate built-in DTD %s"), + parser->dtd_name ()); } else { @@ -493,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. */ @@ -509,26 +549,24 @@ 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", XML_ErrorString (err)); + _("XML_UseForeignDTD failed: %s"), + XML_ErrorString (err)); } /* Invoke PARSER on BUFFER. BUFFER is the data to parse, which @@ -539,45 +577,56 @@ 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; } +int +gdb_xml_parse_quick (const char *name, const char *dtd_name, + const struct gdb_xml_element *elements, + const char *document, void *user_data) +{ + gdb_xml_parser parser (name, elements, user_data); + if (dtd_name != NULL) + parser.use_dtd (dtd_name); + return parser.parse (document); +} + /* Parse a field VALSTR that we expect to contain an integer value. The integer is returned in *VALP. The string is parsed with an equivalent to strtoul. @@ -629,7 +678,7 @@ gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser, gdb_xml_error (parser, _("Can't convert %s=\"%s\" to an integer"), attribute->name, value); - ret = xmalloc (sizeof (result)); + ret = XNEW (ULONGEST); memcpy (ret, &result, sizeof (result)); return ret; } @@ -652,10 +701,12 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser, const struct gdb_xml_attribute *attribute, const char *value) { - const struct gdb_xml_enum *enums = attribute->handler_data; + const struct gdb_xml_enum *enums + = (const struct gdb_xml_enum *) attribute->handler_data; void *ret; - for (enums = attribute->handler_data; enums->name != NULL; enums++) + for (enums = (const struct gdb_xml_enum *) attribute->handler_data; + enums->name != NULL; enums++) if (strcasecmp (enums->name, value) == 0) break; @@ -693,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, @@ -715,12 +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 = user_data; - char *href = VEC_index (gdb_xml_value_s, attributes, 0)->value; - struct cleanup *back_to; - char *text, *output; + struct xinclude_parsing_data *data + = (struct xinclude_parsing_data *) user_data; + char *href = (char *) xml_find_attribute (attributes, "href")->value.get (); gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href); @@ -728,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++; } @@ -752,7 +808,8 @@ xinclude_end_include (struct gdb_xml_parser *parser, const struct gdb_xml_element *element, void *user_data, const char *body_text) { - struct xinclude_parsing_data *data = user_data; + struct xinclude_parsing_data *data + = (struct xinclude_parsing_data *) user_data; data->skip_depth--; } @@ -760,8 +817,8 @@ xinclude_end_include (struct gdb_xml_parser *parser, static void XMLCALL xml_xinclude_default (void *data_, const XML_Char *s, int len) { - struct gdb_xml_parser *parser = data_; - struct xinclude_parsing_data *data = parser->user_data; + struct gdb_xml_parser *parser = (struct gdb_xml_parser *) 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. */ @@ -770,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 @@ -778,8 +835,8 @@ xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset) { - struct gdb_xml_parser *parser = data_; - struct xinclude_parsing_data *data = parser->user_data; + struct gdb_xml_parser *parser = (struct gdb_xml_parser *) 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. */ @@ -789,8 +846,8 @@ xml_xinclude_start_doctype (void *data_, const XML_Char *doctypeName, static void XMLCALL xml_xinclude_end_doctype (void *data_) { - struct gdb_xml_parser *parser = data_; - struct xinclude_parsing_data *data = parser->user_data; + struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_; + xinclude_parsing_data *data = (xinclude_parsing_data *) parser->user_data (); data->skip_depth--; } @@ -804,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 = 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 } @@ -827,56 +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; - - data = XZALLOC (struct xinclude_parsing_data); - obstack_init (&data->obstack); - back_to = make_cleanup (xml_xinclude_cleanup, data); - - parser = gdb_xml_create_parser_and_cleanup (name, xinclude_elements, data); - parser->is_xinclude = 1; + xinclude_parsing_data data (result, fetcher, fetcher_baton, depth); - data->include_depth = depth; - data->fetcher = fetcher; - data->fetcher_baton = fetcher_baton; + gdb_xml_parser parser (name, xinclude_elements, &data); + parser.set_is_xinclude (true); - 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 (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 */ @@ -887,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) @@ -934,173 +967,51 @@ show_debug_xml (struct ui_file *file, int from_tty, fprintf_filtered (file, _("XML debugging is %s.\n"), value); } -/* Return a malloc allocated string with special characters from TEXT - replaced by entity references. */ - -char * -xml_escape_text (const char *text) -{ - char *result; - int i, special; - - /* Compute the length of the result. */ - for (i = 0, special = 0; text[i] != '\0'; i++) - switch (text[i]) - { - case '\'': - case '\"': - special += 5; - break; - case '&': - special += 4; - break; - case '<': - case '>': - special += 3; - break; - default: - break; - } - - /* Expand the result. */ - result = xmalloc (i + special + 1); - for (i = 0, special = 0; text[i] != '\0'; i++) - switch (text[i]) - { - case '\'': - strcpy (result + i + special, "'"); - special += 5; - break; - case '\"': - strcpy (result + i + special, """); - special += 5; - break; - case '&': - strcpy (result + i + special, "&"); - special += 4; - break; - case '<': - strcpy (result + i + special, "<"); - special += 3; - break; - case '>': - strcpy (result + i + special, ">"); - special += 3; - break; - default: - result[i + special] = text[i]; - break; - } - result[i + special] = '\0'; - - return result; -} - -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 = baton; - FILE *file; - struct cleanup *back_to; - char *text; - size_t len, offset; + const char *dirname = (const char *) baton; + gdb_file_up file; if (dirname && *dirname) { char *fullname = concat (dirname, "/", filename, (char *) NULL); - if (fullname == NULL) - nomem (0); - file = fopen (fullname, FOPEN_RT); + file = gdb_fopen_cloexec (fullname, FOPEN_RB); xfree (fullname); } else - file = fopen (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 = 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 = 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."),