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