Remove some calls to malloc_failure
[deliverable/binutils-gdb.git] / gdb / xml-support.c
index d6c940c0de95c8dc41ec7d00f715ad454354c609..f5a142754578e18572874406258cb2e2c0d0fcc0 100644 (file)
@@ -1,6 +1,6 @@
 /* Helper routines for parsing XML using Expat.
 
-   Copyright (C) 2006-2017 Free Software Foundation, Inc.
+   Copyright (C) 2006-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #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 <vector>
+#include <string>
 
 /* Debugging flag.  */
-static int debug_xml;
+static bool debug_xml;
 
 /* The contents of this file are only useful if XML support is
    available.  */
@@ -46,29 +48,9 @@ struct scope_level
   explicit scope_level (const gdb_xml_element *elements_ = NULL)
     : elements (elements_),
       element (NULL),
-      seen (0),
-      body (NULL)
+      seen (0)
   {}
 
-  scope_level (scope_level &&other) noexcept
-    : elements (other.elements),
-      element (other.element),
-      seen (other.seen),
-      body (other.body)
-  {
-    if (this != &other)
-      other.body = NULL;
-  }
-
-  ~scope_level ()
-  {
-    if (this->body)
-      {
-       obstack_free (this->body, NULL);
-       xfree (this->body);
-      }
-  }
-
   /* Elements we allow at this level.  */
   const struct gdb_xml_element *elements;
 
@@ -79,8 +61,8 @@ struct scope_level
      optional and repeatable checking).  */
   unsigned int seen;
 
-  /* Body text accumulation.  This is an owning pointer.  */
-  struct obstack *body;
+  /* Body text accumulation.  */
+  std::string body;
 };
 
 /* The parser itself, and our additional state.  */
@@ -91,126 +73,183 @@ struct gdb_xml_parser
                  void *user_data);
   ~gdb_xml_parser();
 
-  XML_Parser expat_parser;     /* The underlying expat 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.
 
-  const char *name;            /* Name of this parser.  */
-  void *user_data;             /* The user's callback data, for handlers.  */
+     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 <xi:include> 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;
+
+  /* The user's callback data, for handlers.  */
+  void *m_user_data;
 
   /* Scoping stack.  */
-  std::vector<scope_level> scopes;
+  std::vector<scope_level> m_scopes;
+
+/* A thrown error, if any.  */
+  struct gdb_exception m_error;
 
-  struct gdb_exception error;  /* A thrown error, if any.  */
-  int last_line;               /* The line of the thrown error, or 0.  */
+  /* The line of the thrown error, or 0.  */
+  int m_last_line;
 
-  const char *dtd_name;                /* The name of the expected / default DTD,
-                                  if specified.  */
-  bool is_xinclude;            /* Are we the special <xi:include> parser?  */
+  /* The name of the expected / default DTD, if specified.  */
+  const char *m_dtd_name;
+
+  /* Are we the special <xi:include> 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;
 
-  if (parser->error.reason < 0)
-    return;
+  parser->body_text (text, length);
+}
 
-  scope_level &scope = parser->scopes.back ();
+/* Issue a debugging message from one of PARSER's handlers.  */
 
-  if (scope.body == NULL)
-    {
-      scope.body = XCNEW (struct obstack);
-      obstack_init (scope.body);
-    }
+void
+gdb_xml_parser::vdebug (const char *format, va_list ap)
+{
+  int line = XML_GetCurrentLineNumber (m_expat_parser);
 
-  obstack_grow (scope.body, text, length);
+  std::string message = string_vprintf (format, ap);
+  if (line)
+    fprintf_unfiltered (gdb_stderr, "%s (line %d): %s\n",
+                       m_name, line, message.c_str ());
+  else
+    fprintf_unfiltered (gdb_stderr, "%s: %s\n",
+                       m_name, message.c_str ());
 }
 
