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++
 /* 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
    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 "config.h"
 #endif
 
-#include <ctype.h>
+#include "safe-ctype.h"
+
 #include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
@@ -51,6 +53,8 @@ char * realloc ();
 
 #include "libiberty.h"
 
 
 #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
 #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
 
 #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' };
 
 
 static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
 
@@ -153,9 +157,9 @@ struct work_stuff
 
 static const struct optable
 {
 
 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) */
 } 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;
 
   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, " ");}
 #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 */
 
 
 /* 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 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 *));
 #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 *));
 
 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));
 
 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));
 
 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.
 
 /* 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;
 
 {
   int count = 0;
 
-  if (! isdigit ((unsigned char)**type))
+  if (! ISDIGIT ((unsigned char)**type))
     return -1;
 
     return -1;
 
-  while (isdigit ((unsigned char)**type))
+  while (ISDIGIT ((unsigned char)**type))
     {
       count *= 10;
 
     {
       count *= 10;
 
@@ -478,7 +565,7 @@ consume_count (type)
         ten.  */
       if ((count % 10) != 0)
        {
         ten.  */
       if ((count % 10) != 0)
        {
-         while (isdigit ((unsigned char) **type))
+         while (ISDIGIT ((unsigned char) **type))
            (*type)++;
          return -1;
        }
            (*type)++;
          return -1;
        }
