/* Helper routines for parsing XML using Expat.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2016 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbcmd.h"
+#include "xml-support.h"
+#include "filestuff.h"
+#include "safe-ctype.h"
/* Debugging flag. */
static int debug_xml;
available. */
#ifdef HAVE_LIBEXPAT
-#include "exceptions.h"
-#include "xml-support.h"
-
#include "gdb_expat.h"
-#include "gdb_string.h"
-#include "safe-ctype.h"
/* The maximum depth of <xi:include> nesting. No need to be miserly,
we just want to avoid running out of stack on loops. */
#define MAX_XINCLUDE_DEPTH 30
+/* Simplified XML parser infrastructure. */
+
/* A parsing level -- used to keep track of the current element
nesting. */
struct scope_level
static void
gdb_xml_body_text (void *data, const XML_Char *text, int length)
{
- struct gdb_xml_parser *parser = data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
struct scope_level *scope = VEC_last (scope_level_s, parser->scopes);
if (parser->error.reason < 0)
if (scope->body == NULL)
{
- scope->body = XZALLOC (struct obstack);
+ scope->body = XCNEW (struct obstack);
obstack_init (scope->body);
}
throw_verror (XML_PARSE_ERROR, format, ap);
}
+/* Find the attribute named NAME in the set of parsed attributes
+ ATTRIBUTES. Returns NULL if not found. */
+
+struct gdb_xml_value *
+xml_find_attribute (VEC(gdb_xml_value_s) *attributes, const char *name)
+{
+ struct gdb_xml_value *value;
+ int ix;
+
+ for (ix = 0; VEC_iterate (gdb_xml_value_s, attributes, ix, value); ix++)
+ if (strcmp (value->name, name) == 0)
+ return value;
+
+ return NULL;
+}
+
/* Clean up a vector of parsed attribute values. */
static void
gdb_xml_values_cleanup (void *data)
{
- VEC(gdb_xml_value_s) **values = data;
+ VEC(gdb_xml_value_s) **values = (VEC(gdb_xml_value_s) **) data;
struct gdb_xml_value *value;
int ix;
gdb_xml_start_element (void *data, const XML_Char *name,
const XML_Char **attrs)
{
- struct gdb_xml_parser *parser = data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
struct scope_level *scope;
struct scope_level new_scope;
const struct gdb_xml_element *element;
gdb_xml_start_element_wrapper (void *data, const XML_Char *name,
const XML_Char **attrs)
{
- struct gdb_xml_parser *parser = data;
- volatile struct gdb_exception ex;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
if (parser->error.reason < 0)
return;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
gdb_xml_start_element (data, name, attrs);
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ALL)
{
parser->error = ex;
#ifdef HAVE_XML_STOPPARSER
XML_StopParser (parser->expat_parser, XML_FALSE);
#endif
}
+ END_CATCH
}
/* Handle the end of an element. DATA is our local XML parser, and
static void
gdb_xml_end_element (void *data, const XML_Char *name)
{
- struct gdb_xml_parser *parser = data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
struct scope_level *scope = VEC_last (scope_level_s, parser->scopes);
const struct gdb_xml_element *element;
unsigned int seen;
gdb_xml_error (parser, _("Required element <%s> is missing"),
element->name);
- /* Call the element processor. */
+ /* Call the element processor. */
if (scope->element != NULL && scope->element->end_handler)
{
char *body;
length = obstack_object_size (scope->body);
obstack_1grow (scope->body, '\0');
- body = obstack_finish (scope->body);
+ body = (char *) obstack_finish (scope->body);
/* Strip leading and trailing whitespace. */
while (length > 0 && ISSPACE (body[length-1]))
static void
gdb_xml_end_element_wrapper (void *data, const XML_Char *name)
{
- struct gdb_xml_parser *parser = data;
- volatile struct gdb_exception ex;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data;
if (parser->error.reason < 0)
return;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
gdb_xml_end_element (data, name);
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ALL)
{
parser->error = ex;
#ifdef HAVE_XML_STOPPARSER
XML_StopParser (parser->expat_parser, XML_FALSE);
#endif
}
+ END_CATCH
}
/* Free a parser and all its associated state. */
static void
gdb_xml_cleanup (void *arg)
{
- struct gdb_xml_parser *parser = arg;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) arg;
struct scope_level *scope;
int ix;
xfree (parser);
}
-/* Initialize and return a parser. Register a cleanup to destroy the
- parser. */
+/* Initialize a parser and store it to *PARSER_RESULT. Register a
+ cleanup to destroy the parser. */
-struct gdb_xml_parser *
+static struct cleanup *
gdb_xml_create_parser_and_cleanup (const char *name,
const struct gdb_xml_element *elements,
- void *user_data)
+ void *user_data,
+ struct gdb_xml_parser **parser_result)
{
struct gdb_xml_parser *parser;
struct scope_level start_scope;
+ struct cleanup *result;
/* Initialize the parser. */
- parser = XZALLOC (struct gdb_xml_parser);
+ parser = XCNEW (struct gdb_xml_parser);
parser->expat_parser = XML_ParserCreateNS (NULL, '!');
if (parser->expat_parser == NULL)
{
xfree (parser);
- nomem (0);
+ malloc_failure (0);
}
parser->name = name;
start_scope.elements = elements;
VEC_safe_push (scope_level_s, parser->scopes, &start_scope);
- make_cleanup (gdb_xml_cleanup, parser);
-
- return parser;
+ *parser_result = parser;
+ return make_cleanup (gdb_xml_cleanup, parser);
}
/* External entity handler. The only external entities we support
const XML_Char *systemId,
const XML_Char *publicId)
{
- struct gdb_xml_parser *parser = XML_GetUserData (expat_parser);
+ struct gdb_xml_parser *parser
+ = (struct gdb_xml_parser *) XML_GetUserData (expat_parser);
XML_Parser entity_parser;
const char *text;
enum XML_Status status;
{
text = fetch_xml_builtin (parser->dtd_name);
if (text == NULL)
- internal_error (__FILE__, __LINE__, "could not locate built-in DTD %s",
+ internal_error (__FILE__, __LINE__,
+ _("could not locate built-in DTD %s"),
parser->dtd_name);
}
else
err = XML_UseForeignDTD (parser->expat_parser, XML_TRUE);
if (err != XML_ERROR_NONE)
internal_error (__FILE__, __LINE__,
- "XML_UseForeignDTD failed: %s", XML_ErrorString (err));
+ _("XML_UseForeignDTD failed: %s"),
+ XML_ErrorString (err));
}
/* Invoke PARSER on BUFFER. BUFFER is the data to parse, which
enum XML_Status status;
const char *error_string;
+ gdb_xml_debug (parser, _("Starting:\n%s"), buffer);
+
status = XML_Parse (parser->expat_parser, buffer, strlen (buffer), 1);
if (status == XML_STATUS_OK && parser->error.reason == 0)
else if (status == XML_STATUS_ERROR)
{
enum XML_Error err = XML_GetErrorCode (parser->expat_parser);
+
error_string = XML_ErrorString (err);
}
else
return -1;
}
+int
+gdb_xml_parse_quick (const char *name, const char *dtd_name,
+ const struct gdb_xml_element *elements,
+ const char *document, void *user_data)
+{
+ struct gdb_xml_parser *parser;
+ struct cleanup *back_to;
+ int result;
+
+ back_to = gdb_xml_create_parser_and_cleanup (name, elements,
+ user_data, &parser);
+ if (dtd_name != NULL)
+ gdb_xml_use_dtd (parser, dtd_name);
+ result = gdb_xml_parse (parser, document);
+
+ do_cleanups (back_to);
+
+ return result;
+}
+
/* Parse a field VALSTR that we expect to contain an integer value.
The integer is returned in *VALP. The string is parsed with an
equivalent to strtoul.
gdb_xml_error (parser, _("Can't convert %s=\"%s\" to an integer"),
attribute->name, value);
- ret = xmalloc (sizeof (result));
+ ret = XNEW (ULONGEST);
memcpy (ret, &result, sizeof (result));
return ret;
}
+/* A handler_data for yes/no boolean values. */
+
+const struct gdb_xml_enum gdb_xml_enums_boolean[] = {
+ { "yes", 1 },
+ { "no", 0 },
+ { NULL, 0 }
+};
+
/* Map NAME to VALUE. A struct gdb_xml_enum * should be saved as the
value of handler_data when using gdb_xml_parse_attr_enum to parse a
fixed list of possible strings. The list is terminated by an entry
const struct gdb_xml_attribute *attribute,
const char *value)
{
- const struct gdb_xml_enum *enums = attribute->handler_data;
+ const struct gdb_xml_enum *enums
+ = (const struct gdb_xml_enum *) attribute->handler_data;
void *ret;
- for (enums = attribute->handler_data; enums->name != NULL; enums++)
- if (strcmp (enums->name, value) == 0)
+ for (enums = (const struct gdb_xml_enum *) attribute->handler_data;
+ enums->name != NULL; enums++)
+ if (strcasecmp (enums->name, value) == 0)
break;
if (enums->name == NULL)
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- struct xinclude_parsing_data *data = user_data;
- char *href = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ struct xinclude_parsing_data *data
+ = (struct xinclude_parsing_data *) user_data;
+ char *href = (char *) xml_find_attribute (attributes, "href")->value;
struct cleanup *back_to;
char *text, *output;
- int ret;
gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href);
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
- struct xinclude_parsing_data *data = user_data;
+ struct xinclude_parsing_data *data
+ = (struct xinclude_parsing_data *) user_data;
data->skip_depth--;
}
static void XMLCALL
xml_xinclude_default (void *data_, const XML_Char *s, int len)
{
- struct gdb_xml_parser *parser = data_;
- struct xinclude_parsing_data *data = parser->user_data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
+ struct xinclude_parsing_data *data
+ = (struct xinclude_parsing_data *) parser->user_data;
/* If we are inside of e.g. xi:include or the DTD, don't save this
string. */
const XML_Char *sysid, const XML_Char *pubid,
int has_internal_subset)
{
- struct gdb_xml_parser *parser = data_;
- struct xinclude_parsing_data *data = parser->user_data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
+ struct xinclude_parsing_data *data
+ = (struct xinclude_parsing_data *) parser->user_data;
/* Don't print out the doctype, or the contents of the DTD internal
subset, if any. */
static void XMLCALL
xml_xinclude_end_doctype (void *data_)
{
- struct gdb_xml_parser *parser = data_;
- struct xinclude_parsing_data *data = parser->user_data;
+ struct gdb_xml_parser *parser = (struct gdb_xml_parser *) data_;
+ struct xinclude_parsing_data *data
+ = (struct xinclude_parsing_data *) parser->user_data;
data->skip_depth--;
}
static void
xml_xinclude_cleanup (void *data_)
{
- struct xinclude_parsing_data *data = data_;
+ struct xinclude_parsing_data *data = (struct xinclude_parsing_data *) data_;
obstack_free (&data->obstack, NULL);
xfree (data);
xml_fetch_another fetcher, void *fetcher_baton,
int depth)
{
- enum XML_Error err;
struct gdb_xml_parser *parser;
struct xinclude_parsing_data *data;
struct cleanup *back_to;
char *result = NULL;
- data = XZALLOC (struct xinclude_parsing_data);
+ data = XCNEW (struct xinclude_parsing_data);
obstack_init (&data->obstack);
back_to = make_cleanup (xml_xinclude_cleanup, data);
- parser = gdb_xml_create_parser_and_cleanup (name, xinclude_elements, data);
+ gdb_xml_create_parser_and_cleanup (name, xinclude_elements,
+ data, &parser);
parser->is_xinclude = 1;
data->include_depth = depth;
if (gdb_xml_parse (parser, text) == 0)
{
obstack_1grow (&data->obstack, '\0');
- result = xstrdup (obstack_finish (&data->obstack));
+ result = xstrdup ((const char *) obstack_finish (&data->obstack));
if (depth == 0)
- gdb_xml_debug (parser, _("XInclude processing succeeded:\n%s"),
- result);
+ gdb_xml_debug (parser, _("XInclude processing succeeded."));
}
else
result = NULL;
do_cleanups (back_to);
return result;
}
+#endif /* HAVE_LIBEXPAT */
\f
/* Return an XML document which was compiled into GDB, from
return NULL;
}
-#endif /* HAVE_LIBEXPAT */
+/* A to_xfer_partial helper function which reads XML files which were
+ compiled into GDB. The target may call this function from its own
+ to_xfer_partial handler, after converting object and annex to the
+ appropriate filename. */
+
+LONGEST
+xml_builtin_xfer_partial (const char *filename,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ const char *buf;
+ LONGEST len_avail;
+
+ gdb_assert (readbuf != NULL && writebuf == NULL);
+ gdb_assert (filename != NULL);
+
+ buf = fetch_xml_builtin (filename);
+ if (buf == NULL)
+ return -1;
+
+ len_avail = strlen (buf);
+ if (offset >= len_avail)
+ return 0;
+
+ if (len > len_avail - offset)
+ len = len_avail - offset;
+ memcpy (readbuf, buf + offset, len);
+ return len;
+}
+\f
static void
show_debug_xml (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("XML debugging is %s.\n"), value);
}
+void
+obstack_xml_printf (struct obstack *obstack, const char *format, ...)
+{
+ va_list ap;
+ const char *f;
+ const char *prev;
+ int percent = 0;
+
+ va_start (ap, format);
+
+ prev = format;
+ for (f = format; *f; f++)
+ {
+ if (percent)
+ {
+ switch (*f)
+ {
+ case 's':
+ {
+ char *p;
+ char *a = va_arg (ap, char *);
+
+ obstack_grow (obstack, prev, f - prev - 1);
+ p = xml_escape_text (a);
+ obstack_grow_str (obstack, p);
+ xfree (p);
+ prev = f + 1;
+ }
+ break;
+ }
+ percent = 0;
+ }
+ else if (*f == '%')
+ percent = 1;
+ }
+
+ obstack_grow_str (obstack, prev);
+ va_end (ap);
+}
+
+char *
+xml_fetch_content_from_file (const char *filename, void *baton)
+{
+ const char *dirname = (const char *) baton;
+ FILE *file;
+ struct cleanup *back_to;
+ char *text;
+ size_t len, offset;
+
+ if (dirname && *dirname)
+ {
+ char *fullname = concat (dirname, "/", filename, (char *) NULL);
+
+ if (fullname == NULL)
+ malloc_failure (0);
+ file = gdb_fopen_cloexec (fullname, FOPEN_RT);
+ xfree (fullname);
+ }
+ else
+ file = gdb_fopen_cloexec (filename, FOPEN_RT);
+
+ if (file == NULL)
+ return NULL;
+
+ back_to = make_cleanup_fclose (file);
+
+ /* Read in the whole file, one chunk at a time. */
+ len = 4096;
+ offset = 0;
+ text = (char *) xmalloc (len);
+ make_cleanup (free_current_contents, &text);
+ while (1)
+ {
+ size_t bytes_read;
+
+ /* Continue reading where the last read left off. Leave at least
+ one byte so that we can NUL-terminate the result. */
+ bytes_read = fread (text + offset, 1, len - offset - 1, file);
+ if (ferror (file))
+ {
+ warning (_("Read error from \"%s\""), filename);
+ do_cleanups (back_to);
+ return NULL;
+ }
+
+ offset += bytes_read;
+
+ if (feof (file))
+ break;
+
+ len = len * 2;
+ text = (char *) xrealloc (text, len);
+ }
+
+ fclose (file);
+ discard_cleanups (back_to);
+
+ text[offset] = '\0';
+ return text;
+}
+
void _initialize_xml_support (void);
void