-/* Issue a debugging message from one of PARSER's handlers.  */
-
 void
 gdb_xml_debug (struct gdb_xml_parser *parser, const char *format, ...)
 {
-  int line = XML_GetCurrentLineNumber (parser->expat_parser);
-  va_list ap;
-  char *message;
-
   if (!debug_xml)
     return;
 
+  va_list ap;
   va_start (ap, format);
-  message = xstrvprintf (format, ap);
-  if (line)
-    fprintf_unfiltered (gdb_stderr, "%s (line %d): %s\n",
-                       parser->name, line, message);
-  else
-    fprintf_unfiltered (gdb_stderr, "%s: %s\n",
-                       parser->name, message);
-  xfree (message);
+  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<gdb_xml_value> &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;
   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
@@ -220,12 +259,12 @@ gdb_xml_start_element (void *data, const XML_Char *name,
      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.  */
-  parser->scopes.emplace_back ();
+  m_scopes.emplace_back ();
 
   /* Get a reference to the current scope.  */
-  scope_level &scope = parser->scopes[parser->scopes.size () - 2];
+  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.  */
@@ -241,25 +280,25 @@ gdb_xml_start_element (void *data, const XML_Char *name,
       /* If we're working on XInclude, <xi:include> 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)
        {
-         XML_DefaultCurrent (parser->expat_parser);
+         XML_DefaultCurrent (m_expat_parser);
 
-         scope_level &unknown_scope = parser->scopes.back ();
+         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);
+    gdb_xml_error (this, _("Element <%s> only expected once"), name);
 
   scope.seen |= seen;
 
-  back_to = make_cleanup (gdb_xml_values_cleanup, &attributes);
+  std::vector<gdb_xml_value> attributes;
 
   for (attribute = element->attributes;
        attribute != NULL && attribute->name != NULL;
@@ -268,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]))
@@ -279,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;
@@ -295,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.  */
@@ -322,23 +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.  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 = parser->scopes.back ();
+  scope_level &new_scope = m_scopes.back ();
   new_scope.element = element;
   new_scope.elements = element->children;
-
-  do_cleanups (back_to);
 }
 
 /* Wrapper for gdb_xml_start_element, to prevent throwing exceptions
@@ -350,75 +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.  PARSER 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 (gdb_xml_parser *parser, const XML_Char *name)
+void
+gdb_xml_parser::end_element (const XML_Char *name)
 {
-  struct scope_level *scope = &parser->scopes.back ();
+  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)
     {
-      const char *scope_body;
+      const char *body;
 
-      if (scope->body == NULL)
-       scope_body = "";
+      if (scope->body.empty ())
+       body = "";
       else
        {
          int length;
 
-         length = obstack_object_size (scope->body);
-         obstack_1grow (scope->body, '\0');
-         char *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_body = body;
        }
 
-      scope->element->end_handler (parser, scope->element, parser->user_data,
-                                  scope_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.  */
-  parser->scopes.pop_back ();
+  m_scopes.pop_back ();
 }
 
 /* Wrapper for gdb_xml_end_element, to prevent throwing exceptions
@@ -429,55 +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 (parser, 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.  */
 
 gdb_xml_parser::~gdb_xml_parser ()
 {
-  XML_ParserFree (this->expat_parser);
+  XML_ParserFree (m_expat_parser);
 }
 
 /* Initialize a parser.  */
 
-gdb_xml_parser::gdb_xml_parser (const char *name_,
+gdb_xml_parser::gdb_xml_parser (const char *name,
                                const gdb_xml_element *elements,
-                               void *user_data_)
-  : name (name_),
-    user_data (user_data_),
-    error (exception_none),
-    last_line (0),
-    dtd_name (NULL),
-    is_xinclude (false)
-{
-  this->expat_parser = XML_ParserCreateNS (NULL, '!');
-  if (this->expat_parser == NULL)
+                               void *user_data)
+  : m_name (name),
+    m_user_data (user_data),
+    m_last_line (0),
+    m_dtd_name (NULL),
+    m_is_xinclude (false)
+{
+  m_expat_parser = XML_ParserCreateNS (NULL, '!');
+  if (m_expat_parser == NULL)
     malloc_failure (0);
 
-  XML_SetUserData (this->expat_parser, this);
+  XML_SetUserData (m_expat_parser, this);
 
   /* Set the callbacks.  */
-  XML_SetElementHandler (this->expat_parser, gdb_xml_start_element_wrapper,
+  XML_SetElementHandler (m_expat_parser, gdb_xml_start_element_wrapper,
                         gdb_xml_end_element_wrapper);
-  XML_SetCharacterDataHandler (this->expat_parser, gdb_xml_body_text);
+  XML_SetCharacterDataHandler (m_expat_parser, gdb_xml_body_text);
 
   /* Initialize the outer scope.  */
-  this->scopes.emplace_back (elements);
+  m_scopes.emplace_back (elements);
 }
 
 /* External entity handler.  The only external entities we support
@@ -491,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
     {
@@ -512,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.  */
@@ -528,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"),
@@ -559,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;
 }
@@ -605,8 +623,8 @@ gdb_xml_parse_quick (const char *name, const char *dtd_name,
 {
   gdb_xml_parser parser (name, elements, user_data);
   if (dtd_name != NULL)
-    gdb_xml_use_dtd (&parser, dtd_name);
-  return gdb_xml_parse (&parser, document);
+    parser.use_dtd (dtd_name);
+  return parser.parse (document);
 }
 
 /* Parse a field VALSTR that we expect to contain an integer value.
@@ -726,23 +744,18 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser,
 
 struct xinclude_parsing_data
 {
-  xinclude_parsing_data (xml_fetch_another fetcher_, void *fetcher_baton_,
+  xinclude_parsing_data (std::string &output_,
+                        xml_fetch_another fetcher_, void *fetcher_baton_,
                         int include_depth_)
-    : skip_depth (0),
+    : output (output_),
+      skip_depth (0),
       include_depth (include_depth_),
       fetcher (fetcher_),
       fetcher_baton (fetcher_baton_)
-  {
-    obstack_init (&this->obstack);
-  }
-
-  ~xinclude_parsing_data ()
-  {
-    obstack_free (&this->obstack, NULL);
-  }
+  {}
 
-  /* The obstack to build the output in.  */
-  struct obstack obstack;
+  /* 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,
@@ -763,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<gdb_xml_value> &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);
 
@@ -777,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<gdb::char_vector> 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++;
 }
 
@@ -811,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.  */
@@ -821,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
@@ -830,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.  */
@@ -842,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--;
 }
@@ -871,46 +875,41 @@ const struct gdb_xml_element xinclude_elements[] = {
 
 /* The main entry point for <xi:include> 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)
 {
-  char *result = NULL;
-
-  xinclude_parsing_data data (fetcher, fetcher_baton, depth);
+  xinclude_parsing_data data (result, fetcher, fetcher_baton, depth);
 
   gdb_xml_parser parser (name, xinclude_elements, &data);
-  parser.is_xinclude = true;
+  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 ((const char *) obstack_finish (&data.obstack));
-
       if (depth == 0)
        gdb_xml_debug (&parser, _("XInclude processing succeeded."));
+      return true;
     }
-  else
-    result = NULL;
 
-  return result;
+  return false;
 }
 #endif /* HAVE_LIBEXPAT */
 \f
@@ -921,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)
@@ -968,61 +967,16 @@ 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<gdb::char_vector>
 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);
       xfree (fullname);
     }
@@ -1030,47 +984,30 @@ xml_fetch_content_from_file (const char *filename, void *baton)
     file = gdb_fopen_cloexec (filename, FOPEN_RT);
 
   if (file == NULL)
-    return NULL;
+    return {};
 
-  back_to = make_cleanup_fclose (file);
+  /* Read in the whole file.  */
 
-  /* 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;
-
-      /* 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)
 {
This page took 0.038103 seconds and 4 git commands to generate.