@@ -504,7 +591,7 @@ consume_count_with_underscores (mangled)
   if (**mangled == '_')
     {
       (*mangled)++;
   if (**mangled == '_')
     {
       (*mangled)++;
-      if (!isdigit ((unsigned char)**mangled))
+      if (!ISDIGIT ((unsigned char)**mangled))
        return -1;
 
       idx = consume_count (mangled);
        return -1;
 
       idx = consume_count (mangled);
@@ -636,14 +723,14 @@ cplus_demangle_opname (opname, result, options)
        }
     }
   else if (opname[0] == '_' && opname[1] == '_'
        }
     }
   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;
     {
       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)
            {
              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;
            {
              /* 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)
                {
                  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;
          && 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
            {
              len1 = len - 10;
              if ((int) strlen (optable[i].in) == len1
@@ -702,7 +789,7 @@ cplus_demangle_opname (opname, result, options)
       else
        {
          size_t i;
       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
            {
              len1 = len - 3;
              if ((int) strlen (optable[i].in) == len1
@@ -733,6 +820,7 @@ cplus_demangle_opname (opname, result, options)
   return ret;
 
 }
   return ret;
 
 }
+
 /* Takes operator name as e.g. "++" and returns mangled
    operator name (e.g. "postincrement_expr"), or NULL if not found.
 
 /* 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);
   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)
     {
       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);
 }
 
   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
 /* 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.
    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];
 {
   char *ret;
   struct work_stuff work[1];
+
+  if (current_demangling_style == no_demangling)
+    return xstrdup (mangled);
+
   memset ((char *) work, 0, sizeof (work));
   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);
 
   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
 /* 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;
   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;
   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;
   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);
   /* 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;
     }
       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.  */
 
   /* 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);
   else
     {
       string_appendn (declp, "", 1);
-      demangled = declp -> b;
+      demangled = declp->b;
     }
   return (demangled);
 }
     }
   return (demangled);
 }
@@ -1154,7 +1524,7 @@ demangle_signature (work, mangled, declp)
          break;
 
        case '_':
          break;
 
        case '_':
-         if (GNU_DEMANGLING && expect_return_type)
+         if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
            {
              /* Read the return type. */
              string return_type;
            {
              /* Read the return type. */
              string return_type;
@@ -1180,7 +1550,7 @@ demangle_signature (work, mangled, declp)
             if (HP_DEMANGLING)
               {
                 (*mangled)++;
             if (HP_DEMANGLING)
               {
                 (*mangled)++;
-                while (**mangled && isdigit ((unsigned char)**mangled))
+                while (**mangled && ISDIGIT ((unsigned char)**mangled))
                   (*mangled)++;
               }
             else
                   (*mangled)++;
               }
             else
@@ -1188,7 +1558,7 @@ demangle_signature (work, mangled, declp)
          break;
 
        case 'H':
          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,
            {
              /* 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);
 
 
          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);
 
            {
              size_t l = strlen (optable[i].in);
 
@@ -1433,6 +1801,11 @@ demangle_integral_value (work, mangled, s)
     {
       int value;
 
     {
       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'.  */
       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)++;
        }
          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 (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.  */
            (*mangled)++;
 
          /* All is well.  */
@@ -1478,7 +1883,7 @@ demangle_real_value (work, mangled, s)
       string_appendn (s, "-", 1);
       (*mangled)++;
     }
       string_appendn (s, "-", 1);
       (*mangled)++;
     }
-  while (isdigit ((unsigned char)**mangled))
+  while (ISDIGIT ((unsigned char)**mangled))
     {
       string_appendn (s, *mangled, 1);
       (*mangled)++;
     {
       string_appendn (s, *mangled, 1);
       (*mangled)++;
@@ -1487,7 +1892,7 @@ demangle_real_value (work, mangled, s)
     {
       string_appendn (s, ".", 1);
       (*mangled)++;
     {
       string_appendn (s, ".", 1);
       (*mangled)++;
-      while (isdigit ((unsigned char)**mangled))
+      while (ISDIGIT ((unsigned char)**mangled))
        {
          string_appendn (s, *mangled, 1);
          (*mangled)++;
        {
          string_appendn (s, *mangled, 1);
          (*mangled)++;
@@ -1497,7 +1902,7 @@ demangle_real_value (work, mangled, s)
     {
       string_appendn (s, "e", 1);
       (*mangled)++;
     {
       string_appendn (s, "e", 1);
       (*mangled)++;
-      while (isdigit ((unsigned char)**mangled))
+      while (ISDIGIT ((unsigned char)**mangled))
        {
          string_appendn (s, *mangled, 1);
          (*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,
    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
    types.  */
 
 static int
@@ -2148,6 +2553,86 @@ demangle_class (work, mangled, declp)
   return (success);
 }
 
   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
 /*
 
 LOCAL FUNCTION
@@ -2163,6 +2648,8 @@ SYNOPSIS
 DESCRIPTION
 
        Consume and demangle the prefix of the mangled name.
 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
 
        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)
     {
     }
   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)
        {
          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)
               || (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);
        {
          *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);
     }
       /* 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,
           && (scan[2] != 't'))
     {
       /* Mangled name starts with "__".  Skip over any leading '_' characters,
@@ -2336,29 +2823,16 @@ demangle_prefix (work, mangled, declp)
              success = 0;
            }
          else
              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
        }
     }
   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
     {
     }
   else
     {
@@ -2451,7 +2925,7 @@ gnu_special (work, mangled, declp)
                                           1);
              break;
            default:
                                           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
                {
                  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;
            }
              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;
        }
          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_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')
          break;
        }
       if (success && **mangled != '\0')
@@ -2959,13 +3452,13 @@ get_count (type, count)
   const char *p;
   int n;
 
   const char *p;
   int n;
 
-  if (!isdigit ((unsigned char)**type))
+  if (!ISDIGIT ((unsigned char)**type))
     return (0);
   else
     {
       *count = **type - '0';
       (*type)++;
     return (0);
   else
     {
       *count = **type - '0';
       (*type)++;
-      if (isdigit ((unsigned char)**type))
+      if (ISDIGIT ((unsigned char)**type))
        {
          p = *type;
          n = *count;
        {
          p = *type;
          n = *count;
@@ -2975,7 +3468,7 @@ get_count (type, count)
              n += *p - '0';
              p++;
            }
              n += *p - '0';
              p++;
            }
-         while (isdigit ((unsigned char)*p));
+         while (ISDIGIT ((unsigned char)*p));
          if (*p == '_')
            {
              *type = p + 1;
          if (*p == '_')
            {
              *type = p + 1;
@@ -3105,7 +3598,7 @@ do_type (work, mangled, result)
            if (**mangled != 'Q')
              string_prepend (&decl, SCOPE_STRING (work));
 
            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
              {
                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 done = 0;
   int success = 1;
   char buf[10];
-  int dec = 0;
+  unsigned int dec = 0;
   string btype;
   type_kind_t tk = tk_integral;
 
   string btype;
   type_kind_t tk = tk_integral;
 
@@ -3425,7 +3918,7 @@ demangle_fund_type (work, mangled, result)
       break;
     case 'G':
       (*mangled)++;
       break;
     case 'G':
       (*mangled)++;
-      if (!isdigit ((unsigned char)**mangled))
+      if (!ISDIGIT ((unsigned char)**mangled))
        {
          success = 0;
          break;
        {
          success = 0;
          break;
@@ -3455,7 +3948,7 @@ demangle_fund_type (work, mangled, result)
          *mangled += min (strlen (*mangled), 2);
        }
       sscanf (buf, "%x", &dec);
          *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;
       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 */
     }
 
   /* 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 */
     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);
     {
       char_str[0] = **mangled;
       string_append (result, char_str);
@@ -3621,10 +4114,10 @@ snarf_numeric_literal (args, arg)
   else if (**args == '+')
     (*args)++;
 
   else if (**args == '+')
     (*args)++;
 
-  if (!isdigit ((unsigned char)**args))
+  if (!ISDIGIT ((unsigned char)**args))
     return 0;
 
     return 0;
 
-  while (isdigit ((unsigned char)**args))
+  while (ISDIGIT ((unsigned char)**args))
     {
       char_str[0] = **args;
       string_append (arg, char_str);
     {
       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)
        {
       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
            {
              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
        {
        }
       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
            {
              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] == '_'
        }
     }
   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.  */
     {
       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)
            {
              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.  */
          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)
                {
                  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 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)
 
 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, "\
 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);
           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);
 }
 
   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'},
   {"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}
   {"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 *
 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.  */
 /* 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
 extern int main PARAMS ((int, char **));
 
 int
@@ -4526,12 +5060,13 @@ main (argc, argv)
   char *result;
   int c;
   const char *valid_symbols;
   char *result;
   int c;
   const char *valid_symbols;
+  enum demangling_styles style = auto_demangling;
 
   program_name = argv[0];
 
   strip_underscore = prepends_underscore;
 
 
   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)
        {
     {
       switch (c)
        {
@@ -4549,36 +5084,18 @@ main (argc, argv)
        case '_':
          strip_underscore = 1;
          break;
        case '_':
          strip_underscore = 1;
          break;
-       case 'j':
-         flags |= DMGL_JAVA;
-         break;
        case 's':
        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;
        }
     }
          break;
        }
     }
@@ -4597,12 +5114,18 @@ main (argc, argv)
        case gnu_demangling:
        case lucid_demangling:
        case arm_demangling:
        case gnu_demangling:
        case lucid_demangling:
        case arm_demangling:
+       case java_demangling:
        case edg_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;
          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
        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.  */
          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;
            {
              if (i >= MBUF_SIZE-1)
                break;
@@ -4626,7 +5149,7 @@ main (argc, argv)
            {
              int skip_first = 0;
 
            {
              int skip_first = 0;
 
-             if (mbuffer[0] == '.')
+             if (mbuffer[0] == '.' || mbuffer[0] == '$')
                ++skip_first;
              if (strip_underscore && mbuffer[skip_first] == '_')
                ++skip_first;
                ++skip_first;
              if (strip_underscore && mbuffer[skip_first] == '_')
                ++skip_first;
@@ -4635,7 +5158,7 @@ main (argc, argv)
                skip_first = i;
 
              mbuffer[i] = 0;
                skip_first = i;
 
              mbuffer[i] = 0;
-
+             flags |= (int) style;
              result = cplus_demangle (mbuffer + skip_first, flags);
              if (result)
                {
              result = cplus_demangle (mbuffer + skip_first, flags);
              if (result)
                {
@@ -4652,6 +5175,7 @@ main (argc, argv)
          if (c == EOF)
            break;
          putchar (c);
          if (c == EOF)
            break;
          putchar (c);
+         fflush (stdout);
        }
     }
 
        }
     }