OSDN Git Service

* demangle.h (no_demangling): New.
[pf3gnuchains/gcc-fork.git] / libiberty / cplus-dem.c
index 0c49c55..a35ff14 100644 (file)
@@ -1,5 +1,6 @@
 /* Demangler for GNU C++
-   Copyright 1989, 91, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
+   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001 Free Software Foundation, Inc.
    Written by James Clark (jjc@jclark.uucp)
    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
    Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
@@ -33,7 +34,8 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #endif
 
-#include <ctype.h>
+#include "safe-ctype.h"
+
 #include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
@@ -51,6 +53,8 @@ char * realloc ();
 
 #include "libiberty.h"
 
+static char *ada_demangle  PARAMS ((const char *, int));
+
 #define min(X,Y) (((X) < (Y)) ? (X) : (Y))
 
 /* A value at least one greater than the maximum number of characters
@@ -98,7 +102,7 @@ mystrstr (s1, s2)
 #define CPLUS_MARKER '$'
 #endif
 
-enum demangling_styles current_demangling_style = gnu_demangling;
+enum demangling_styles current_demangling_style = auto_demangling;
 
 static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
 
@@ -153,9 +157,9 @@ struct work_stuff
 
 static const struct optable
 {
-  const char *in;
-  const char *out;
-  int flags;
+  const char *const in;
+  const char *const out;
+  const int flags;
 } optable[] = {
   {"nw",         " new",       DMGL_ANSI},     /* new (1.92,    ansi) */
   {"dl",         " delete",    DMGL_ANSI},     /* new (1.92,    ansi) */
@@ -252,6 +256,73 @@ typedef enum type_kind_t
   tk_real
 } type_kind_t;
 
+const struct demangler_engine libiberty_demanglers[] =
+{
+  {
+    NO_DEMANGLING_STYLE_STRING,
+    no_demangling,
+    "Demangling disabled"
+  }
+  ,
+  {
+    AUTO_DEMANGLING_STYLE_STRING,
+      auto_demangling,
+      "Automatic selection based on executable"
+  }
+  ,
+  {
+    GNU_DEMANGLING_STYLE_STRING,
+      gnu_demangling,
+      "GNU (g++) style demangling"
+  }
+  ,
+  {
+    LUCID_DEMANGLING_STYLE_STRING,
+      lucid_demangling,
+      "Lucid (lcc) style demangling"
+  }
+  ,
+  {
+    ARM_DEMANGLING_STYLE_STRING,
+      arm_demangling,
+      "ARM style demangling"
+  }
+  ,
+  {
+    HP_DEMANGLING_STYLE_STRING,
+      hp_demangling,
+      "HP (aCC) style demangling"
+  }
+  ,
+  {
+    EDG_DEMANGLING_STYLE_STRING,
+      edg_demangling,
+      "EDG style demangling"
+  }
+  ,
+  {
+    GNU_V3_DEMANGLING_STYLE_STRING,
+    gnu_v3_demangling,
+    "GNU (g++) V3 ABI-style demangling"
+  }
+  ,
+  {
+    JAVA_DEMANGLING_STYLE_STRING,
+    java_demangling,
+    "Java style demangling"
+  }
+  ,
+  {
+    GNAT_DEMANGLING_STYLE_STRING,
+    gnat_demangling,
+    "GNAT style demangling"
+  }
+  ,
+  {
+    NULL, unknown_demangling, NULL
+  }
+};
+
 #define STRING_EMPTY(str)      ((str) -> b == (str) -> p)
 #define PREPEND_BLANK(str)     {if (!STRING_EMPTY(str)) \
     string_prepend(str, " ");}
@@ -268,12 +339,21 @@ typedef enum type_kind_t
 
 /* Prototypes for local functions */
 
+static void
+delete_work_stuff PARAMS ((struct work_stuff *));
+
+static void
+delete_non_B_K_work_stuff PARAMS ((struct work_stuff *));
+
 static char *
 mop_up PARAMS ((struct work_stuff *, string *, int));
 
 static void
 squangle_mop_up PARAMS ((struct work_stuff *));
 
+static void
+work_stuff_copy_to_from PARAMS ((struct work_stuff *, struct work_stuff *));
+
 #if 0
 static int
 demangle_method_args PARAMS ((struct work_stuff *, const char **, string *));
@@ -379,6 +459,10 @@ static void
 demangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
                                const char *));
 
+static int
+iterate_demangle_function PARAMS ((struct work_stuff *,
+                                  const char **, string *, const char *));
+
 static void
 remember_type PARAMS ((struct work_stuff *, const char *, int));
 
@@ -450,6 +534,9 @@ static void
 recursively_demangle PARAMS ((struct work_stuff *, const char **, string *,
                              int));
 
+static void
+grow_vect PARAMS ((void **, size_t *, size_t, int));
+
 /* Translate count to integer, consuming tokens in the process.
    Conversion terminates on the first non-digit character.
 
@@ -464,10 +551,10 @@ consume_count (type)
 {
   int count = 0;
 
-  if (! isdigit ((unsigned char)**type))
+  if (! ISDIGIT ((unsigned char)**type))
     return -1;
 
-  while (isdigit ((unsigned char)**type))
+  while (ISDIGIT ((unsigned char)**type))
     {
       count *= 10;
 
@@ -478,7 +565,7 @@ consume_count (type)
         ten.  */
       if ((count % 10) != 0)
        {
-         while (isdigit ((unsigned char) **type))
+         while (ISDIGIT ((unsigned char) **type))
            (*type)++;
          return -1;
        }
