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