2009-12-02 Tristan Gingold <gingold@adacore.com>
[binutils-gdb.git] / gdb / xml-support.c
index 1a31db4805b4e2532af446cb45749a98d51ca556..ad20d3bf954f1838bd3b06b474633f34851674e5 100644 (file)
@@ -1,12 +1,12 @@
 /* Helper routines for parsing XML using Expat.
 
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009 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 "exceptions.h"
+#include "xml-support.h"
+
+#include "gdb_string.h"
+#include "safe-ctype.h"
 
 /* Debugging flag.  */
 static int debug_xml;
@@ -29,17 +32,14 @@ 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
@@ -544,6 +544,8 @@ gdb_xml_parse (struct gdb_xml_parser *parser, const char *buffer)
   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)
@@ -631,6 +633,14 @@ gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser,
   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
@@ -645,7 +655,7 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser,
   void *ret;
 
   for (enums = attribute->handler_data; enums->name != NULL; enums++)
-    if (strcmp (enums->name, value) == 0)
+    if (strcasecmp (enums->name, value) == 0)
       break;
 
   if (enums->name == NULL)
@@ -861,8 +871,7 @@ xml_process_xincludes (const char *name, const char *text,
       result = xstrdup (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;
@@ -870,6 +879,7 @@ xml_process_xincludes (const char *name, const char *text,
   do_cleanups (back_to);
   return result;
 }
+#endif /* HAVE_LIBEXPAT */
 \f
 
 /* Return an XML document which was compiled into GDB, from
@@ -887,7 +897,36 @@ fetch_xml_builtin (const char *filename)
   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,
@@ -896,6 +935,167 @@ show_debug_xml (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("XML debugging is %s.\n"), value);
 }
 
+/* Return a malloc allocated string with special characters from TEXT
+   replaced by entity references.  */
+
+char *
+xml_escape_text (const char *text)
+{
+  char *result;
+  int i, special;
+
+  /* Compute the length of the result.  */
+  for (i = 0, special = 0; text[i] != '\0'; i++)
+    switch (text[i])
+      {
+      case '\'':
+      case '\"':
+       special += 5;
+       break;
+      case '&':
+       special += 4;
+       break;
+      case '<':
+      case '>':
+       special += 3;
+       break;
+      default:
+       break;
+      }
+
+  /* Expand the result.  */
+  result = xmalloc (i + special + 1);
+  for (i = 0, special = 0; text[i] != '\0'; i++)
+    switch (text[i])
+      {
+      case '\'':
+       strcpy (result + i + special, "&apos;");
+       special += 5;
+       break;
+      case '\"':
+       strcpy (result + i + special, "&quot;");
+       special += 5;
+       break;
+      case '&':
+       strcpy (result + i + special, "&amp;");
+       special += 4;
+       break;
+      case '<':
+       strcpy (result + i + special, "&lt;");
+       special += 3;
+       break;
+      case '>':
+       strcpy (result + i + special, "&gt;");
+       special += 3;
+       break;
+      default:
+       result[i + special] = text[i];
+       break;
+      }
+  result[i + special] = '\0';
+
+  return result;
+}
+
+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 = 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)
+       nomem (0);
+      file = fopen (fullname, FOPEN_RT);
+      xfree (fullname);
+    }
+  else
+    file = fopen (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 = 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 = xrealloc (text, len);
+    }
+
+  fclose (file);
+  discard_cleanups (back_to);
+
+  text[offset] = '\0';
+  return text;
+}
+
 void _initialize_xml_support (void);
 
 void