@@ -504,7 +591,7 @@ consume_count_with_underscores (mangled)
   if (**mangled == '_')
     {
       (*mangled)++;
-      if (!isdigit ((unsigned char)**mangled))
+      if (!ISDIGIT ((unsigned char)**mangled))
        return -1;
 
       idx = consume_count (mangled);
@@ -636,14 +723,14 @@ cplus_demangle_opname (opname, result, options)
        }
     }
   else if (opname[0] == '_' && opname[1] == '_'
-          && islower(opname[2])
-          && islower(opname[3]))
+          && ISLOWER((unsigned char)opname[2])
+          && ISLOWER((unsigned char)opname[3]))
     {
       if (opname[4] == '\0')
        {
          /* Operator.  */
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              if (strlen (optable[i].in) == 2
                  && memcmp (optable[i].in, opname + 2, 2) == 0)
@@ -661,7 +748,7 @@ cplus_demangle_opname (opname, result, options)
            {
              /* Assignment.  */
              size_t i;
-             for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+             for (i = 0; i < ARRAY_SIZE (optable); i++)
                {
                  if (strlen (optable[i].in) == 3
                      && memcmp (optable[i].in, opname + 2, 3) == 0)
@@ -685,7 +772,7 @@ cplus_demangle_opname (opname, result, options)
          && memcmp (opname + 3, "assign_", 7) == 0)
        {
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              len1 = len - 10;
              if ((int) strlen (optable[i].in) == len1
@@ -702,7 +789,7 @@ cplus_demangle_opname (opname, result, options)
       else
        {
          size_t i;
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              len1 = len - 3;
              if ((int) strlen (optable[i].in) == len1
@@ -733,6 +820,7 @@ cplus_demangle_opname (opname, result, options)
   return ret;
 
 }
+
 /* Takes operator name as e.g. "++" and returns mangled
    operator name (e.g. "postincrement_expr"), or NULL if not found.
 
@@ -748,7 +836,7 @@ cplus_mangle_opname (opname, options)
   int len;
 
   len = strlen (opname);
-  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+  for (i = 0; i < ARRAY_SIZE (optable); i++)
     {
       if ((int) strlen (optable[i].out) == len
          && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
@@ -758,10 +846,44 @@ cplus_mangle_opname (opname, options)
   return (0);
 }
 
+/* Add a routine to set the demangling style to be sure it is valid and
+   allow for any demangler initialization that maybe necessary. */
+
+enum demangling_styles
+cplus_demangle_set_style (style)
+     enum demangling_styles style;
+{
+  const struct demangler_engine *demangler = libiberty_demanglers; 
+
+  for (; demangler->demangling_style != unknown_demangling; ++demangler)
+    if (style == demangler->demangling_style)
+      {
+       current_demangling_style = style;
+       return current_demangling_style;
+      }
+
+  return unknown_demangling;
+}
+
+/* Do string name to style translation */
+
+enum demangling_styles
+cplus_demangle_name_to_style (name)
+     const char *name;
+{
+  const struct demangler_engine *demangler = libiberty_demanglers; 
+
+  for (; demangler->demangling_style != unknown_demangling; ++demangler)
+    if (strcmp (name, demangler->demangling_style_name) == 0)
+      return demangler->demangling_style;
+
+  return unknown_demangling;
+}
+
 /* char *cplus_demangle (const char *mangled, int options)
 
    If MANGLED is a mangled function name produced by GNU C++, then
-   a pointer to a malloced string giving a C++ representation
+   a pointer to a @code{malloc}ed string giving a C++ representation
    of the name will be returned; otherwise NULL will be returned.
    It is the caller's responsibility to free the string which
    is returned.
@@ -793,10 +915,32 @@ cplus_demangle (mangled, options)
 {
   char *ret;
   struct work_stuff work[1];
+
+  if (current_demangling_style == no_demangling)
+    return xstrdup (mangled);
+
   memset ((char *) work, 0, sizeof (work));
-  work -> options = options;
-  if ((work -> options & DMGL_STYLE_MASK) == 0)
-    work -> options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+  work->options = options;
+  if ((work->options & DMGL_STYLE_MASK) == 0)
+    work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+
+  /* The V3 ABI demangling is implemented elsewhere.  */
+  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
+    {
+      ret = cplus_demangle_v3 (mangled);
+      if (ret || GNU_V3_DEMANGLING)
+       return ret;
+    }
+
+  if (JAVA_DEMANGLING)
+    {
+      ret = java_demangle_v3 (mangled);
+      if (ret)
+        return ret;
+    }
+
+  if (GNAT_DEMANGLING)
+    return ada_demangle(mangled,options);
 
   ret = internal_cplus_demangle (work, mangled);
   squangle_mop_up (work);
@@ -804,6 +948,139 @@ cplus_demangle (mangled, options)
 }
 
 
+/* Assuming *OLD_VECT points to an array of *SIZE objects of size
+   ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
+   updating *OLD_VECT and *SIZE as necessary.  */
+
+static void
+grow_vect (old_vect, size, min_size, element_size)
+     void **old_vect;
+     size_t *size;
+     size_t min_size;
+     int element_size;
+{
+  if (*size < min_size)
+    {
+      *size *= 2;
+      if (*size < min_size)
+       *size = min_size;
+      *old_vect = xrealloc (*old_vect, *size * element_size);
+    }
+}
+
+/* Demangle ada names:
+   1. Discard final __{DIGIT}+ or ${DIGIT}+
+   2. Convert other instances of embedded "__" to `.'.
+   3. Discard leading _ada_.
+   4. Remove everything after first ___ if it is followed by 'X'.
+   5. Put symbols that should be suppressed in <...> brackets.
+   The resulting string is valid until the next call of ada_demangle.  */
+
+static char *
+ada_demangle (mangled, option)
+     const char *mangled;
+     int option ATTRIBUTE_UNUSED;
+{
+  int i, j;
+  int len0;
+  const char* p;
+  char *demangled = NULL;
+  int at_start_name;
+  int changed;
+  char *demangling_buffer = NULL;
+  size_t demangling_buffer_size = 0;
+  
+  changed = 0;
+
+  if (strncmp (mangled, "_ada_", 5) == 0)
+    {
+      mangled += 5;
+      changed = 1;
+    }
+  
+  if (mangled[0] == '_' || mangled[0] == '<')
+    goto Suppress;
+  
+  p = strstr (mangled, "___");
+  if (p == NULL)
+    len0 = strlen (mangled);
+  else
+    {
+      if (p[3] == 'X')
+       {
+         len0 = p - mangled;
+         changed = 1;
+       }
+      else
+       goto Suppress;
+    }
+  
+  /* Make demangled big enough for possible expansion by operator name.  */
+  grow_vect ((void **) &(demangling_buffer),
+            &demangling_buffer_size,  2 * len0 + 1,
+            sizeof (char));
+  demangled = demangling_buffer;
+  
+  if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
+    for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
+      ;
+    if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
+      {
+       len0 = i - 1;
+       changed = 1;
+      }
+    else if (mangled[i] == '$')
+      {
+       len0 = i;
+       changed = 1;
+      }
+  }
+  
+  for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
+       i += 1, j += 1)
+    demangled[j] = mangled[i];
+  
+  at_start_name = 1;
+  while (i < len0)
+    {
+      at_start_name = 0;
+      
+      if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
+       {
+         demangled[j] = '.';
+         changed = at_start_name = 1;
+         i += 2; j += 1;
+       }
+      else
+       {
+         demangled[j] = mangled[i];
+         i += 1;  j += 1;
+       }
+    }
+  demangled[j] = '\000';
+  
+  for (i = 0; demangled[i] != '\0'; i += 1)
+    if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
+      goto Suppress;
+
+  if (! changed)
+    return NULL;
+  else
+    return demangled;
+  
+ Suppress:
+  grow_vect ((void **) &(demangling_buffer),
+            &demangling_buffer_size,  strlen (mangled) + 3,
+            sizeof (char));
+  demangled = demangling_buffer;
+  if (mangled[0] == '<')
+     strcpy (demangled, mangled);
+  else
+    sprintf (demangled, "<%s>", mangled);
+
+  return demangled;
+}
+
 /* This function performs most of what cplus_demangle use to do, but
    to be able to demangle a name with a B, K or n code, we need to
    have a longer term memory of what types have been seen. The original
@@ -819,7 +1096,7 @@ internal_cplus_demangle (work, mangled)
   string decl;
   int success = 0;
   char *demangled = NULL;
-  int s1,s2,s3,s4;
+  int s1, s2, s3, s4;
   s1 = work->constructor;
   s2 = work->destructor;
   s3 = work->static_type;
@@ -872,7 +1149,7 @@ internal_cplus_demangle (work, mangled)
   work->destructor = s2;
   work->static_type = s3;
   work->type_quals = s4;
-  return (demangled);
+  return demangled;
 }
 
 
@@ -893,16 +1170,85 @@ squangle_mop_up (work)
     }
 }
 
-/* Clear out any mangled storage */
 
-static char *
-mop_up (work, declp, success)
-     struct work_stuff *work;
-     string *declp;
-     int success;
+/* Copy the work state and storage.  */
+
+static void
+work_stuff_copy_to_from (to, from)
+     struct work_stuff *to;
+     struct work_stuff *from;
 {
-  char *demangled = NULL;
+  int i;
+
+  delete_work_stuff (to);
+
+  /* Shallow-copy scalars.  */
+  memcpy (to, from, sizeof (*to));
+
+  /* Deep-copy dynamic storage.  */
+  if (from->typevec_size)
+    to->typevec
+      = (char **) xmalloc (from->typevec_size * sizeof (to->typevec[0]));
+
+  for (i = 0; i < from->ntypes; i++)
+    {
+      int len = strlen (from->typevec[i]) + 1;
+
+      to->typevec[i] = xmalloc (len);
+      memcpy (to->typevec[i], from->typevec[i], len);
+    }
+
+  if (from->ksize)
+    to->ktypevec
+      = (char **) xmalloc (from->ksize * sizeof (to->ktypevec[0]));
+
+  for (i = 0; i < from->numk; i++)
+    {
+      int len = strlen (from->ktypevec[i]) + 1;
+
+      to->ktypevec[i] = xmalloc (len);
+      memcpy (to->ktypevec[i], from->ktypevec[i], len);
+    }
+
+  if (from->bsize)
+    to->btypevec
+      = (char **) xmalloc (from->bsize * sizeof (to->btypevec[0]));
+
+  for (i = 0; i < from->numb; i++)
+    {
+      int len = strlen (from->btypevec[i]) + 1;
+
+      to->btypevec[i] = xmalloc (len);
+      memcpy (to->btypevec[i], from->btypevec[i], len);
+    }
+
+  if (from->ntmpl_args)
+    to->tmpl_argvec
+      = xmalloc (from->ntmpl_args * sizeof (to->tmpl_argvec[0]));
+
+  for (i = 0; i < from->ntmpl_args; i++)
+    {
+      int len = strlen (from->tmpl_argvec[i]) + 1;
+
+      to->tmpl_argvec[i] = xmalloc (len);
+      memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
+    }
 
+  if (from->previous_argument)
+    {
+      to->previous_argument = (string*) xmalloc (sizeof (string));
+      string_init (to->previous_argument);
+      string_appends (to->previous_argument, from->previous_argument);
+    }
+}
+
+
+/* Delete dynamic stuff in work_stuff that is not to be re-used.  */
+
+static void
+delete_non_B_K_work_stuff (work)
+     struct work_stuff *work;
+{
   /* Discard the remembered types, if any.  */
 
   forget_types (work);
@@ -929,6 +1275,30 @@ mop_up (work, declp, success)
       free ((char*) work->previous_argument);
       work->previous_argument = NULL;
     }
+}
+
+
+/* Delete all dynamic storage in work_stuff.  */
+static void
+delete_work_stuff (work)
+     struct work_stuff *work;
+{
+  delete_non_B_K_work_stuff (work);
+  squangle_mop_up (work);
+}
+
+
+/* Clear out any mangled storage */
+
+static char *
+mop_up (work, declp, success)
+     struct work_stuff *work;
+     string *declp;
+     int success;
+{
+  char *demangled = NULL;
+
+  delete_non_B_K_work_stuff (work);
 
   /* If demangling was successful, ensure that the demangled string is null
      terminated and return it.  Otherwise, free the demangling decl.  */
@@ -940,7 +1310,7 @@ mop_up (work, declp, success)
   else
     {
       string_appendn (declp, "", 1);
-      demangled = declp -> b;
+      demangled = declp->b;
     }
   return (demangled);
 }
@@ -1154,7 +1524,7 @@ demangle_signature (work, mangled, declp)
          break;
 
        case '_':
-         if (GNU_DEMANGLING && expect_return_type)
+         if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
            {
              /* Read the return type. */
              string return_type;
@@ -1180,7 +1550,7 @@ demangle_signature (work, mangled, declp)
             if (HP_DEMANGLING)
               {
                 (*mangled)++;
-                while (**mangled && isdigit ((unsigned char)**mangled))
+                while (**mangled && ISDIGIT ((unsigned char)**mangled))
                   (*mangled)++;
               }
             else
@@ -1188,7 +1558,7 @@ demangle_signature (work, mangled, declp)
          break;
 
        case 'H':
-         if (GNU_DEMANGLING)
+         if (AUTO_DEMANGLING || GNU_DEMANGLING)
            {
              /* A G++ template function.  Read the template arguments. */
              success = demangle_template (work, mangled, declp, 0, 0,
@@ -1379,9 +1749,7 @@ demangle_expression (work, mangled, s, tk)
 
          len = strlen (*mangled);
 
-         for (i = 0;
-              i < sizeof (optable) / sizeof (optable [0]);
-              ++i)
+         for (i = 0; i < ARRAY_SIZE (optable); ++i)
            {
              size_t l = strlen (optable[i].in);
 
@@ -1433,6 +1801,11 @@ demangle_integral_value (work, mangled, s)
     {
       int value;
 
+      /* By default, we let the number decide whether we shall consume an
+        underscore.  */
+      int consume_following_underscore = 0;
+      int leave_following_underscore = 0;
+
       success = 0;
 
       /* Negative numbers are indicated with a leading `m'.  */
@@ -1441,17 +1814,49 @@ demangle_integral_value (work, mangled, s)
          string_appendn (s, "-", 1);
          (*mangled)++;
        }
+      else if (mangled[0][0] == '_' && mangled[0][1] == 'm')
+       {
+         /* Since consume_count_with_underscores does not handle the
+            `m'-prefix we must do it here, using consume_count and
+            adjusting underscores: we have to consume the underscore
+            matching the prepended one.  */
+         consume_following_underscore = 1;
+         string_appendn (s, "-", 1);
+         (*mangled) += 2;
+       }
+      else if (**mangled == '_')
+       {
+         /* Do not consume a following underscore;
+            consume_following_underscore will consume what should be
+            consumed.  */
+         leave_following_underscore = 1;
+       }
+
+      /* We must call consume_count if we expect to remove a trailing
+        underscore, since consume_count_with_underscores expects
+        the leading underscore (that we consumed) if it is to handle
+        multi-digit numbers.  */
+      if (consume_following_underscore)
+       value = consume_count (mangled);
+      else
+       value = consume_count_with_underscores (mangled);
 
-      /* Read the rest of the number.  */
-      value = consume_count_with_underscores (mangled);
       if (value != -1)
        {
          char buf[INTBUF_SIZE];
          sprintf (buf, "%d", value);
          string_append (s, buf);
 
-         /* If the next character is an underscore, skip it.  */
-         if (**mangled == '_')
+         /* Numbers not otherwise delimited, might have an underscore
+            appended as a delimeter, which we should skip.
+
+            ??? This used to always remove a following underscore, which
+            is wrong.  If other (arbitrary) cases are followed by an
+            underscore, we need to do something more radical.  */
+
+         if ((value > 9 || consume_following_underscore)
+             && ! leave_following_underscore
+             && **mangled == '_')
            (*mangled)++;
 
          /* All is well.  */
@@ -1478,7 +1883,7 @@ demangle_real_value (work, mangled, s)
       string_appendn (s, "-", 1);
       (*mangled)++;
     }
-  while (isdigit ((unsigned char)**mangled))
+  while (ISDIGIT ((unsigned char)**mangled))
     {
       string_appendn (s, *mangled, 1);
       (*mangled)++;
@@ -1487,7 +1892,7 @@ demangle_real_value (work, mangled, s)
     {
       string_appendn (s, ".", 1);
       (*mangled)++;
-      while (isdigit ((unsigned char)**mangled))
+      while (ISDIGIT ((unsigned char)**mangled))
        {
          string_appendn (s, *mangled, 1);
          (*mangled)++;
@@ -1497,7 +1902,7 @@ demangle_real_value (work, mangled, s)
     {
       string_appendn (s, "e", 1);
       (*mangled)++;
-      while (isdigit ((unsigned char)**mangled))
+      while (ISDIGIT ((unsigned char)**mangled))
        {
          string_appendn (s, *mangled, 1);
          (*mangled)++;
@@ -1616,7 +2021,7 @@ demangle_template_value_parm (work, mangled, s, tk)
    template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
    non-NULL.  If IS_TYPE is nonzero, this template is a type template,
    not a function template.  If both IS_TYPE and REMEMBER are nonzero,
-   the tmeplate is remembered in the list of back-referenceable
+   the template is remembered in the list of back-referenceable
    types.  */
 
 static int
@@ -2148,6 +2553,86 @@ demangle_class (work, mangled, declp)
   return (success);
 }
 
+
+/* Called when there's a "__" in the mangled name, with `scan' pointing to
+   the rightmost guess.
+
+   Find the correct "__"-sequence where the function name ends and the
+   signature starts, which is ambiguous with GNU mangling.
+   Call demangle_signature here, so we can make sure we found the right
+   one; *mangled will be consumed so caller will not make further calls to
+   demangle_signature.  */
+
+static int
+iterate_demangle_function (work, mangled, declp, scan)
+     struct work_stuff *work;
+     const char **mangled;
+     string *declp;
+     const char *scan;
+{
+  const char *mangle_init = *mangled;
+  int success = 0;
+  string decl_init;
+  struct work_stuff work_init;
+
+  if (*(scan + 2) == '\0')
+    return 0;
+
+  /* Do not iterate for some demangling modes, or if there's only one
+     "__"-sequence.  This is the normal case.  */
+  if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
+      || mystrstr (scan + 2, "__") == NULL)
+    {
+      demangle_function_name (work, mangled, declp, scan);
+      return 1;
+    }
+
+  /* Save state so we can restart if the guess at the correct "__" was
+     wrong.  */
+  string_init (&decl_init);
+  string_appends (&decl_init, declp);
+  memset (&work_init, 0, sizeof work_init);
+  work_stuff_copy_to_from (&work_init, work);
+
+  /* Iterate over occurrences of __, allowing names and types to have a
+     "__" sequence in them.  We must start with the first (not the last)
+     occurrence, since "__" most often occur between independent mangled
+     parts, hence starting at the last occurence inside a signature
+     might get us a "successful" demangling of the signature.  */
+
+  while (scan[2])
+    {
+      demangle_function_name (work, mangled, declp, scan);
+      success = demangle_signature (work, mangled, declp);
+      if (success)
+       break;
+
+      /* Reset demangle state for the next round.  */
+      *mangled = mangle_init;
+      string_clear (declp);
+      string_appends (declp, &decl_init);
+      work_stuff_copy_to_from (work, &work_init);
+
+      /* Leave this underscore-sequence.  */
+      scan += 2;
+
+      /* Scan for the next "__" sequence.  */
+      while (*scan && (scan[0] != '_' || scan[1] != '_'))
+       scan++;
+
+      /* Move to last "__" in this sequence.  */
+      while (*scan && *scan == '_')
+       scan++;
+      scan -= 2;
+    }
+
+  /* Delete saved state.  */
+  delete_work_stuff (&work_init);
+  string_delete (&decl_init);
+
+  return success;
+}
+
 /*
 
 LOCAL FUNCTION
@@ -2163,6 +2648,8 @@ SYNOPSIS
 DESCRIPTION
 
        Consume and demangle the prefix of the mangled name.
+       While processing the function name root, arrange to call
+       demangle_signature if the root is ambiguous.
 
        DECLP points to the string buffer into which demangled output is
        placed.  On entry, the buffer is empty.  On exit it contains
@@ -2266,20 +2753,20 @@ demangle_prefix (work, mangled, declp)
     }
   else if (work -> static_type)
     {
-      if (!isdigit ((unsigned char)scan[0]) && (scan[0] != 't'))
+      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
        {
          success = 0;
        }
     }
   else if ((scan == *mangled)
-          && (isdigit ((unsigned char)scan[2]) || (scan[2] == 'Q')
+          && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
               || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
     {
       /* The ARM says nothing about the mangling of local variables.
         But cfront mangles local variables by prepending __<nesting_level>
         to them. As an extension to ARM demangling we handle this case.  */
       if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
-         && isdigit ((unsigned char)scan[2]))
+         && ISDIGIT ((unsigned char)scan[2]))
        {
          *mangled = scan + 2;
          consume_count (mangled);
@@ -2316,7 +2803,7 @@ demangle_prefix (work, mangled, declp)
       /* EDG template? */
       demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
     }
-  else if ((scan == *mangled) && !isdigit ((unsigned char)scan[2])
+  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
           && (scan[2] != 't'))
     {
       /* Mangled name starts with "__".  Skip over any leading '_' characters,
@@ -2336,29 +2823,16 @@ demangle_prefix (work, mangled, declp)
              success = 0;
            }
          else
-           {
-             const char *tmp;
-
-              /* Look for the LAST occurrence of __, allowing names to
-                 have the '__' sequence embedded in them. */
-             if (!(ARM_DEMANGLING || HP_DEMANGLING))
-               {
-                 while ((tmp = mystrstr (scan + 2, "__")) != NULL)
-                   scan = tmp;
-               }
-             if (*(scan + 2) == '\0')
-               success = 0;
-              else
-                demangle_function_name (work, mangled, declp, scan);
-           }
+           return iterate_demangle_function (work, mangled, declp, scan);
        }
     }
   else if (*(scan + 2) != '\0')
     {
       /* Mangled name does not start with "__" but does have one somewhere
         in there with non empty stuff after it.  Looks like a global
-        function name.  */
-      demangle_function_name (work, mangled, declp, scan);
+        function name.  Iterate over all "__":s until the right
+        one is found.  */
+      return iterate_demangle_function (work, mangled, declp, scan);
     }
   else
     {
@@ -2451,7 +2925,7 @@ gnu_special (work, mangled, declp)
                                           1);
              break;
            default:
-             if (isdigit((unsigned char)*mangled[0]))
+             if (ISDIGIT((unsigned char)*mangled[0]))
                {
                  n = consume_count(mangled);
                  /* We may be seeing a too-large size, or else a
@@ -2512,6 +2986,25 @@ gnu_special (work, mangled, declp)
              success = 0;
              break;
            }
+
+         if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
+             && (*mangled)[9] == 'N'
+             && (*mangled)[8] == (*mangled)[10]
+             && strchr (cplus_markers, (*mangled)[8]))
+           {
+             /* A member of the anonymous namespace.  There's information
+                about what identifier or filename it was keyed to, but
+                it's just there to make the mangled name unique; we just
+                step over it.  */
+             string_append (declp, "{anonymous}");
+             (*mangled) += n;
+
+             /* Now p points to the marker before the N, so we need to
+                update it to the first marker after what we consumed.  */
+             p = strpbrk (*mangled, cplus_markers);
+             break;
+           }
+
          string_appendn (declp, *mangled, n);
          (*mangled) += n;
        }
@@ -2573,7 +3066,7 @@ gnu_special (work, mangled, declp)
          success = demangle_template (work, mangled, declp, 0, 1, 1);
          break;
        default:
-         success = demangle_fund_type (work, mangled, declp);
+         success = do_type (work, mangled, declp);
          break;
        }
       if (success && **mangled != '\0')
@@ -2959,13 +3452,13 @@ get_count (type, count)
   const char *p;
   int n;
 
-  if (!isdigit ((unsigned char)**type))
+  if (!ISDIGIT ((unsigned char)**type))
     return (0);
   else
     {
       *count = **type - '0';
       (*type)++;
-      if (isdigit ((unsigned char)**type))
+      if (ISDIGIT ((unsigned char)**type))
        {
          p = *type;
          n = *count;
@@ -2975,7 +3468,7 @@ get_count (type, count)
              n += *p - '0';
              p++;
            }
-         while (isdigit ((unsigned char)*p));
+         while (ISDIGIT ((unsigned char)*p));
          if (*p == '_')
            {
              *type = p + 1;
@@ -3105,7 +3598,7 @@ do_type (work, mangled, result)
            if (**mangled != 'Q')
              string_prepend (&decl, SCOPE_STRING (work));
 
-           if (isdigit ((unsigned char)**mangled))
+           if (ISDIGIT ((unsigned char)**mangled))
              {
                n = consume_count (mangled);
                if (n == -1
@@ -3311,7 +3804,7 @@ demangle_fund_type (work, mangled, result)
   int done = 0;
   int success = 1;
   char buf[10];
-  int dec = 0;
+  unsigned int dec = 0;
   string btype;
   type_kind_t tk = tk_integral;
 
@@ -3425,7 +3918,7 @@ demangle_fund_type (work, mangled, result)
       break;
     case 'G':
       (*mangled)++;
-      if (!isdigit ((unsigned char)**mangled))
+      if (!ISDIGIT ((unsigned char)**mangled))
        {
          success = 0;
          break;
@@ -3455,7 +3948,7 @@ demangle_fund_type (work, mangled, result)
          *mangled += min (strlen (*mangled), 2);
        }
       sscanf (buf, "%x", &dec);
-      sprintf (buf, "int%i_t", dec);
+      sprintf (buf, "int%u_t", dec);
       APPEND_BLANK (result);
       string_append (result, buf);
       break;
@@ -3537,12 +4030,12 @@ do_hpacc_template_const_value (work, mangled, result)
     }
 
   /* We have to be looking at an integer now */
-  if (!(isdigit ((unsigned char)**mangled)))
+  if (!(ISDIGIT ((unsigned char)**mangled)))
     return 0;
 
   /* We only deal with integral values for template
      parameters -- so it's OK to look only for digits */
-  while (isdigit ((unsigned char)**mangled))
+  while (ISDIGIT ((unsigned char)**mangled))
     {
       char_str[0] = **mangled;
       string_append (result, char_str);
@@ -3621,10 +4114,10 @@ snarf_numeric_literal (args, arg)
   else if (**args == '+')
     (*args)++;
 
-  if (!isdigit ((unsigned char)**args))
+  if (!ISDIGIT ((unsigned char)**args))
     return 0;
 
-  while (isdigit ((unsigned char)**args))
+  while (ISDIGIT ((unsigned char)**args))
     {
       char_str[0] = **args;
       string_append (arg, char_str);
@@ -4130,7 +4623,7 @@ demangle_function_name (work, mangled, declp, scan)
       if (declp->p - declp->b >= 10 /* op$assign_ */
          && memcmp (declp->b + 3, "assign_", 7) == 0)
        {
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              int len = declp->p - declp->b - 10;
              if ((int) strlen (optable[i].in) == len
@@ -4146,7 +4639,7 @@ demangle_function_name (work, mangled, declp, scan)
        }
       else
        {
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              int len = declp->p - declp->b - 3;
              if ((int) strlen (optable[i].in) == len
@@ -4188,13 +4681,13 @@ demangle_function_name (work, mangled, declp, scan)
        }
     }
   else if (declp->b[0] == '_' && declp->b[1] == '_'
-          && islower(declp->b[2])
-          && islower(declp->b[3]))
+          && ISLOWER((unsigned char)declp->b[2])
+          && ISLOWER((unsigned char)declp->b[3]))
     {
       if (declp->b[4] == '\0')
        {
          /* Operator.  */
-         for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+         for (i = 0; i < ARRAY_SIZE (optable); i++)
            {
              if (strlen (optable[i].in) == 2
                  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
@@ -4211,7 +4704,7 @@ demangle_function_name (work, mangled, declp, scan)
          if (declp->b[2] == 'a' && declp->b[5] == '\0')
            {
              /* Assignment.  */
-             for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
+             for (i = 0; i < ARRAY_SIZE (optable); i++)
                {
                  if (strlen (optable[i].in) == 3
                      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
@@ -4402,6 +4895,7 @@ static int flags = DMGL_PARAMS | DMGL_ANSI;
 static void demangle_it PARAMS ((char *));
 static void usage PARAMS ((FILE *, int)) ATTRIBUTE_NORETURN;
 static void fatal PARAMS ((const char *)) ATTRIBUTE_NORETURN;
+static void print_demangler_list PARAMS ((FILE *));
 
 static void
 demangle_it (mangled_name)
@@ -4421,16 +4915,43 @@ demangle_it (mangled_name)
     }
 }
 
+static void 
+print_demangler_list (stream)
+     FILE *stream;
+{
+  const struct demangler_engine *demangler; 
+
+  fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
+  
+  for (demangler = libiberty_demanglers + 1;
+       demangler->demangling_style != unknown_demangling;
+       ++demangler)
+    fprintf (stream, ",%s", demangler->demangling_style_name);
+
+  fprintf (stream, "}");
+}
+
 static void
 usage (stream, status)
      FILE *stream;
      int status;
 {
   fprintf (stream, "\
-Usage: %s [-_] [-n] [-s {gnu,lucid,arm,hp,edg}] [--strip-underscores]\n\
-       [--no-strip-underscores] [--format={gnu,lucid,arm,hp,edg}]\n\
-      [--help] [--version] [arg...]\n",
+Usage: %s [-_] [-n] [--strip-underscores] [--no-strip-underscores] \n",
           program_name);
+
+  fprintf (stream, "\
+       [-s ");
+  print_demangler_list (stream);
+  fprintf (stream, "]\n");
+
+  fprintf (stream, "\
+       [--format ");
+  print_demangler_list (stream);
+  fprintf (stream, "]\n");
+
+  fprintf (stream, "\
+       [--help] [--version] [arg...]\n");
   exit (status);
 }
 
@@ -4446,7 +4967,6 @@ static struct option long_options[] = {
   {"strip-underscores", no_argument, 0, '_'},
   {"format", required_argument, 0, 's'},
   {"help", no_argument, 0, 'h'},
-  {"java", no_argument, 0, 'j'},
   {"no-strip-underscores", no_argument, 0, 'n'},
   {"version", no_argument, 0, 'v'},
   {0, no_argument, 0, 0}
@@ -4468,6 +4988,9 @@ standard_symbol_characters PARAMS ((void));
 static const char *
 hp_symbol_characters PARAMS ((void));
 
+static const char *
+gnu_v3_symbol_characters PARAMS ((void));
+
 /* Return the string of non-alnum characters that may occur 
    as a valid symbol component, in the standard assembler symbol
    syntax.  */
@@ -4516,6 +5039,17 @@ hp_symbol_characters ()
 }
 
 
+/* Return the string of non-alnum characters that may occur 
+   as a valid symbol component in the GNU C++ V3 ABI mangling
+   scheme.  */
+
+static const char *
+gnu_v3_symbol_characters ()
+{
+  return "_$.";
+}
+
+
 extern int main PARAMS ((int, char **));
 
 int
@@ -4526,12 +5060,13 @@ main (argc, argv)
   char *result;
   int c;
   const char *valid_symbols;
+  enum demangling_styles style = auto_demangling;
 
   program_name = argv[0];
 
   strip_underscore = prepends_underscore;
 
-  while ((c = getopt_long (argc, argv, "_ns:j", long_options, (int *) 0)) != EOF)
+  while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
     {
       switch (c)
        {
@@ -4549,36 +5084,18 @@ main (argc, argv)
        case '_':
          strip_underscore = 1;
          break;
-       case 'j':
-         flags |= DMGL_JAVA;
-         break;
        case 's':
-         if (strcmp (optarg, "gnu") == 0)
-           {
-             current_demangling_style = gnu_demangling;
-           }
-         else if (strcmp (optarg, "lucid") == 0)
-           {
-             current_demangling_style = lucid_demangling;
-           }
-         else if (strcmp (optarg, "arm") == 0)
-           {
-             current_demangling_style = arm_demangling;
-           }
-         else if (strcmp (optarg, "hp") == 0)
-           {
-             current_demangling_style = hp_demangling;
-           }
-          else if (strcmp (optarg, "edg") == 0)
-            {
-              current_demangling_style = edg_demangling;
-            }
-         else
-           {
-             fprintf (stderr, "%s: unknown demangling style `%s'\n",
-                      program_name, optarg);
-             return (1);
-           }
+         {
+           style = cplus_demangle_name_to_style (optarg);
+           if (style == unknown_demangling)
+             {
+               fprintf (stderr, "%s: unknown demangling style `%s'\n",
+                        program_name, optarg);
+               return (1);
+             }
+           else
+             cplus_demangle_set_style (style);
+         }
          break;
        }
     }
@@ -4597,12 +5114,18 @@ main (argc, argv)
        case gnu_demangling:
        case lucid_demangling:
        case arm_demangling:
+       case java_demangling:
        case edg_demangling:
+       case gnat_demangling:
+       case auto_demangling:
          valid_symbols = standard_symbol_characters ();
          break;
        case hp_demangling:
          valid_symbols = hp_symbol_characters ();
          break;
+       case gnu_v3_demangling:
+         valid_symbols = gnu_v3_symbol_characters ();
+         break;
        default:
          /* Folks should explicitly indicate the appropriate alphabet for
             each demangling.  Providing a default would allow the
@@ -4615,7 +5138,7 @@ main (argc, argv)
          int i = 0;
          c = getchar ();
          /* Try to read a label.  */
-         while (c != EOF && (isalnum (c) || strchr (valid_symbols, c)))
+         while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
            {
              if (i >= MBUF_SIZE-1)
                break;
@@ -4626,7 +5149,7 @@ main (argc, argv)
            {
              int skip_first = 0;
 
-             if (mbuffer[0] == '.')
+             if (mbuffer[0] == '.' || mbuffer[0] == '$')
                ++skip_first;
              if (strip_underscore && mbuffer[skip_first] == '_')
                ++skip_first;
@@ -4635,7 +5158,7 @@ main (argc, argv)
                skip_first = i;
 
              mbuffer[i] = 0;
-
+             flags |= (int) style;
              result = cplus_demangle (mbuffer + skip_first, flags);
              if (result)
                {
@@ -4652,6 +5175,7 @@ main (argc, argv)
          if (c == EOF)
            break;
          putchar (c);
+         fflush (stdout);
        }
     }