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