]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libiberty/cplus-dem.c
Update gennews for GCC 14.
[thirdparty/gcc.git] / libiberty / cplus-dem.c
index 59afcd371ba5f4caa5240a1e286235e29d737d1a..ee9e84f5d6b139927b1b0ca30f7d049526a28fd5 100644 (file)
@@ -1,6 +1,5 @@
 /* Demangler for GNU C++
-   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1989-2024 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
@@ -27,14 +26,8 @@ Library General Public License for more details.
 
 You should have received a copy of the GNU Library General Public
 License along with libiberty; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
-
-   This file imports xmalloc and xrealloc, which are like malloc and
-   realloc except that they generate a fatal error if there is no
-   available memory.  */
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* This file lives in both GCC and libiberty.  When making changes, please
    try not to break either.  */
@@ -45,207 +38,23 @@ Boston, MA 02111-1307, USA.  */
 
 #include "safe-ctype.h"
 
-#include <sys/types.h>
 #include <string.h>
-#include <stdio.h>
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #else
-char * malloc ();
-char * realloc ();
+void * malloc ();
+void * realloc ();
 #endif
 
 #include <demangle.h>
 #undef CURRENT_DEMANGLING_STYLE
-#define CURRENT_DEMANGLING_STYLE work->options
+#define CURRENT_DEMANGLING_STYLE options
 
 #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
-   that will be output when using the `%d' format with `printf'.  */
-#define INTBUF_SIZE 32
-
-extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
-
-/* In order to allow a single demangler executable to demangle strings
-   using various common values of CPLUS_MARKER, as well as any specific
-   one set at compile time, we maintain a string containing all the
-   commonly used ones, and check to see if the marker we are looking for
-   is in that string.  CPLUS_MARKER is usually '$' on systems where the
-   assembler can deal with that.  Where the assembler can't, it's usually
-   '.' (but on many systems '.' is used for other things).  We put the
-   current defined CPLUS_MARKER first (which defaults to '$'), followed
-   by the next most common value, followed by an explicit '$' in case
-   the value of CPLUS_MARKER is not '$'.
-
-   We could avoid this if we could just get g++ to tell us what the actual
-   cplus marker character is as part of the debug information, perhaps by
-   ensuring that it is the character that terminates the gcc<n>_compiled
-   marker symbol (FIXME).  */
-
-#if !defined (CPLUS_MARKER)
-#define CPLUS_MARKER '$'
-#endif
-
 enum demangling_styles current_demangling_style = auto_demangling;
 
-static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
-
-static char char_str[2] = { '\000', '\000' };
-
-void
-set_cplus_marker_for_demangling (ch)
-     int ch;
-{
-  cplus_markers[0] = ch;
-}
-
-typedef struct string          /* Beware: these aren't required to be */
-{                              /*  '\0' terminated.  */
-  char *b;                     /* pointer to start of string */
-  char *p;                     /* pointer after last character */
-  char *e;                     /* pointer after end of allocated space */
-} string;
-
-/* Stuff that is shared between sub-routines.
-   Using a shared structure allows cplus_demangle to be reentrant.  */
-
-struct work_stuff
-{
-  int options;
-  char **typevec;
-  char **ktypevec;
-  char **btypevec;
-  int numk;
-  int numb;
-  int ksize;
-  int bsize;
-  int ntypes;
-  int typevec_size;
-  int constructor;
-  int destructor;
-  int static_type;     /* A static member function */
-  int temp_start;       /* index in demangled to start of template args */
-  int type_quals;       /* The type qualifiers.  */
-  int dllimported;     /* Symbol imported from a PE DLL */
-  char **tmpl_argvec;   /* Template function arguments. */
-  int ntmpl_args;       /* The number of template function arguments. */
-  int forgetting_types; /* Nonzero if we are not remembering the types
-                          we see.  */
-  string* previous_argument; /* The last function argument demangled.  */
-  int nrepeats;         /* The number of times to repeat the previous
-                          argument.  */
-};
-
-#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
-#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
-
-static const struct optable
-{
-  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) */
-  {"new",        " new",       0},             /* old (1.91,    and 1.x) */
-  {"delete",     " delete",    0},             /* old (1.91,    and 1.x) */
-  {"vn",         " new []",    DMGL_ANSI},     /* GNU, pending ansi */
-  {"vd",         " delete []", DMGL_ANSI},     /* GNU, pending ansi */
-  {"as",         "=",          DMGL_ANSI},     /* ansi */
-  {"ne",         "!=",         DMGL_ANSI},     /* old, ansi */
-  {"eq",         "==",         DMGL_ANSI},     /* old, ansi */
-  {"ge",         ">=",         DMGL_ANSI},     /* old, ansi */
-  {"gt",         ">",          DMGL_ANSI},     /* old, ansi */
-  {"le",         "<=",         DMGL_ANSI},     /* old, ansi */
-  {"lt",         "<",          DMGL_ANSI},     /* old, ansi */
-  {"plus",       "+",          0},             /* old */
-  {"pl",         "+",          DMGL_ANSI},     /* ansi */
-  {"apl",        "+=",         DMGL_ANSI},     /* ansi */
-  {"minus",      "-",          0},             /* old */
-  {"mi",         "-",          DMGL_ANSI},     /* ansi */
-  {"ami",        "-=",         DMGL_ANSI},     /* ansi */
-  {"mult",       "*",          0},             /* old */
-  {"ml",         "*",          DMGL_ANSI},     /* ansi */
-  {"amu",        "*=",         DMGL_ANSI},     /* ansi (ARM/Lucid) */
-  {"aml",        "*=",         DMGL_ANSI},     /* ansi (GNU/g++) */
-  {"convert",    "+",          0},             /* old (unary +) */
-  {"negate",     "-",          0},             /* old (unary -) */
-  {"trunc_mod",          "%",          0},             /* old */
-  {"md",         "%",          DMGL_ANSI},     /* ansi */
-  {"amd",        "%=",         DMGL_ANSI},     /* ansi */
-  {"trunc_div",          "/",          0},             /* old */
-  {"dv",         "/",          DMGL_ANSI},     /* ansi */
-  {"adv",        "/=",         DMGL_ANSI},     /* ansi */
-  {"truth_andif", "&&",                0},             /* old */
-  {"aa",         "&&",         DMGL_ANSI},     /* ansi */
-  {"truth_orif",  "||",                0},             /* old */
-  {"oo",         "||",         DMGL_ANSI},     /* ansi */
-  {"truth_not",          "!",          0},             /* old */
-  {"nt",         "!",          DMGL_ANSI},     /* ansi */
-  {"postincrement","++",       0},             /* old */
-  {"pp",         "++",         DMGL_ANSI},     /* ansi */
-  {"postdecrement","--",       0},             /* old */
-  {"mm",         "--",         DMGL_ANSI},     /* ansi */
-  {"bit_ior",    "|",          0},             /* old */
-  {"or",         "|",          DMGL_ANSI},     /* ansi */
-  {"aor",        "|=",         DMGL_ANSI},     /* ansi */
-  {"bit_xor",    "^",          0},             /* old */
-  {"er",         "^",          DMGL_ANSI},     /* ansi */
-  {"aer",        "^=",         DMGL_ANSI},     /* ansi */
-  {"bit_and",    "&",          0},             /* old */
-  {"ad",         "&",          DMGL_ANSI},     /* ansi */
-  {"aad",        "&=",         DMGL_ANSI},     /* ansi */
-  {"bit_not",    "~",          0},             /* old */
-  {"co",         "~",          DMGL_ANSI},     /* ansi */
-  {"call",       "()",         0},             /* old */
-  {"cl",         "()",         DMGL_ANSI},     /* ansi */
-  {"alshift",    "<<",         0},             /* old */
-  {"ls",         "<<",         DMGL_ANSI},     /* ansi */
-  {"als",        "<<=",        DMGL_ANSI},     /* ansi */
-  {"arshift",    ">>",         0},             /* old */
-  {"rs",         ">>",         DMGL_ANSI},     /* ansi */
-  {"ars",        ">>=",        DMGL_ANSI},     /* ansi */
-  {"component",          "->",         0},             /* old */
-  {"pt",         "->",         DMGL_ANSI},     /* ansi; Lucid C++ form */
-  {"rf",         "->",         DMGL_ANSI},     /* ansi; ARM/GNU form */
-  {"indirect",   "*",          0},             /* old */
-  {"method_call",  "->()",     0},             /* old */
-  {"addr",       "&",          0},             /* old (unary &) */
-  {"array",      "[]",         0},             /* old */
-  {"vc",         "[]",         DMGL_ANSI},     /* ansi */
-  {"compound",   ", ",         0},             /* old */
-  {"cm",         ", ",         DMGL_ANSI},     /* ansi */
-  {"cond",       "?:",         0},             /* old */
-  {"cn",         "?:",         DMGL_ANSI},     /* pseudo-ansi */
-  {"max",        ">?",         0},             /* old */
-  {"mx",         ">?",         DMGL_ANSI},     /* pseudo-ansi */
-  {"min",        "<?",         0},             /* old */
-  {"mn",         "<?",         DMGL_ANSI},     /* pseudo-ansi */
-  {"nop",        "",           0},             /* old (for operator=) */
-  {"rm",         "->*",        DMGL_ANSI},     /* ansi */
-  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
-};
-
-/* These values are used to indicate the various type varieties.
-   They are all non-zero so that they can be used as `success'
-   values.  */
-typedef enum type_kind_t
-{
-  tk_none,
-  tk_pointer,
-  tk_reference,
-  tk_integral,
-  tk_bool,
-  tk_char,
-  tk_real
-} type_kind_t;
-
 const struct demangler_engine libiberty_demanglers[] =
 {
   {
@@ -260,40 +69,10 @@ const struct demangler_engine libiberty_demanglers[] =
       "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"
+    "GNU (g++) V3 (Itanium C++ ABI) style demangling"
   }
   ,
   {
@@ -308,541 +87,28 @@ const struct demangler_engine libiberty_demanglers[] =
     "GNAT style demangling"
   }
   ,
+  {
+    DLANG_DEMANGLING_STYLE_STRING,
+    dlang_demangling,
+    "DLANG style demangling"
+  }
+  ,
+  {
+    RUST_DEMANGLING_STYLE_STRING,
+    rust_demangling,
+    "Rust style demangling"
+  }
+  ,
   {
     NULL, unknown_demangling, NULL
   }
 };
 
-#define STRING_EMPTY(str)      ((str) -> b == (str) -> p)
-#define APPEND_BLANK(str)      {if (!STRING_EMPTY(str)) \
-    string_append(str, " ");}
-#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
-
-/* The scope separator appropriate for the language being demangled.  */
-
-#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
-
-#define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/ARM virtual table prefix */
-#define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
-
-/* 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 *));
-#endif
-
-static char *
-internal_cplus_demangle PARAMS ((struct work_stuff *, const char *));
-
-static int
-demangle_template_template_parm PARAMS ((struct work_stuff *work,
-                                        const char **, string *));
-
-static int
-demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
-                          string *, int, int));
-
-static int
-arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
-               const char **));
-
-static int
-demangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
-                           int, int));
-
-static int
-demangle_class PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-demangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-demangle_signature PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-demangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-gnu_special PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-arm_special PARAMS ((const char **, string *));
-
-static void
-string_need PARAMS ((string *, int));
-
-static void
-string_delete PARAMS ((string *));
-
-static void
-string_init PARAMS ((string *));
-
-static void
-string_clear PARAMS ((string *));
-
-#if 0
-static int
-string_empty PARAMS ((string *));
-#endif
-
-static void
-string_append PARAMS ((string *, const char *));
-
-static void
-string_appends PARAMS ((string *, string *));
-
-static void
-string_appendn PARAMS ((string *, const char *, int));
-
-static void
-string_prepend PARAMS ((string *, const char *));
-
-static void
-string_prependn PARAMS ((string *, const char *, int));
-
-static void
-string_append_template_idx PARAMS ((string *, int));
-
-static int
-get_count PARAMS ((const char **, int *));
-
-static int
-consume_count PARAMS ((const char **));
-
-static int
-consume_count_with_underscores PARAMS ((const char**));
-
-static int
-demangle_args PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-demangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
-
-static int
-do_type PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-do_arg PARAMS ((struct work_stuff *, const char **, string *));
-
-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));
-
-static void
-remember_Btype PARAMS ((struct work_stuff *, const char *, int, int));
-
-static int
-register_Btype PARAMS ((struct work_stuff *));
-
-static void
-remember_Ktype PARAMS ((struct work_stuff *, const char *, int));
-
-static void
-forget_types PARAMS ((struct work_stuff *));
-
-static void
-forget_B_and_K_types PARAMS ((struct work_stuff *));
-
-static void
-string_prepends PARAMS ((string *, string *));
-
-static int
-demangle_template_value_parm PARAMS ((struct work_stuff*, const char**,
-                                     string*, type_kind_t));
-
-static int
-do_hpacc_template_const_value PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-do_hpacc_template_literal PARAMS ((struct work_stuff *, const char **, string *));
-
-static int
-snarf_numeric_literal PARAMS ((const char **, string *));
-
-/* There is a TYPE_QUAL value for each type qualifier.  They can be
-   combined by bitwise-or to form the complete set of qualifiers for a
-   type.  */
-
-#define TYPE_UNQUALIFIED   0x0
-#define TYPE_QUAL_CONST    0x1
-#define TYPE_QUAL_VOLATILE 0x2
-#define TYPE_QUAL_RESTRICT 0x4
-
-static int
-code_for_qualifier PARAMS ((int));
-
-static const char*
-qualifier_string PARAMS ((int));
-
-static const char*
-demangle_qualifier PARAMS ((int));
-
-static int
-demangle_expression PARAMS ((struct work_stuff *, const char **, string *, 
-                            type_kind_t));
-
-static int
-demangle_integral_value PARAMS ((struct work_stuff *, const char **,
-                                string *));
-
-static int
-demangle_real_value PARAMS ((struct work_stuff *, const char **, string *));
-
-static void
-demangle_arm_hp_template PARAMS ((struct work_stuff *, const char **, int,
-                                 string *));
-
-static void
-recursively_demangle PARAMS ((struct work_stuff *, const char **, string *,
-                             int));
-
-static void
-grow_vect PARAMS ((char **, size_t *, size_t, int));
-
-/* Translate count to integer, consuming tokens in the process.
-   Conversion terminates on the first non-digit character.
-
-   Trying to consume something that isn't a count results in no
-   consumption of input and a return of -1.
-
-   Overflow consumes the rest of the digits, and returns -1.  */
-
-static int
-consume_count (type)
-     const char **type;
-{
-  int count = 0;
-
-  if (! ISDIGIT ((unsigned char)**type))
-    return -1;
-
-  while (ISDIGIT ((unsigned char)**type))
-    {
-      count *= 10;
-
-      /* Check for overflow.
-        We assume that count is represented using two's-complement;
-        no power of two is divisible by ten, so if an overflow occurs
-        when multiplying by ten, the result will not be a multiple of
-        ten.  */
-      if ((count % 10) != 0)
-       {
-         while (ISDIGIT ((unsigned char) **type))
-           (*type)++;
-         return -1;
-       }
-
-      count += **type - '0';
-      (*type)++;
-    }
-
-  if (count < 0)
-    count = -1;
-
-  return (count);
-}
-
-
-/* Like consume_count, but for counts that are preceded and followed
-   by '_' if they are greater than 10.  Also, -1 is returned for
-   failure, since 0 can be a valid value.  */
-
-static int
-consume_count_with_underscores (mangled)
-     const char **mangled;
-{
-  int idx;
-
-  if (**mangled == '_')
-    {
-      (*mangled)++;
-      if (!ISDIGIT ((unsigned char)**mangled))
-       return -1;
-
-      idx = consume_count (mangled);
-      if (**mangled != '_')
-       /* The trailing underscore was missing. */
-       return -1;
-
-      (*mangled)++;
-    }
-  else
-    {
-      if (**mangled < '0' || **mangled > '9')
-       return -1;
-
-      idx = **mangled - '0';
-      (*mangled)++;
-    }
-
-  return idx;
-}
-
-/* C is the code for a type-qualifier.  Return the TYPE_QUAL
-   corresponding to this qualifier.  */
-
-static int
-code_for_qualifier (c)
-  int c;
-{
-  switch (c)
-    {
-    case 'C':
-      return TYPE_QUAL_CONST;
-
-    case 'V':
-      return TYPE_QUAL_VOLATILE;
-
-    case 'u':
-      return TYPE_QUAL_RESTRICT;
-
-    default:
-      break;
-    }
-
-  /* C was an invalid qualifier.  */
-  abort ();
-}
-
-/* Return the string corresponding to the qualifiers given by
-   TYPE_QUALS.  */
-
-static const char*
-qualifier_string (type_quals)
-     int type_quals;
-{
-  switch (type_quals)
-    {
-    case TYPE_UNQUALIFIED:
-      return "";
-
-    case TYPE_QUAL_CONST:
-      return "const";
-
-    case TYPE_QUAL_VOLATILE:
-      return "volatile";
-
-    case TYPE_QUAL_RESTRICT:
-      return "__restrict";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
-      return "const volatile";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
-      return "const __restrict";
-
-    case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
-      return "volatile __restrict";
-
-    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
-      return "const volatile __restrict";
-
-    default:
-      break;
-    }
-
-  /* TYPE_QUALS was an invalid qualifier set.  */
-  abort ();
-}
-
-/* C is the code for a type-qualifier.  Return the string
-   corresponding to this qualifier.  This function should only be
-   called with a valid qualifier code.  */
-
-static const char*
-demangle_qualifier (c)
-  int c;
-{
-  return qualifier_string (code_for_qualifier (c));
-}
-
-int
-cplus_demangle_opname (opname, result, options)
-     const char *opname;
-     char *result;
-     int options;
-{
-  int len, len1, ret;
-  string type;
-  struct work_stuff work[1];
-  const char *tem;
-
-  len = strlen(opname);
-  result[0] = '\0';
-  ret = 0;
-  memset ((char *) work, 0, sizeof (work));
-  work->options = options;
-
-  if (opname[0] == '_' && opname[1] == '_'
-      && opname[2] == 'o' && opname[3] == 'p')
-    {
-      /* ANSI.  */
-      /* type conversion operator.  */
-      tem = opname + 4;
-      if (do_type (work, &tem, &type))
-       {
-         strcat (result, "operator ");
-         strncat (result, type.b, type.p - type.b);
-         string_delete (&type);
-         ret = 1;
-       }
-    }
-  else if (opname[0] == '_' && opname[1] == '_'
-          && ISLOWER((unsigned char)opname[2])
-          && ISLOWER((unsigned char)opname[3]))
-    {
-      if (opname[4] == '\0')
-       {
-         /* Operator.  */
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             if (strlen (optable[i].in) == 2
-                 && memcmp (optable[i].in, opname + 2, 2) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-      else
-       {
-         if (opname[2] == 'a' && opname[5] == '\0')
-           {
-             /* Assignment.  */
-             size_t i;
-             for (i = 0; i < ARRAY_SIZE (optable); i++)
-               {
-                 if (strlen (optable[i].in) == 3
-                     && memcmp (optable[i].in, opname + 2, 3) == 0)
-                   {
-                     strcat (result, "operator");
-                     strcat (result, optable[i].out);
-                     ret = 1;
-                     break;
-                   }
-               }
-           }
-       }
-    }
-  else if (len >= 3
-          && opname[0] == 'o'
-          && opname[1] == 'p'
-          && strchr (cplus_markers, opname[2]) != NULL)
-    {
-      /* see if it's an assignment expression */
-      if (len >= 10 /* op$assign_ */
-         && memcmp (opname + 3, "assign_", 7) == 0)
-       {
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             len1 = len - 10;
-             if ((int) strlen (optable[i].in) == len1
-                 && memcmp (optable[i].in, opname + 10, len1) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 strcat (result, "=");
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-      else
-       {
-         size_t i;
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             len1 = len - 3;
-             if ((int) strlen (optable[i].in) == len1
-                 && memcmp (optable[i].in, opname + 3, len1) == 0)
-               {
-                 strcat (result, "operator");
-                 strcat (result, optable[i].out);
-                 ret = 1;
-                 break;
-               }
-           }
-       }
-    }
-  else if (len >= 5 && memcmp (opname, "type", 4) == 0
-          && strchr (cplus_markers, opname[4]) != NULL)
-    {
-      /* type conversion operator */
-      tem = opname + 5;
-      if (do_type (work, &tem, &type))
-       {
-         strcat (result, "operator ");
-         strncat (result, type.b, type.p - type.b);
-         string_delete (&type);
-         ret = 1;
-       }
-    }
-  squangle_mop_up (work);
-  return ret;
-
-}
-
-/* Takes operator name as e.g. "++" and returns mangled
-   operator name (e.g. "postincrement_expr"), or NULL if not found.
-
-   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
-   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
-
-const char *
-cplus_mangle_opname (opname, options)
-     const char *opname;
-     int options;
-{
-  size_t i;
-  int len;
-
-  len = strlen (opname);
-  for (i = 0; i < ARRAY_SIZE (optable); i++)
-    {
-      if ((int) strlen (optable[i].out) == len
-         && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
-         && memcmp (optable[i].out, opname, len) == 0)
-       return optable[i].in;
-    }
-  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;
+cplus_demangle_set_style (enum demangling_styles style)
 {
   const struct demangler_engine *demangler = libiberty_demanglers; 
 
@@ -859,8 +125,7 @@ cplus_demangle_set_style (style)
 /* Do string name to style translation */
 
 enum demangling_styles
-cplus_demangle_name_to_style (name)
-     const char *name;
+cplus_demangle_name_to_style (const char *name)
 {
   const struct demangler_engine *demangler = libiberty_demanglers; 
 
@@ -879,46 +144,34 @@ cplus_demangle_name_to_style (name)
    It is the caller's responsibility to free the string which
    is returned.
 
-   The OPTIONS arg may contain one or more of the following bits:
-
-       DMGL_ANSI       ANSI qualifiers such as `const' and `void' are
-                       included.
-       DMGL_PARAMS     Function parameters are included.
-
-   For example,
-
-   cplus_demangle ("foo__1Ai", DMGL_PARAMS)            => "A::foo(int)"
-   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)        => "A::foo(int)"
-   cplus_demangle ("foo__1Ai", 0)                      => "A::foo"
-
-   cplus_demangle ("foo__1Afe", DMGL_PARAMS)           => "A::foo(float,...)"
-   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
-   cplus_demangle ("foo__1Afe", 0)                     => "A::foo"
-
    Note that any leading underscores, or other such characters prepended by
    the compilation system, are presumed to have already been stripped from
    MANGLED.  */
 
 char *
-cplus_demangle (mangled, options)
-     const char *mangled;
-     int options;
+cplus_demangle (const char *mangled, int 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;
+  if ((options & DMGL_STYLE_MASK) == 0)
+    options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+
+  /* The Rust demangling is implemented elsewhere.
+     Legacy Rust symbols overlap with GNU_V3, so try Rust first.  */
+  if (RUST_DEMANGLING || AUTO_DEMANGLING)
+    {
+      ret = rust_demangle (mangled, options);
+      if (ret || RUST_DEMANGLING)
+        return ret;
+    }
 
   /* The V3 ABI demangling is implemented elsewhere.  */
   if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
     {
-      ret = cplus_demangle_v3 (mangled, work->options);
+      ret = cplus_demangle_v3 (mangled, options);
       if (ret || GNU_V3_DEMANGLING)
        return ret;
     }
@@ -931,3961 +184,279 @@ cplus_demangle (mangled, options)
     }
 
   if (GNAT_DEMANGLING)
-    return ada_demangle(mangled,options);
-
-  ret = internal_cplus_demangle (work, mangled);
-  squangle_mop_up (work);
-  return (ret);
-}
+    return ada_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)
-     char **old_vect;
-     size_t *size;
-     size_t min_size;
-     int element_size;
-{
-  if (*size < min_size)
+  if (DLANG_DEMANGLING || AUTO_DEMANGLING)
     {
-      *size *= 2;
-      if (*size < min_size)
-       *size = min_size;
-      *old_vect = (void *) xrealloc (*old_vect, *size * element_size);
+      ret = dlang_demangle (mangled, options);
+      if (ret)
+       return ret;
     }
+
+  return (ret);
 }
 
-/* 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.  */
+/* Demangle ada names.  The encoding is documented in gcc/ada/exp_dbug.ads.  */
 
-static char *
-ada_demangle (mangled, option)
-     const char *mangled;
-     int option ATTRIBUTE_UNUSED;
+char *
+ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
 {
-  int i, j;
   int len0;
   const char* p;
+  char *d;
   char *demangled = NULL;
-  int at_start_name;
-  int changed;
-  size_t demangled_size = 0;
   
-  changed = 0;
-
+  /* Discard leading _ada_, which is used for library level subprograms.  */
   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 (&demangled,
-            &demangled_size,  2 * len0 + 1,
-            sizeof (char));
-  
-  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;
+    mangled += 5;
+
+  /* All ada unit names are lower-case.  */
+  if (!ISLOWER (mangled[0]))
+    goto unknown;
+
+  /* Most of the demangling will trivially remove chars.  Operator names
+     may add one char but because they are always preceeded by '__' which is
+     replaced by '.', they eventually never expand the size.
+     A few special names such as '___elabs' add a few chars (at most 7), but
+     they occur only once.  */
+  len0 = strlen (mangled) + 7 + 1;
+  demangled = XNEWVEC (char, len0);
   
- Suppress:
-  grow_vect (&demangled,
-            &demangled_size,  strlen (mangled) + 3,
-            sizeof (char));
-
-  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
-   now initializes and cleans up the squangle code info, while internal
-   calls go directly to this routine to avoid resetting that info. */
-
-static char *
-internal_cplus_demangle (work, mangled)
-     struct work_stuff *work;
-     const char *mangled;
-{
-
-  string decl;
-  int success = 0;
-  char *demangled = NULL;
-  int s1, s2, s3, s4;
-  s1 = work->constructor;
-  s2 = work->destructor;
-  s3 = work->static_type;
-  s4 = work->type_quals;
-  work->constructor = work->destructor = 0;
-  work->type_quals = TYPE_UNQUALIFIED;
-  work->dllimported = 0;
-
-  if ((mangled != NULL) && (*mangled != '\0'))
+  d = demangled;
+  p = mangled;
+  while (1)
     {
-      string_init (&decl);
-
-      /* First check to see if gnu style demangling is active and if the
-        string to be demangled contains a CPLUS_MARKER.  If so, attempt to
-        recognize one of the gnu special forms rather than looking for a
-        standard prefix.  In particular, don't worry about whether there
-        is a "__" string in the mangled string.  Consider "_$_5__foo" for
-        example.  */
-
-      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
-       {
-         success = gnu_special (work, &mangled, &decl);
-       }
-      if (!success)
-       {
-         success = demangle_prefix (work, &mangled, &decl);
-       }
-      if (success && (*mangled != '\0'))
-       {
-         success = demangle_signature (work, &mangled, &decl);
-       }
-      if (work->constructor == 2)
+      /* An entity names is expected.  */
+      if (ISLOWER (*p))
         {
-          string_prepend (&decl, "global constructors keyed to ");
-          work->constructor = 0;
+          /* An identifier, which is always lower case.  */
+          do
+            *d++ = *p++;
+          while (ISLOWER(*p) || ISDIGIT (*p)
+                 || (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1]))));
         }
-      else if (work->destructor == 2)
+      else if (p[0] == 'O')
         {
-          string_prepend (&decl, "global destructors keyed to ");
-          work->destructor = 0;
+          /* An operator name.  */
+          static const char * const operators[][2] =
+            {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"},
+             {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"},
+             {"Oxor", "xor"},  {"Oeq", "="},       {"One", "/="},
+             {"Olt", "<"},     {"Ole", "<="},      {"Ogt", ">"},
+             {"Oge", ">="},    {"Oadd", "+"},      {"Osubtract", "-"},
+             {"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"},
+             {"Oexpon", "**"}, {NULL, NULL}};
+          int k;
+
+          for (k = 0; operators[k][0] != NULL; k++)
+            {
+              size_t slen = strlen (operators[k][0]);
+              if (strncmp (p, operators[k][0], slen) == 0)
+                {
+                  p += slen;
+                  slen = strlen (operators[k][1]);
+                  *d++ = '"';
+                  memcpy (d, operators[k][1], slen);
+                  d += slen;
+                  *d++ = '"';
+                  break;
+                }
+            }
+          /* Operator not found.  */
+          if (operators[k][0] == NULL)
+            goto unknown;
         }
-      else if (work->dllimported == 1)
+      else
         {
-          string_prepend (&decl, "import stub for ");
-          work->dllimported = 0;
+          /* Not a GNAT encoding.  */
+          goto unknown;
         }
-      demangled = mop_up (work, &decl, success);
-    }
-  work->constructor = s1;
-  work->destructor = s2;
-  work->static_type = s3;
-  work->type_quals = s4;
-  return demangled;
-}
-
-
-/* Clear out and squangling related storage */
-static void
-squangle_mop_up (work)
-     struct work_stuff *work;
-{
-  /* clean up the B and K type mangling types. */
-  forget_B_and_K_types (work);
-  if (work -> btypevec != NULL)
-    {
-      free ((char *) work -> btypevec);
-    }
-  if (work -> ktypevec != NULL)
-    {
-      free ((char *) work -> ktypevec);
-    }
-}
-
-
-/* Copy the work state and storage.  */
-
-static void
-work_stuff_copy_to_from (to, from)
-     struct work_stuff *to;
-     struct work_stuff *from;
-{
-  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
-      = (char **) 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);
-  if (work -> typevec != NULL)
-    {
-      free ((char *) work -> typevec);
-      work -> typevec = NULL;
-      work -> typevec_size = 0;
-    }
-  if (work->tmpl_argvec)
-    {
-      int i;
-
-      for (i = 0; i < work->ntmpl_args; i++)
-       if (work->tmpl_argvec[i])
-         free ((char*) work->tmpl_argvec[i]);
-
-      free ((char*) work->tmpl_argvec);
-      work->tmpl_argvec = NULL;
-    }
-  if (work->previous_argument)
-    {
-      string_delete (work->previous_argument);
-      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 (!success)
-    {
-      string_delete (declp);
-    }
-  else
-    {
-      string_appendn (declp, "", 1);
-      demangled = declp->b;
-    }
-  return (demangled);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_signature -- demangle the signature part of a mangled name
-
-SYNOPSIS
-
-       static int
-       demangle_signature (struct work_stuff *work, const char **mangled,
-                           string *declp);
-
-DESCRIPTION
-
-       Consume and demangle the signature portion of the mangled name.
-
-       DECLP is the string where demangled output is being built.  At
-       entry it contains the demangled root name from the mangled name
-       prefix.  I.E. either a demangled operator name or the root function
-       name.  In some special cases, it may contain nothing.
-
-       *MANGLED points to the current unconsumed location in the mangled
-       name.  As tokens are consumed and demangling is performed, the
-       pointer is updated to continuously point at the next token to
-       be consumed.
-
-       Demangling GNU style mangled names is nasty because there is no
-       explicit token that marks the start of the outermost function
-       argument list.  */
-
-static int
-demangle_signature (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int success = 1;
-  int func_done = 0;
-  int expect_func = 0;
-  int expect_return_type = 0;
-  const char *oldmangled = NULL;
-  string trawname;
-  string tname;
-
-  while (success && (**mangled != '\0'))
-    {
-      switch (**mangled)
-       {
-       case 'Q':
-         oldmangled = *mangled;
-         success = demangle_qualified (work, mangled, declp, 1, 0);
-         if (success)
-           remember_type (work, oldmangled, *mangled - oldmangled);
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           expect_func = 1;
-         oldmangled = NULL;
-         break;
-
-        case 'K':
-         oldmangled = *mangled;
-         success = demangle_qualified (work, mangled, declp, 1, 0);
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             expect_func = 1;
-           }
-         oldmangled = NULL;
-         break;
-
-       case 'S':
-         /* Static member function */
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-         (*mangled)++;
-         work -> static_type = 1;
-         break;
-
-       case 'C':
-       case 'V':
-       case 'u':
-         work->type_quals |= code_for_qualifier (**mangled);
-
-         /* a qualified member function */
-         if (oldmangled == NULL)
-           oldmangled = *mangled;
-         (*mangled)++;
-         break;
-
-       case 'L':
-         /* Local class name follows after "Lnnn_" */
-         if (HP_DEMANGLING)
-           {
-             while (**mangled && (**mangled != '_'))
-               (*mangled)++;
-             if (!**mangled)
-               success = 0;
-             else
-               (*mangled)++;
-           }
-         else
-           success = 0;
-         break;
-
-       case '0': case '1': case '2': case '3': case '4':
-       case '5': case '6': case '7': case '8': case '9':
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-          work->temp_start = -1; /* uppermost call to demangle_class */
-         success = demangle_class (work, mangled, declp);
-         if (success)
-           {
-             remember_type (work, oldmangled, *mangled - oldmangled);
-           }
-         if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
-           {
-              /* EDG and others will have the "F", so we let the loop cycle
-                 if we are looking at one. */
-              if (**mangled != 'F')
-                 expect_func = 1;
-           }
-         oldmangled = NULL;
-         break;
-
-       case 'B':
-         {
-           string s;
-           success = do_type (work, mangled, &s);
-           if (success)
-             {
-               string_append (&s, SCOPE_STRING (work));
-               string_prepends (declp, &s);
-               string_delete (&s);
-             }
-           oldmangled = NULL;
-           expect_func = 1;
-         }
-         break;
-
-       case 'F':
-         /* Function */
-         /* ARM/HP style demangling includes a specific 'F' character after
-            the class name.  For GNU style, it is just implied.  So we can
-            safely just consume any 'F' at this point and be compatible
-            with either style.  */
-
-         oldmangled = NULL;
-         func_done = 1;
-         (*mangled)++;
-
-         /* For lucid/ARM/HP style we have to forget any types we might
-            have remembered up to this point, since they were not argument
-            types.  GNU style considers all types seen as available for
-            back references.  See comment in demangle_args() */
-
-         if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-           {
-             forget_types (work);
-           }
-         success = demangle_args (work, mangled, declp);
-         /* After picking off the function args, we expect to either
-            find the function return type (preceded by an '_') or the
-            end of the string. */
-         if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
-           {
-             ++(*mangled);
-              /* At this level, we do not care about the return type. */
-              success = do_type (work, mangled, &tname);
-              string_delete (&tname);
+      /* The name can be directly followed by some uppercase letters.  */
+      if (p[0] == 'T' && p[1] == 'K')
+        {
+          /* Task stuff.  */
+          if (p[2] == 'B' && p[3] == 0)
+            {
+              /* Subprogram for task body.  */
+              break;
             }
+          else if (p[2] == '_' && p[3] == '_')
+            {
+              /* Inner declarations in a task.  */
+              p += 4;
+              *d++ = '.';
+              continue;
+            }
+          else
+            goto unknown;
+        }
+      if (p[0] == 'E' && p[1] == 0)
+        {
+          /* Exception name.  */
+          goto unknown;
+        }
+      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
+        {
+          /* Protected type subprogram.  */
+          break;
+        }
+      if ((*p == 'N' || *p == 'S') && p[1] == 0)
+        {
+          /* Enumerated type name table.  */
+          goto unknown;
+        }
+      if (p[0] == 'X')
+        {
+          /* Body nested.  */
+          p++;
+          while (p[0] == 'n' || p[0] == 'b')
+            p++;
+        }
+      if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0))
+        {
+          /* Stream operations.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'R':
+              name = "'Read";
+              break;
+            case 'W':
+              name = "'Write";
+              break;
+            case 'I':
+              name = "'Input";
+              break;
+            case 'O':
+              name = "'Output";
+              break;
+            default:
+              goto unknown;
+            }
+          p += 2;
+          strcpy (d, name);
+          d += strlen (name);
+        }
+      else if (p[0] == 'D')
+        {
+          /* Controlled type operation.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'F':
+              name = ".Finalize";
+              break;
+            case 'A':
+              name = ".Adjust";
+              break;
+            default:
+              goto unknown;
+            }
+          strcpy (d, name);
+          d += strlen (name);
+          break;
+        }
 
-         break;
-
-       case 't':
-         /* G++ Template */
-         string_init(&trawname);
-         string_init(&tname);
-         if (oldmangled == NULL)
-           {
-             oldmangled = *mangled;
-           }
-         success = demangle_template (work, mangled, &tname,
-                                      &trawname, 1, 1);
-         if (success)
-           {
-             remember_type (work, oldmangled, *mangled - oldmangled);
-           }
-         string_append (&tname, SCOPE_STRING (work));
-
-         string_prepends(declp, &tname);
-         if (work -> destructor & 1)
-           {
-             string_prepend (&trawname, "~");
-             string_appends (declp, &trawname);
-             work->destructor -= 1;
-           }
-         if ((work->constructor & 1) || (work->destructor & 1))
-           {
-             string_appends (declp, &trawname);
-             work->constructor -= 1;
-           }
-         string_delete(&trawname);
-         string_delete(&tname);
-         oldmangled = NULL;
-         expect_func = 1;
-         break;
-
-       case '_':
-         if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
-           {
-             /* Read the return type. */
-             string return_type;
-
-             (*mangled)++;
-             success = do_type (work, mangled, &return_type);
-             APPEND_BLANK (&return_type);
-
-             string_prepends (declp, &return_type);
-             string_delete (&return_type);
-             break;
-           }
-         else
-           /* At the outermost level, we cannot have a return type specified,
-              so if we run into another '_' at this point we are dealing with
-              a mangled name that is either bogus, or has been mangled by
-              some algorithm we don't know how to deal with.  So just
-              reject the entire demangling.  */
-            /* However, "_nnn" is an expected suffix for alternate entry point
-               numbered nnn for a function, with HP aCC, so skip over that
-               without reporting failure. pai/1997-09-04 */
-            if (HP_DEMANGLING)
-              {
-                (*mangled)++;
-                while (**mangled && ISDIGIT ((unsigned char)**mangled))
-                  (*mangled)++;
-              }
-            else
-             success = 0;
-         break;
-
-       case 'H':
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             /* A G++ template function.  Read the template arguments. */
-             success = demangle_template (work, mangled, declp, 0, 0,
-                                          0);
-             if (!(work->constructor & 1))
-               expect_return_type = 1;
-             (*mangled)++;
-             break;
-           }
-         else
-           /* fall through */
-           {;}
+      if (p[0] == '_')
+        {
+          /* Separator.  */
+          if (p[1] == '_')
+            {
+              /* Standard separator.  Handled first.  */
+              p += 2;
 
-       default:
-         if (AUTO_DEMANGLING || GNU_DEMANGLING)
-           {
-             /* Assume we have stumbled onto the first outermost function
-                argument token, and start processing args.  */
-             func_done = 1;
-             success = demangle_args (work, mangled, declp);
-           }
-         else
-           {
-             /* Non-GNU demanglers use a specific token to mark the start
-                of the outermost function argument tokens.  Typically 'F',
-                for ARM/HP-demangling, for example.  So if we find something
-                we are not prepared for, it must be an error.  */
-             success = 0;
-           }
-         break;
-       }
-      /*
-       if (AUTO_DEMANGLING || GNU_DEMANGLING)
-       */
-      {
-       if (success && expect_func)
-         {
-           func_done = 1;
-              if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
+              if (ISDIGIT (*p))
                 {
-                  forget_types (work);
+                  /* Overloading number.  */
+                  do
+                    p++;
+                  while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
+                  if (*p == 'X')
+                    {
+                      p++;
+                      while (p[0] == 'n' || p[0] == 'b')
+                        p++;
+                    }
                 }
-           success = demangle_args (work, mangled, declp);
-           /* Since template include the mangling of their return types,
-              we must set expect_func to 0 so that we don't try do
-              demangle more arguments the next time we get here.  */
-           expect_func = 0;
-         }
-      }
-    }
-  if (success && !func_done)
-    {
-      if (AUTO_DEMANGLING || GNU_DEMANGLING)
-       {
-         /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
-            bar__3fooi is 'foo::bar(int)'.  We get here when we find the
-            first case, and need to ensure that the '(void)' gets added to
-            the current declp.  Note that with ARM/HP, the first case
-            represents the name of a static data member 'foo::bar',
-            which is in the current declp, so we leave it alone.  */
-         success = demangle_args (work, mangled, declp);
-       }
-    }
-  if (success && PRINT_ARG_TYPES)
-    {
-      if (work->static_type)
-       string_append (declp, " static");
-      if (work->type_quals != TYPE_UNQUALIFIED)
-       {
-         APPEND_BLANK (declp);
-         string_append (declp, qualifier_string (work->type_quals));
-       }
-    }
-
-  return (success);
-}
-
-#if 0
-
-static int
-demangle_method_args (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int success = 0;
-
-  if (work -> static_type)
-    {
-      string_append (declp, *mangled + 1);
-      *mangled += strlen (*mangled);
-      success = 1;
-    }
-  else
-    {
-      success = demangle_args (work, mangled, declp);
-    }
-  return (success);
-}
-
-#endif
-
-static int
-demangle_template_template_parm (work, mangled, tname)
-     struct work_stuff *work;
-     const char **mangled;
-     string *tname;
-{
-  int i;
-  int r;
-  int need_comma = 0;
-  int success = 1;
-  string temp;
-
-  string_append (tname, "template <");
-  /* get size of template parameter list */
-  if (get_count (mangled, &r))
-    {
-      for (i = 0; i < r; i++)
-       {
-         if (need_comma)
-           {
-             string_append (tname, ", ");
-           }
-
-           /* Z for type parameters */
-           if (**mangled == 'Z')
-             {
-               (*mangled)++;
-               string_append (tname, "class");
-             }
-             /* z for template parameters */
-           else if (**mangled == 'z')
-             {
-               (*mangled)++;
-               success =
-                 demangle_template_template_parm (work, mangled, tname);
-               if (!success)
-                 {
-                   break;
-                 }
-             }
-           else
-             {
-               /* temp is initialized in do_type */
-               success = do_type (work, mangled, &temp);
-               if (success)
-                 {
-                   string_appends (tname, &temp);
-                 }
-               string_delete(&temp);
-               if (!success)
-                 {
-                   break;
-                 }
-             }
-         need_comma = 1;
-       }
-
-    }
-  if (tname->p[-1] == '>')
-    string_append (tname, " ");
-  string_append (tname, "> class");
-  return (success);
-}
-
-static int
-demangle_expression (work, mangled, s, tk)
-     struct work_stuff *work;
-     const char** mangled;
-     string* s;
-     type_kind_t tk;
-{
-  int need_operator = 0;
-  int success;
-
-  success = 1;
-  string_appendn (s, "(", 1);
-  (*mangled)++;
-  while (success && **mangled != 'W' && **mangled != '\0')
-    {
-      if (need_operator)
-       {
-         size_t i;
-         size_t len;
-
-         success = 0;
-
-         len = strlen (*mangled);
-
-         for (i = 0; i < ARRAY_SIZE (optable); ++i)
-           {
-             size_t l = strlen (optable[i].in);
-
-             if (l <= len
-                 && memcmp (optable[i].in, *mangled, l) == 0)
-               {
-                 string_appendn (s, " ", 1);
-                 string_append (s, optable[i].out);
-                 string_appendn (s, " ", 1);
-                 success = 1;
-                 (*mangled) += l;
-                 break;
-               }
-           }
-
-         if (!success)
-           break;
-       }
-      else
-       need_operator = 1;
-
-      success = demangle_template_value_parm (work, mangled, s, tk);
-    }
-
-  if (**mangled != 'W')
-    success = 0;
-  else
-    {
-      string_appendn (s, ")", 1);
-      (*mangled)++;
-    }
-
-  return success;
-}
-
-static int
-demangle_integral_value (work, mangled, s)
-     struct work_stuff *work;
-     const char** mangled;
-     string* s;
-{
-  int success;
-
-  if (**mangled == 'E')
-    success = demangle_expression (work, mangled, s, tk_integral);
-  else if (**mangled == 'Q' || **mangled == 'K')
-    success = demangle_qualified (work, mangled, s, 0, 1);
-  else
-    {
-      int value;
-
-      /* By default, we let the number decide whether we shall consume an
-        underscore.  */
-      int multidigit_without_leading_underscore = 0;
-      int leave_following_underscore = 0;
-
-      success = 0;
+              else if (p[0] == '_' && p[1] != '_')
+                {
+                  /* Special names.  */
+                  static const char * const special[][2] = {
+                    { "_elabb", "'Elab_Body" },
+                    { "_elabs", "'Elab_Spec" },
+                    { "_size", "'Size" },
+                    { "_alignment", "'Alignment" },
+                    { "_assign", ".\":=\"" },
+                    { NULL, NULL }
+                  };
+                  int k;
+
+                  for (k = 0; special[k][0] != NULL; k++)
+                    {
+                      size_t slen = strlen (special[k][0]);
+                      if (strncmp (p, special[k][0], slen) == 0)
+                        {
+                          p += slen;
+                          slen = strlen (special[k][1]);
+                          memcpy (d, special[k][1], slen);
+                          d += slen;
+                          break;
+                        }
+                    }
+                  if (special[k][0] != NULL)
+                    break;
+                  else
+                    goto unknown;
+                }
+              else
+                {
+                  *d++ = '.';
+                  continue;
+                }
+            }
+          else if (p[1] == 'B' || p[1] == 'E')
+            {
+              /* Entry Body or barrier Evaluation.  */
+              p += 2;
+              while (ISDIGIT (*p))
+                p++;
+              if (p[0] == 's' && p[1] == 0)
+                break;
+              else
+                goto unknown;
+            }
+          else
+            goto unknown;
+        }
 
-      if (**mangled == '_')
+      if (p[0] == '.' && ISDIGIT (p[1]))
         {
-         if (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.  */
-             multidigit_without_leading_underscore = 1;
-             string_appendn (s, "-", 1);
-             (*mangled) += 2;
-           }
-         else
-           {
-             /* Do not consume a following underscore;
-                consume_count_with_underscores will consume what
-                should be consumed.  */
-             leave_following_underscore = 1;
-           }
-       }
-      else
-       {
-         /* Negative numbers are indicated with a leading `m'.  */
-         if (**mangled == 'm')
-         {
-           string_appendn (s, "-", 1);
-           (*mangled)++;
-         }
-         /* Since consume_count_with_underscores does not handle
-            multi-digit numbers that do not start with an underscore,
-            and this number can be an integer template parameter,
-            we have to call consume_count. */
-         multidigit_without_leading_underscore = 1;
-         /* These multi-digit numbers never end on an underscore,
-            so if there is one then don't eat it. */
-         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 (multidigit_without_leading_underscore)
-       value = consume_count (mangled);
-      else
-       value = consume_count_with_underscores (mangled);
-
-      if (value != -1)
-       {
-         char buf[INTBUF_SIZE];
-         sprintf (buf, "%d", value);
-         string_append (s, buf);
-
-         /* 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 || multidigit_without_leading_underscore)
-             && ! leave_following_underscore
-             && **mangled == '_')
-           (*mangled)++;
-
-         /* All is well.  */
-         success = 1;
-       }
-      }
-
-  return success;
-}
-
-/* Demangle the real value in MANGLED.  */
-
-static int
-demangle_real_value (work, mangled, s)
-     struct work_stuff *work;
-     const char **mangled;
-     string* s;
-{
-  if (**mangled == 'E')
-    return demangle_expression (work, mangled, s, tk_real);
-
-  if (**mangled == 'm')
-    {
-      string_appendn (s, "-", 1);
-      (*mangled)++;
-    }
-  while (ISDIGIT ((unsigned char)**mangled))
-    {
-      string_appendn (s, *mangled, 1);
-      (*mangled)++;
-    }
-  if (**mangled == '.') /* fraction */
-    {
-      string_appendn (s, ".", 1);
-      (*mangled)++;
-      while (ISDIGIT ((unsigned char)**mangled))
-       {
-         string_appendn (s, *mangled, 1);
-         (*mangled)++;
-       }
-    }
-  if (**mangled == 'e') /* exponent */
-    {
-      string_appendn (s, "e", 1);
-      (*mangled)++;
-      while (ISDIGIT ((unsigned char)**mangled))
-       {
-         string_appendn (s, *mangled, 1);
-         (*mangled)++;
-       }
-    }
-
-  return 1;
-}
-
-static int
-demangle_template_value_parm (work, mangled, s, tk)
-     struct work_stuff *work;
-     const char **mangled;
-     string* s;
-     type_kind_t tk;
-{
-  int success = 1;
-
-  if (**mangled == 'Y')
-    {
-      /* The next argument is a template parameter. */
-      int idx;
-
-      (*mangled)++;
-      idx = consume_count_with_underscores (mangled);
-      if (idx == -1
-         || (work->tmpl_argvec && idx >= work->ntmpl_args)
-         || consume_count_with_underscores (mangled) == -1)
-       return -1;
-      if (work->tmpl_argvec)
-       string_append (s, work->tmpl_argvec[idx]);
-      else
-       string_append_template_idx (s, idx);
-    }
-  else if (tk == tk_integral)
-    success = demangle_integral_value (work, mangled, s);
-  else if (tk == tk_char)
-    {
-      char tmp[2];
-      int val;
-      if (**mangled == 'm')
-       {
-         string_appendn (s, "-", 1);
-         (*mangled)++;
-       }
-      string_appendn (s, "'", 1);
-      val = consume_count(mangled);
-      if (val <= 0)
-       success = 0;
-      else
-       {
-         tmp[0] = (char)val;
-         tmp[1] = '\0';
-         string_appendn (s, &tmp[0], 1);
-         string_appendn (s, "'", 1);
-       }
-    }
-  else if (tk == tk_bool)
-    {
-      int val = consume_count (mangled);
-      if (val == 0)
-       string_appendn (s, "false", 5);
-      else if (val == 1)
-       string_appendn (s, "true", 4);
-      else
-       success = 0;
-    }
-  else if (tk == tk_real)
-    success = demangle_real_value (work, mangled, s);
-  else if (tk == tk_pointer || tk == tk_reference)
-    {
-      if (**mangled == 'Q')
-       success = demangle_qualified (work, mangled, s,
-                                     /*isfuncname=*/0, 
-                                     /*append=*/1);
+          /* Nested subprogram.  */
+          p += 2;
+          while (ISDIGIT (*p))
+            p++;
+        }
+      if (*p == 0)
+        {
+          /* End of mangled name.  */
+          break;
+        }
       else
-       {
-         int symbol_len  = consume_count (mangled);
-         if (symbol_len == -1)
-           return -1;
-         if (symbol_len == 0)
-           string_appendn (s, "0", 1);
-         else
-           {
-             char *p = xmalloc (symbol_len + 1), *q;
-             strncpy (p, *mangled, symbol_len);
-             p [symbol_len] = '\0';
-             /* We use cplus_demangle here, rather than
-                internal_cplus_demangle, because the name of the entity
-                mangled here does not make use of any of the squangling
-                or type-code information we have built up thus far; it is
-                mangled independently.  */
-             q = cplus_demangle (p, work->options);
-             if (tk == tk_pointer)
-               string_appendn (s, "&", 1);
-             /* FIXME: Pointer-to-member constants should get a
-                qualifying class name here.  */
-             if (q)
-               {
-                 string_append (s, q);
-                 free (q);
-               }
-             else
-               string_append (s, p);
-             free (p);
-           }
-         *mangled += symbol_len;
-       }
+        goto unknown;
     }
+  *d = 0;
+  return demangled;
 
-  return success;
-}
-
-/* Demangle the template name in MANGLED.  The full name of the
-   template (e.g., S<int>) is placed in TNAME.  The name without the
-   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 template is remembered in the list of back-referenceable
-   types.  */
-
-static int
-demangle_template (work, mangled, tname, trawname, is_type, remember)
-     struct work_stuff *work;
-     const char **mangled;
-     string *tname;
-     string *trawname;
-     int is_type;
-     int remember;
-{
-  int i;
-  int r;
-  int need_comma = 0;
-  int success = 0;
-  const char *start;
-  int is_java_array = 0;
-  string temp;
-  int bindex = 0;
-
-  (*mangled)++;
-  if (is_type)
-    {
-      if (remember)
-       bindex = register_Btype (work);
-      start = *mangled;
-      /* get template name */
-      if (**mangled == 'z')
-       {
-         int idx;
-         (*mangled)++;
-         (*mangled)++;
+ unknown:
+  XDELETEVEC (demangled);
+  len0 = strlen (mangled);
+  demangled = XNEWVEC (char, len0 + 3);
 
-         idx = consume_count_with_underscores (mangled);
-         if (idx == -1
-             || (work->tmpl_argvec && idx >= work->ntmpl_args)
-             || consume_count_with_underscores (mangled) == -1)
-           return (0);
+  if (mangled[0] == '<')
+     strcpy (demangled, mangled);
+  else
+    sprintf (demangled, "<%s>", mangled);
 
-         if (work->tmpl_argvec)
-           {
-             string_append (tname, work->tmpl_argvec[idx]);
-             if (trawname)
-               string_append (trawname, work->tmpl_argvec[idx]);
-           }
-         else
-           {
-             string_append_template_idx (tname, idx);
-             if (trawname)
-               string_append_template_idx (trawname, idx);
-           }
-       }
-      else
-       {
-         if ((r = consume_count (mangled)) <= 0
-             || (int) strlen (*mangled) < r)
-           {
-             return (0);
-           }
-         is_java_array = (work -> options & DMGL_JAVA)
-           && strncmp (*mangled, "JArray1Z", 8) == 0;
-         if (! is_java_array)
-           {
-             string_appendn (tname, *mangled, r);
-           }
-         if (trawname)
-           string_appendn (trawname, *mangled, r);
-         *mangled += r;
-       }
-    }
-  if (!is_java_array)
-    string_append (tname, "<");
-  /* get size of template parameter list */
-  if (!get_count (mangled, &r))
-    {
-      return (0);
-    }
-  if (!is_type)
-    {
-      /* Create an array for saving the template argument values. */
-      work->tmpl_argvec = (char**) xmalloc (r * sizeof (char *));
-      work->ntmpl_args = r;
-      for (i = 0; i < r; i++)
-       work->tmpl_argvec[i] = 0;
-    }
-  for (i = 0; i < r; i++)
-    {
-      if (need_comma)
-       {
-         string_append (tname, ", ");
-       }
-      /* Z for type parameters */
-      if (**mangled == 'Z')
-       {
-         (*mangled)++;
-         /* temp is initialized in do_type */
-         success = do_type (work, mangled, &temp);
-         if (success)
-           {
-             string_appends (tname, &temp);
-
-             if (!is_type)
-               {
-                 /* Save the template argument. */
-                 int len = temp.p - temp.b;
-                 work->tmpl_argvec[i] = xmalloc (len + 1);
-                 memcpy (work->tmpl_argvec[i], temp.b, len);
-                 work->tmpl_argvec[i][len] = '\0';
-               }
-           }
-         string_delete(&temp);
-         if (!success)
-           {
-             break;
-           }
-       }
-      /* z for template parameters */
-      else if (**mangled == 'z')
-       {
-         int r2;
-         (*mangled)++;
-         success = demangle_template_template_parm (work, mangled, tname);
-
-         if (success
-             && (r2 = consume_count (mangled)) > 0
-             && (int) strlen (*mangled) >= r2)
-           {
-             string_append (tname, " ");
-             string_appendn (tname, *mangled, r2);
-             if (!is_type)
-               {
-                 /* Save the template argument. */
-                 int len = r2;
-                 work->tmpl_argvec[i] = xmalloc (len + 1);
-                 memcpy (work->tmpl_argvec[i], *mangled, len);
-                 work->tmpl_argvec[i][len] = '\0';
-               }
-             *mangled += r2;
-           }
-         if (!success)
-           {
-             break;
-           }
-       }
-      else
-       {
-         string  param;
-         string* s;
-
-         /* otherwise, value parameter */
-
-         /* temp is initialized in do_type */
-         success = do_type (work, mangled, &temp);
-         string_delete(&temp);
-         if (!success)
-           break;
-
-         if (!is_type)
-           {
-             s = &param;
-             string_init (s);
-           }
-         else
-           s = tname;
-
-         success = demangle_template_value_parm (work, mangled, s,
-                                                 (type_kind_t) success);
-
-         if (!success)
-           {
-             if (!is_type)
-               string_delete (s);
-             success = 0;
-             break;
-           }
-
-         if (!is_type)
-           {
-             int len = s->p - s->b;
-             work->tmpl_argvec[i] = xmalloc (len + 1);
-             memcpy (work->tmpl_argvec[i], s->b, len);
-             work->tmpl_argvec[i][len] = '\0';
-
-             string_appends (tname, s);
-             string_delete (s);
-           }
-       }
-      need_comma = 1;
-    }
-  if (is_java_array)
-    {
-      string_append (tname, "[]");
-    }
-  else
-    {
-      if (tname->p[-1] == '>')
-       string_append (tname, " ");
-      string_append (tname, ">");
-    }
-
-  if (is_type && remember)
-    remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
-
-  /*
-    if (work -> static_type)
-    {
-    string_append (declp, *mangled + 1);
-    *mangled += strlen (*mangled);
-    success = 1;
-    }
-    else
-    {
-    success = demangle_args (work, mangled, declp);
-    }
-    }
-    */
-  return (success);
-}
-
-static int
-arm_pt (work, mangled, n, anchor, args)
-     struct work_stuff *work;
-     const char *mangled;
-     int n;
-     const char **anchor, **args;
-{
-  /* Check if ARM template with "__pt__" in it ("parameterized type") */
-  /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
-  if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__")))
-    {
-      int len;
-      *args = *anchor + 6;
-      len = consume_count (args);
-      if (len == -1)
-       return 0;
-      if (*args + len == mangled + n && **args == '_')
-       {
-         ++*args;
-         return 1;
-       }
-    }
-  if (AUTO_DEMANGLING || EDG_DEMANGLING)
-    {
-      if ((*anchor = strstr (mangled, "__tm__"))
-          || (*anchor = strstr (mangled, "__ps__"))
-          || (*anchor = strstr (mangled, "__pt__")))
-        {
-          int len;
-          *args = *anchor + 6;
-          len = consume_count (args);
-         if (len == -1)
-           return 0;
-          if (*args + len == mangled + n && **args == '_')
-            {
-              ++*args;
-              return 1;
-            }
-        }
-      else if ((*anchor = strstr (mangled, "__S")))
-        {
-         int len;
-         *args = *anchor + 3;
-         len = consume_count (args);
-         if (len == -1)
-           return 0;
-         if (*args + len == mangled + n && **args == '_')
-            {
-              ++*args;
-             return 1;
-            }
-        }
-    }
-
-  return 0;
-}
-
-static void
-demangle_arm_hp_template (work, mangled, n, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     int n;
-     string *declp;
-{
-  const char *p;
-  const char *args;
-  const char *e = *mangled + n;
-  string arg;
-
-  /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
-     template args */
-  if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
-    {
-      char *start_spec_args = NULL;
-
-      /* First check for and omit template specialization pseudo-arguments,
-         such as in "Spec<#1,#1.*>" */
-      start_spec_args = strchr (*mangled, '<');
-      if (start_spec_args && (start_spec_args - *mangled < n))
-        string_appendn (declp, *mangled, start_spec_args - *mangled);
-      else
-        string_appendn (declp, *mangled, n);
-      (*mangled) += n + 1;
-      string_init (&arg);
-      if (work->temp_start == -1) /* non-recursive call */
-        work->temp_start = declp->p - declp->b;
-      string_append (declp, "<");
-      while (1)
-        {
-          string_delete (&arg);
-          switch (**mangled)
-            {
-              case 'T':
-                /* 'T' signals a type parameter */
-                (*mangled)++;
-                if (!do_type (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              case 'U':
-              case 'S':
-                /* 'U' or 'S' signals an integral value */
-                if (!do_hpacc_template_const_value (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              case 'A':
-                /* 'A' signals a named constant expression (literal) */
-                if (!do_hpacc_template_literal (work, mangled, &arg))
-                  goto hpacc_template_args_done;
-                break;
-
-              default:
-                /* Today, 1997-09-03, we have only the above types
-                   of template parameters */
-                /* FIXME: maybe this should fail and return null */
-                goto hpacc_template_args_done;
-            }
-          string_appends (declp, &arg);
-         /* Check if we're at the end of template args.
-             0 if at end of static member of template class,
-             _ if done with template args for a function */
-          if ((**mangled == '\000') || (**mangled == '_'))
-            break;
-          else
-            string_append (declp, ",");
-        }
-    hpacc_template_args_done:
-      string_append (declp, ">");
-      string_delete (&arg);
-      if (**mangled == '_')
-        (*mangled)++;
-      return;
-    }
-  /* ARM template? (Also handles HP cfront extensions) */
-  else if (arm_pt (work, *mangled, n, &p, &args))
-    {
-      string type_str;
-
-      string_init (&arg);
-      string_appendn (declp, *mangled, p - *mangled);
-      if (work->temp_start == -1)  /* non-recursive call */
-       work->temp_start = declp->p - declp->b;
-      string_append (declp, "<");
-      /* should do error checking here */
-      while (args < e) {
-       string_delete (&arg);
-
-       /* Check for type or literal here */
-       switch (*args)
-         {
-           /* HP cfront extensions to ARM for template args */
-           /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
-           /* FIXME: We handle only numeric literals for HP cfront */
-          case 'X':
-            /* A typed constant value follows */
-            args++;
-            if (!do_type (work, &args, &type_str))
-             goto cfront_template_args_done;
-            string_append (&arg, "(");
-            string_appends (&arg, &type_str);
-            string_delete (&type_str);
-            string_append (&arg, ")");
-            if (*args != 'L')
-              goto cfront_template_args_done;
-            args++;
-            /* Now snarf a literal value following 'L' */
-            if (!snarf_numeric_literal (&args, &arg))
-             goto cfront_template_args_done;
-            break;
-
-          case 'L':
-            /* Snarf a literal following 'L' */
-            args++;
-            if (!snarf_numeric_literal (&args, &arg))
-             goto cfront_template_args_done;
-            break;
-          default:
-            /* Not handling other HP cfront stuff */
-            {
-              const char* old_args = args;
-              if (!do_type (work, &args, &arg))
-                goto cfront_template_args_done;
-
-              /* Fail if we didn't make any progress: prevent infinite loop. */
-              if (args == old_args)
-                return;
-            }
-         }
-       string_appends (declp, &arg);
-       string_append (declp, ",");
-      }
-    cfront_template_args_done:
-      string_delete (&arg);
-      if (args >= e)
-       --declp->p; /* remove extra comma */
-      string_append (declp, ">");
-    }
-  else 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.  */
-      string_append (declp, "{anonymous}");
-    }
-  else
-    {
-      if (work->temp_start == -1) /* non-recursive call only */
-       work->temp_start = 0;     /* disable in recursive calls */
-      string_appendn (declp, *mangled, n);
-    }
-  *mangled += n;
-}
-
-/* Extract a class name, possibly a template with arguments, from the
-   mangled string; qualifiers, local class indicators, etc. have
-   already been dealt with */
-
-static int
-demangle_class_name (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int n;
-  int success = 0;
-
-  n = consume_count (mangled);
-  if (n == -1)
-    return 0;
-  if ((int) strlen (*mangled) >= n)
-    {
-      demangle_arm_hp_template (work, mangled, n, declp);
-      success = 1;
-    }
-
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_class -- demangle a mangled class sequence
-
-SYNOPSIS
-
-       static int
-       demangle_class (struct work_stuff *work, const char **mangled,
-                       strint *declp)
-
-DESCRIPTION
-
-       DECLP points to the buffer into which demangling is being done.
-
-       *MANGLED points to the current token to be demangled.  On input,
-       it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
-       On exit, it points to the next token after the mangled class on
-       success, or the first unconsumed token on failure.
-
-       If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
-       we are demangling a constructor or destructor.  In this case
-       we prepend "class::class" or "class::~class" to DECLP.
-
-       Otherwise, we prepend "class::" to the current DECLP.
-
-       Reset the constructor/destructor flags once they have been
-       "consumed".  This allows demangle_class to be called later during
-       the same demangling, to do normal class demangling.
-
-       Returns 1 if demangling is successful, 0 otherwise.
-
-*/
-
-static int
-demangle_class (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int success = 0;
-  int btype;
-  string class_name;
-  char *save_class_name_end = 0;
-
-  string_init (&class_name);
-  btype = register_Btype (work);
-  if (demangle_class_name (work, mangled, &class_name))
-    {
-      save_class_name_end = class_name.p;
-      if ((work->constructor & 1) || (work->destructor & 1))
-       {
-          /* adjust so we don't include template args */
-          if (work->temp_start && (work->temp_start != -1))
-            {
-              class_name.p = class_name.b + work->temp_start;
-            }
-         string_prepends (declp, &class_name);
-         if (work -> destructor & 1)
-           {
-             string_prepend (declp, "~");
-              work -> destructor -= 1;
-           }
-         else
-           {
-             work -> constructor -= 1;
-           }
-       }
-      class_name.p = save_class_name_end;
-      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
-      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
-      string_prepend (declp, SCOPE_STRING (work));
-      string_prepends (declp, &class_name);
-      success = 1;
-    }
-  string_delete (&class_name);
-  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
-      || strstr (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
-
-       demangle_prefix -- consume the mangled name prefix and find signature
-
-SYNOPSIS
-
-       static int
-       demangle_prefix (struct work_stuff *work, const char **mangled,
-                        string *declp);
-
-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
-       the root function name, the demangled operator name, or in some
-       special cases either nothing or the completely demangled result.
-
-       MANGLED points to the current pointer into the mangled name.  As each
-       token of the mangled name is consumed, it is updated.  Upon entry
-       the current mangled name pointer points to the first character of
-       the mangled name.  Upon exit, it should point to the first character
-       of the signature if demangling was successful, or to the first
-       unconsumed character if demangling of the prefix was unsuccessful.
-
-       Returns 1 on success, 0 otherwise.
- */
-
-static int
-demangle_prefix (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int success = 1;
-  const char *scan;
-  int i;
-
-  if (strlen(*mangled) > 6
-      && (strncmp(*mangled, "_imp__", 6) == 0
-          || strncmp(*mangled, "__imp_", 6) == 0))
-    {
-      /* it's a symbol imported from a PE dynamic library. Check for both
-         new style prefix _imp__ and legacy __imp_ used by older versions
-        of dlltool. */
-      (*mangled) += 6;
-      work->dllimported = 1;
-    }
-  else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
-    {
-      char *marker = strchr (cplus_markers, (*mangled)[8]);
-      if (marker != NULL && *marker == (*mangled)[10])
-       {
-         if ((*mangled)[9] == 'D')
-           {
-             /* it's a GNU global destructor to be executed at program exit */
-             (*mangled) += 11;
-             work->destructor = 2;
-             if (gnu_special (work, mangled, declp))
-               return success;
-           }
-         else if ((*mangled)[9] == 'I')
-           {
-             /* it's a GNU global constructor to be executed at program init */
-             (*mangled) += 11;
-             work->constructor = 2;
-             if (gnu_special (work, mangled, declp))
-               return success;
-           }
-       }
-    }
-  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
-    {
-      /* it's a ARM global destructor to be executed at program exit */
-      (*mangled) += 7;
-      work->destructor = 2;
-    }
-  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
-    {
-      /* it's a ARM global constructor to be executed at program initial */
-      (*mangled) += 7;
-      work->constructor = 2;
-    }
-
-  /*  This block of code is a reduction in strength time optimization
-      of:
-      scan = strstr (*mangled, "__"); */
-
-  {
-    scan = *mangled;
-
-    do {
-      scan = strchr (scan, '_');
-    } while (scan != NULL && *++scan != '_');
-
-    if (scan != NULL) --scan;
-  }
-
-  if (scan != NULL)
-    {
-      /* We found a sequence of two or more '_', ensure that we start at
-        the last pair in the sequence.  */
-      i = strspn (scan, "_");
-      if (i > 2)
-       {
-         scan += (i - 2);
-       }
-    }
-
-  if (scan == NULL)
-    {
-      success = 0;
-    }
-  else if (work -> static_type)
-    {
-      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
-       {
-         success = 0;
-       }
-    }
-  else if ((scan == *mangled)
-          && (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]))
-       {
-         *mangled = scan + 2;
-         consume_count (mangled);
-         string_append (declp, *mangled);
-         *mangled += strlen (*mangled);
-         success = 1;
-       }
-      else
-       {
-         /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
-            names like __Q2_3foo3bar for nested type names.  So don't accept
-            this style of constructor for cfront demangling.  A GNU
-            style member-template constructor starts with 'H'. */
-         if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
-           work -> constructor += 1;
-         *mangled = scan + 2;
-       }
-    }
-  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
-    {
-      /* Cfront-style parameterized type.  Handled later as a signature. */
-      success = 1;
-
-      /* ARM template? */
-      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
-    }
-  else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
-                              || (scan[2] == 'p' && scan[3] == 's')
-                              || (scan[2] == 'p' && scan[3] == 't')))
-    {
-      /* EDG-style parameterized type.  Handled later as a signature. */
-      success = 1;
-
-      /* EDG template? */
-      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
-    }
-  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
-          && (scan[2] != 't'))
-    {
-      /* Mangled name starts with "__".  Skip over any leading '_' characters,
-        then find the next "__" that separates the prefix from the signature.
-        */
-      if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-         || (arm_special (mangled, declp) == 0))
-       {
-         while (*scan == '_')
-           {
-             scan++;
-           }
-         if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
-           {
-             /* No separator (I.E. "__not_mangled"), or empty signature
-                (I.E. "__not_mangled_either__") */
-             success = 0;
-           }
-         else
-           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.  Iterate over all "__":s until the right
-        one is found.  */
-      return iterate_demangle_function (work, mangled, declp, scan);
-    }
-  else
-    {
-      /* Doesn't look like a mangled name */
-      success = 0;
-    }
-
-  if (!success && (work->constructor == 2 || work->destructor == 2))
-    {
-      string_append (declp, *mangled);
-      *mangled += strlen (*mangled);
-      success = 1;
-    }
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       gnu_special -- special handling of gnu mangled strings
-
-SYNOPSIS
-
-       static int
-       gnu_special (struct work_stuff *work, const char **mangled,
-                    string *declp);
-
-
-DESCRIPTION
-
-       Process some special GNU style mangling forms that don't fit
-       the normal pattern.  For example:
-
-               _$_3foo         (destructor for class foo)
-               _vt$foo         (foo virtual table)
-               _vt$foo$bar     (foo::bar virtual table)
-               __vt_foo        (foo virtual table, new style with thunks)
-               _3foo$varname   (static data member)
-               _Q22rs2tu$vw    (static data member)
-               __t6vector1Zii  (constructor with template)
-               __thunk_4__$_7ostream (virtual function thunk)
- */
-
-static int
-gnu_special (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  int n;
-  int success = 1;
-  const char *p;
-
-  if ((*mangled)[0] == '_'
-      && strchr (cplus_markers, (*mangled)[1]) != NULL
-      && (*mangled)[2] == '_')
-    {
-      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
-      (*mangled) += 3;
-      work -> destructor += 1;
-    }
-  else if ((*mangled)[0] == '_'
-          && (((*mangled)[1] == '_'
-               && (*mangled)[2] == 'v'
-               && (*mangled)[3] == 't'
-               && (*mangled)[4] == '_')
-              || ((*mangled)[1] == 'v'
-                  && (*mangled)[2] == 't'
-                  && strchr (cplus_markers, (*mangled)[3]) != NULL)))
-    {
-      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
-         and create the decl.  Note that we consume the entire mangled
-        input string, which means that demangle_signature has no work
-        to do.  */
-      if ((*mangled)[2] == 'v')
-       (*mangled) += 5; /* New style, with thunks: "__vt_" */
-      else
-       (*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
-      while (**mangled != '\0')
-       {
-         switch (**mangled)
-           {
-           case 'Q':
-           case 'K':
-             success = demangle_qualified (work, mangled, declp, 0, 1);
-             break;
-           case 't':
-             success = demangle_template (work, mangled, declp, 0, 1,
-                                          1);
-             break;
-           default:
-             if (ISDIGIT((unsigned char)*mangled[0]))
-               {
-                 n = consume_count(mangled);
-                 /* We may be seeing a too-large size, or else a
-                    ".<digits>" indicating a static local symbol.  In
-                    any case, declare victory and move on; *don't* try
-                    to use n to allocate.  */
-                 if (n > (int) strlen (*mangled))
-                   {
-                     success = 1;
-                     break;
-                   }
-               }
-             else
-               {
-                 n = strcspn (*mangled, cplus_markers);
-               }
-             string_appendn (declp, *mangled, n);
-             (*mangled) += n;
-           }
-
-         p = strpbrk (*mangled, cplus_markers);
-         if (success && ((p == NULL) || (p == *mangled)))
-           {
-             if (p != NULL)
-               {
-                 string_append (declp, SCOPE_STRING (work));
-                 (*mangled)++;
-               }
-           }
-         else
-           {
-             success = 0;
-             break;
-           }
-       }
-      if (success)
-       string_append (declp, " virtual table");
-    }
-  else if ((*mangled)[0] == '_'
-          && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
-          && (p = strpbrk (*mangled, cplus_markers)) != NULL)
-    {
-      /* static data member, "_3foo$varname" for example */
-      (*mangled)++;
-      switch (**mangled)
-       {
-       case 'Q':
-       case 'K':
-         success = demangle_qualified (work, mangled, declp, 0, 1);
-         break;
-       case 't':
-         success = demangle_template (work, mangled, declp, 0, 1, 1);
-         break;
-       default:
-         n = consume_count (mangled);
-         if (n < 0 || n > (long) strlen (*mangled))
-           {
-             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;
-       }
-      if (success && (p == *mangled))
-       {
-         /* Consumed everything up to the cplus_marker, append the
-            variable name.  */
-         (*mangled)++;
-         string_append (declp, SCOPE_STRING (work));
-         n = strlen (*mangled);
-         string_appendn (declp, *mangled, n);
-         (*mangled) += n;
-       }
-      else
-       {
-         success = 0;
-       }
-    }
-  else if (strncmp (*mangled, "__thunk_", 8) == 0)
-    {
-      int delta;
-
-      (*mangled) += 8;
-      delta = consume_count (mangled);
-      if (delta == -1)
-       success = 0;
-      else
-       {
-         char *method = internal_cplus_demangle (work, ++*mangled);
-
-         if (method)
-           {
-             char buf[50];
-             sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
-             string_append (declp, buf);
-             string_append (declp, method);
-             free (method);
-             n = strlen (*mangled);
-             (*mangled) += n;
-           }
-         else
-           {
-             success = 0;
-           }
-       }
-    }
-  else if (strncmp (*mangled, "__t", 3) == 0
-          && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
-    {
-      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
-      (*mangled) += 4;
-      switch (**mangled)
-       {
-       case 'Q':
-       case 'K':
-         success = demangle_qualified (work, mangled, declp, 0, 1);
-         break;
-       case 't':
-         success = demangle_template (work, mangled, declp, 0, 1, 1);
-         break;
-       default:
-         success = do_type (work, mangled, declp);
-         break;
-       }
-      if (success && **mangled != '\0')
-       success = 0;
-      if (success)
-       string_append (declp, p);
-    }
-  else
-    {
-      success = 0;
-    }
-  return (success);
-}
-
-static void
-recursively_demangle(work, mangled, result, namelength)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-     int namelength;
-{
-  char * recurse = (char *)NULL;
-  char * recurse_dem = (char *)NULL;
-
-  recurse = (char *) xmalloc (namelength + 1);
-  memcpy (recurse, *mangled, namelength);
-  recurse[namelength] = '\000';
-
-  recurse_dem = cplus_demangle (recurse, work->options);
-
-  if (recurse_dem)
-    {
-      string_append (result, recurse_dem);
-      free (recurse_dem);
-    }
-  else
-    {
-      string_appendn (result, *mangled, namelength);
-    }
-  free (recurse);
-  *mangled += namelength;
-}
-
-/*
-
-LOCAL FUNCTION
-
-       arm_special -- special handling of ARM/lucid mangled strings
-
-SYNOPSIS
-
-       static int
-       arm_special (const char **mangled,
-                    string *declp);
-
-
-DESCRIPTION
-
-       Process some special ARM style mangling forms that don't fit
-       the normal pattern.  For example:
-
-               __vtbl__3foo            (foo virtual table)
-               __vtbl__3foo__3bar      (bar::foo virtual table)
-
- */
-
-static int
-arm_special (mangled, declp)
-     const char **mangled;
-     string *declp;
-{
-  int n;
-  int success = 1;
-  const char *scan;
-
-  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
-    {
-      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
-         and create the decl.  Note that we consume the entire mangled
-        input string, which means that demangle_signature has no work
-        to do.  */
-      scan = *mangled + ARM_VTABLE_STRLEN;
-      while (*scan != '\0')        /* first check it can be demangled */
-        {
-          n = consume_count (&scan);
-          if (n == -1)
-           {
-             return (0);           /* no good */
-           }
-          scan += n;
-          if (scan[0] == '_' && scan[1] == '_')
-           {
-             scan += 2;
-           }
-        }
-      (*mangled) += ARM_VTABLE_STRLEN;
-      while (**mangled != '\0')
-       {
-         n = consume_count (mangled);
-          if (n == -1
-             || n > (long) strlen (*mangled))
-           return 0;
-         string_prependn (declp, *mangled, n);
-         (*mangled) += n;
-         if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
-           {
-             string_prepend (declp, "::");
-             (*mangled) += 2;
-           }
-       }
-      string_append (declp, " virtual table");
-    }
-  else
-    {
-      success = 0;
-    }
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       demangle_qualified -- demangle 'Q' qualified name strings
-
-SYNOPSIS
-
-       static int
-       demangle_qualified (struct work_stuff *, const char *mangled,
-                           string *result, int isfuncname, int append);
-
-DESCRIPTION
-
-       Demangle a qualified name, such as "Q25Outer5Inner" which is
-       the mangled form of "Outer::Inner".  The demangled output is
-       prepended or appended to the result string according to the
-       state of the append flag.
-
-       If isfuncname is nonzero, then the qualified name we are building
-       is going to be used as a member function name, so if it is a
-       constructor or destructor function, append an appropriate
-       constructor or destructor name.  I.E. for the above example,
-       the result for use as a constructor is "Outer::Inner::Inner"
-       and the result for use as a destructor is "Outer::Inner::~Inner".
-
-BUGS
-
-       Numeric conversion is ASCII dependent (FIXME).
-
- */
-
-static int
-demangle_qualified (work, mangled, result, isfuncname, append)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-     int isfuncname;
-     int append;
-{
-  int qualifiers = 0;
-  int success = 1;
-  char num[2];
-  string temp;
-  string last_name;
-  int bindex = register_Btype (work);
-
-  /* We only make use of ISFUNCNAME if the entity is a constructor or
-     destructor.  */
-  isfuncname = (isfuncname
-               && ((work->constructor & 1) || (work->destructor & 1)));
-
-  string_init (&temp);
-  string_init (&last_name);
-
-  if ((*mangled)[0] == 'K')
-    {
-    /* Squangling qualified name reuse */
-      int idx;
-      (*mangled)++;
-      idx = consume_count_with_underscores (mangled);
-      if (idx == -1 || idx >= work -> numk)
-        success = 0;
-      else
-        string_append (&temp, work -> ktypevec[idx]);
-    }
-  else
-    switch ((*mangled)[1])
-    {
-    case '_':
-      /* GNU mangled name with more than 9 classes.  The count is preceded
-        by an underscore (to distinguish it from the <= 9 case) and followed
-        by an underscore.  */
-      (*mangled)++;
-      qualifiers = consume_count_with_underscores (mangled);
-      if (qualifiers == -1)
-       success = 0;
-      break;
-
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      /* The count is in a single digit.  */
-      num[0] = (*mangled)[1];
-      num[1] = '\0';
-      qualifiers = atoi (num);
-
-      /* If there is an underscore after the digit, skip it.  This is
-        said to be for ARM-qualified names, but the ARM makes no
-        mention of such an underscore.  Perhaps cfront uses one.  */
-      if ((*mangled)[2] == '_')
-       {
-         (*mangled)++;
-       }
-      (*mangled) += 2;
-      break;
-
-    case '0':
-    default:
-      success = 0;
-    }
-
-  if (!success)
-    return success;
-
-  /* Pick off the names and collect them in the temp buffer in the order
-     in which they are found, separated by '::'.  */
-
-  while (qualifiers-- > 0)
-    {
-      int remember_K = 1;
-      string_clear (&last_name);
-
-      if (*mangled[0] == '_')
-       (*mangled)++;
-
-      if (*mangled[0] == 't')
-       {
-         /* Here we always append to TEMP since we will want to use
-            the template name without the template parameters as a
-            constructor or destructor name.  The appropriate
-            (parameter-less) value is returned by demangle_template
-            in LAST_NAME.  We do not remember the template type here,
-            in order to match the G++ mangling algorithm.  */
-         success = demangle_template(work, mangled, &temp,
-                                     &last_name, 1, 0);
-         if (!success)
-           break;
-       }
-      else if (*mangled[0] == 'K')
-       {
-          int idx;
-          (*mangled)++;
-          idx = consume_count_with_underscores (mangled);
-          if (idx == -1 || idx >= work->numk)
-            success = 0;
-          else
-            string_append (&temp, work->ktypevec[idx]);
-          remember_K = 0;
-
-         if (!success) break;
-       }
-      else
-       {
-         if (EDG_DEMANGLING)
-            {
-             int namelength;
-             /* Now recursively demangle the qualifier
-              * This is necessary to deal with templates in
-              * mangling styles like EDG */
-             namelength = consume_count (mangled);
-             if (namelength == -1)
-               {
-                 success = 0;
-                 break;
-               }
-             recursively_demangle(work, mangled, &temp, namelength);
-            }
-          else
-            {
-              string_delete (&last_name);
-              success = do_type (work, mangled, &last_name);
-              if (!success)
-                break;
-              string_appends (&temp, &last_name);
-            }
-       }
-
-      if (remember_K)
-       remember_Ktype (work, temp.b, LEN_STRING (&temp));
-
-      if (qualifiers > 0)
-       string_append (&temp, SCOPE_STRING (work));
-    }
-
-  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
-
-  /* If we are using the result as a function name, we need to append
-     the appropriate '::' separated constructor or destructor name.
-     We do this here because this is the most convenient place, where
-     we already have a pointer to the name and the length of the name.  */
-
-  if (isfuncname)
-    {
-      string_append (&temp, SCOPE_STRING (work));
-      if (work -> destructor & 1)
-       string_append (&temp, "~");
-      string_appends (&temp, &last_name);
-    }
-
-  /* Now either prepend the temp buffer to the result, or append it,
-     depending upon the state of the append flag.  */
-
-  if (append)
-    string_appends (result, &temp);
-  else
-    {
-      if (!STRING_EMPTY (result))
-       string_append (&temp, SCOPE_STRING (work));
-      string_prepends (result, &temp);
-    }
-
-  string_delete (&last_name);
-  string_delete (&temp);
-  return (success);
-}
-
-/*
-
-LOCAL FUNCTION
-
-       get_count -- convert an ascii count to integer, consuming tokens
-
-SYNOPSIS
-
-       static int
-       get_count (const char **type, int *count)
-
-DESCRIPTION
-
-       Assume that *type points at a count in a mangled name; set
-       *count to its value, and set *type to the next character after
-       the count.  There are some weird rules in effect here.
-
-       If *type does not point at a string of digits, return zero.
-
-       If *type points at a string of digits followed by an
-       underscore, set *count to their value as an integer, advance
-       *type to point *after the underscore, and return 1.
-
-       If *type points at a string of digits not followed by an
-       underscore, consume only the first digit.  Set *count to its
-       value as an integer, leave *type pointing after that digit,
-       and return 1.
-
-        The excuse for this odd behavior: in the ARM and HP demangling
-        styles, a type can be followed by a repeat count of the form
-        `Nxy', where:
-
-        `x' is a single digit specifying how many additional copies
-            of the type to append to the argument list, and
-
-        `y' is one or more digits, specifying the zero-based index of
-            the first repeated argument in the list.  Yes, as you're
-            unmangling the name you can figure this out yourself, but
-            it's there anyway.
-
-        So, for example, in `bar__3fooFPiN51', the first argument is a
-        pointer to an integer (`Pi'), and then the next five arguments
-        are the same (`N5'), and the first repeat is the function's
-        second argument (`1').
-*/
-
-static int
-get_count (type, count)
-     const char **type;
-     int *count;
-{
-  const char *p;
-  int n;
-
-  if (!ISDIGIT ((unsigned char)**type))
-    return (0);
-  else
-    {
-      *count = **type - '0';
-      (*type)++;
-      if (ISDIGIT ((unsigned char)**type))
-       {
-         p = *type;
-         n = *count;
-         do
-           {
-             n *= 10;
-             n += *p - '0';
-             p++;
-           }
-         while (ISDIGIT ((unsigned char)*p));
-         if (*p == '_')
-           {
-             *type = p + 1;
-             *count = n;
-           }
-       }
-    }
-  return (1);
-}
-
-/* RESULT will be initialised here; it will be freed on failure.  The
-   value returned is really a type_kind_t.  */
-
-static int
-do_type (work, mangled, result)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-{
-  int n;
-  int done;
-  int success;
-  string decl;
-  const char *remembered_type;
-  int type_quals;
-  type_kind_t tk = tk_none;
-
-  string_init (&decl);
-  string_init (result);
-
-  done = 0;
-  success = 1;
-  while (success && !done)
-    {
-      int member;
-      switch (**mangled)
-       {
-
-         /* A pointer type */
-       case 'P':
-       case 'p':
-         (*mangled)++;
-         if (! (work -> options & DMGL_JAVA))
-           string_prepend (&decl, "*");
-         if (tk == tk_none)
-           tk = tk_pointer;
-         break;
-
-         /* A reference type */
-       case 'R':
-         (*mangled)++;
-         string_prepend (&decl, "&");
-         if (tk == tk_none)
-           tk = tk_reference;
-         break;
-
-         /* An array */
-       case 'A':
-         {
-           ++(*mangled);
-           if (!STRING_EMPTY (&decl)
-               && (decl.b[0] == '*' || decl.b[0] == '&'))
-             {
-               string_prepend (&decl, "(");
-               string_append (&decl, ")");
-             }
-           string_append (&decl, "[");
-           if (**mangled != '_')
-             success = demangle_template_value_parm (work, mangled, &decl,
-                                                     tk_integral);
-           if (**mangled == '_')
-             ++(*mangled);
-           string_append (&decl, "]");
-           break;
-         }
-
-       /* A back reference to a previously seen type */
-       case 'T':
-         (*mangled)++;
-         if (!get_count (mangled, &n) || n >= work -> ntypes)
-           {
-             success = 0;
-           }
-         else
-           {
-             remembered_type = work -> typevec[n];
-             mangled = &remembered_type;
-           }
-         break;
-
-         /* A function */
-       case 'F':
-         (*mangled)++;
-           if (!STRING_EMPTY (&decl)
-               && (decl.b[0] == '*' || decl.b[0] == '&'))
-           {
-             string_prepend (&decl, "(");
-             string_append (&decl, ")");
-           }
-         /* After picking off the function args, we expect to either find the
-            function return type (preceded by an '_') or the end of the
-            string.  */
-         if (!demangle_nested_args (work, mangled, &decl)
-             || (**mangled != '_' && **mangled != '\0'))
-           {
-             success = 0;
-             break;
-           }
-         if (success && (**mangled == '_'))
-           (*mangled)++;
-         break;
-
-       case 'M':
-       case 'O':
-         {
-           type_quals = TYPE_UNQUALIFIED;
-
-           member = **mangled == 'M';
-           (*mangled)++;
-
-           string_append (&decl, ")");
-
-           /* We don't need to prepend `::' for a qualified name;
-              demangle_qualified will do that for us.  */
-           if (**mangled != 'Q')
-             string_prepend (&decl, SCOPE_STRING (work));
-
-           if (ISDIGIT ((unsigned char)**mangled))
-             {
-               n = consume_count (mangled);
-               if (n == -1
-                   || (int) strlen (*mangled) < n)
-                 {
-                   success = 0;
-                   break;
-                 }
-               string_prependn (&decl, *mangled, n);
-               *mangled += n;
-             }
-           else if (**mangled == 'X' || **mangled == 'Y')
-             {
-               string temp;
-               do_type (work, mangled, &temp);
-               string_prepends (&decl, &temp);
-               string_delete (&temp);
-             }
-           else if (**mangled == 't')
-             {
-               string temp;
-               string_init (&temp);
-               success = demangle_template (work, mangled, &temp,
-                                            NULL, 1, 1);
-               if (success)
-                 {
-                   string_prependn (&decl, temp.b, temp.p - temp.b);
-                   string_delete (&temp);
-                 }
-               else
-                 break;
-             }
-           else if (**mangled == 'Q')
-             {
-               success = demangle_qualified (work, mangled, &decl,
-                                             /*isfuncnam=*/0, 
-                                             /*append=*/0);
-               if (!success)
-                 break;
-             }
-           else
-             {
-               success = 0;
-               break;
-             }
-
-           string_prepend (&decl, "(");
-           if (member)
-             {
-               switch (**mangled)
-                 {
-                 case 'C':
-                 case 'V':
-                 case 'u':
-                   type_quals |= code_for_qualifier (**mangled);
-                   (*mangled)++;
-                   break;
-
-                 default:
-                   break;
-                 }
-
-               if (*(*mangled)++ != 'F')
-                 {
-                   success = 0;
-                   break;
-                 }
-             }
-           if ((member && !demangle_nested_args (work, mangled, &decl))
-               || **mangled != '_')
-             {
-               success = 0;
-               break;
-             }
-           (*mangled)++;
-           if (! PRINT_ANSI_QUALIFIERS)
-             {
-               break;
-             }
-           if (type_quals != TYPE_UNQUALIFIED)
-             {
-               APPEND_BLANK (&decl);
-               string_append (&decl, qualifier_string (type_quals));
-             }
-           break;
-         }
-        case 'G':
-         (*mangled)++;
-         break;
-
-       case 'C':
-       case 'V':
-       case 'u':
-         if (PRINT_ANSI_QUALIFIERS)
-           {
-             if (!STRING_EMPTY (&decl))
-               string_prepend (&decl, " ");
-
-             string_prepend (&decl, demangle_qualifier (**mangled));
-           }
-         (*mangled)++;
-         break;
-         /*
-           }
-           */
-
-         /* fall through */
-       default:
-         done = 1;
-         break;
-       }
-    }
-
-  if (success) switch (**mangled)
-    {
-      /* A qualified name, such as "Outer::Inner".  */
-    case 'Q':
-    case 'K':
-      {
-        success = demangle_qualified (work, mangled, result, 0, 1);
-        break;
-      }
-
-    /* A back reference to a previously seen squangled type */
-    case 'B':
-      (*mangled)++;
-      if (!get_count (mangled, &n) || n >= work -> numb)
-       success = 0;
-      else
-       string_append (result, work->btypevec[n]);
-      break;
-
-    case 'X':
-    case 'Y':
-      /* A template parm.  We substitute the corresponding argument. */
-      {
-       int idx;
-
-       (*mangled)++;
-       idx = consume_count_with_underscores (mangled);
-
-       if (idx == -1
-           || (work->tmpl_argvec && idx >= work->ntmpl_args)
-           || consume_count_with_underscores (mangled) == -1)
-         {
-           success = 0;
-           break;
-         }
-
-       if (work->tmpl_argvec)
-         string_append (result, work->tmpl_argvec[idx]);
-       else
-         string_append_template_idx (result, idx);
-
-       success = 1;
-      }
-    break;
-
-    default:
-      success = demangle_fund_type (work, mangled, result);
-      if (tk == tk_none)
-       tk = (type_kind_t) success;
-      break;
-    }
-
-  if (success)
-    {
-      if (!STRING_EMPTY (&decl))
-       {
-         string_append (result, " ");
-         string_appends (result, &decl);
-       }
-    }
-  else
-    string_delete (result);
-  string_delete (&decl);
-
-  if (success)
-    /* Assume an integral type, if we're not sure.  */
-    return (int) ((tk == tk_none) ? tk_integral : tk);
-  else
-    return 0;
-}
-
-/* Given a pointer to a type string that represents a fundamental type
-   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
-   string in which the demangled output is being built in RESULT, and
-   the WORK structure, decode the types and add them to the result.
-
-   For example:
-
-       "Ci"    =>      "const int"
-       "Sl"    =>      "signed long"
-       "CUs"   =>      "const unsigned short"
-
-   The value returned is really a type_kind_t.  */
-
-static int
-demangle_fund_type (work, mangled, result)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-{
-  int done = 0;
-  int success = 1;
-  char buf[10];
-  unsigned int dec = 0;
-  type_kind_t tk = tk_integral;
-
-  /* First pick off any type qualifiers.  There can be more than one.  */
-
-  while (!done)
-    {
-      switch (**mangled)
-       {
-       case 'C':
-       case 'V':
-       case 'u':
-         if (PRINT_ANSI_QUALIFIERS)
-           {
-              if (!STRING_EMPTY (result))
-                string_prepend (result, " ");
-             string_prepend (result, demangle_qualifier (**mangled));
-           }
-         (*mangled)++;
-         break;
-       case 'U':
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "unsigned");
-         break;
-       case 'S': /* signed char only */
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "signed");
-         break;
-       case 'J':
-         (*mangled)++;
-         APPEND_BLANK (result);
-         string_append (result, "__complex");
-         break;
-       default:
-         done = 1;
-         break;
-       }
-    }
-
-  /* Now pick off the fundamental type.  There can be only one.  */
-
-  switch (**mangled)
-    {
-    case '\0':
-    case '_':
-      break;
-    case 'v':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "void");
-      break;
-    case 'x':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long long");
-      break;
-    case 'l':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long");
-      break;
-    case 'i':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "int");
-      break;
-    case 's':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "short");
-      break;
-    case 'b':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "bool");
-      tk = tk_bool;
-      break;
-    case 'c':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "char");
-      tk = tk_char;
-      break;
-    case 'w':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "wchar_t");
-      tk = tk_char;
-      break;
-    case 'r':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "long double");
-      tk = tk_real;
-      break;
-    case 'd':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "double");
-      tk = tk_real;
-      break;
-    case 'f':
-      (*mangled)++;
-      APPEND_BLANK (result);
-      string_append (result, "float");
-      tk = tk_real;
-      break;
-    case 'G':
-      (*mangled)++;
-      if (!ISDIGIT ((unsigned char)**mangled))
-       {
-         success = 0;
-         break;
-       }
-    case 'I':
-      (*mangled)++;
-      if (**mangled == '_')
-       {
-         int i;
-         (*mangled)++;
-         for (i = 0;
-              i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
-              (*mangled)++, i++)
-           buf[i] = **mangled;
-         if (**mangled != '_')
-           {
-             success = 0;
-             break;
-           }
-         buf[i] = '\0';
-         (*mangled)++;
-       }
-      else
-       {
-         strncpy (buf, *mangled, 2);
-         buf[2] = '\0';
-         *mangled += min (strlen (*mangled), 2);
-       }
-      sscanf (buf, "%x", &dec);
-      sprintf (buf, "int%u_t", dec);
-      APPEND_BLANK (result);
-      string_append (result, buf);
-      break;
-
-      /* fall through */
-      /* An explicit type, such as "6mytype" or "7integer" */
-    case '0':
-    case '1':
-    case '2':
-    case '3':
-    case '4':
-    case '5':
-    case '6':
-    case '7':
-    case '8':
-    case '9':
-      {
-        int bindex = register_Btype (work);
-        string btype;
-        string_init (&btype);
-        if (demangle_class_name (work, mangled, &btype)) {
-          remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
-          APPEND_BLANK (result);
-          string_appends (result, &btype);
-        }
-        else
-          success = 0;
-        string_delete (&btype);
-        break;
-      }
-    case 't':
-      {
-        string btype;
-        string_init (&btype);
-        success = demangle_template (work, mangled, &btype, 0, 1, 1);
-        string_appends (result, &btype);
-        string_delete (&btype);
-        break;
-      }
-    default:
-      success = 0;
-      break;
-    }
-
-  return success ? ((int) tk) : 0;
-}
-
-
-/* Handle a template's value parameter for HP aCC (extension from ARM)
-   **mangled points to 'S' or 'U' */
-
-static int
-do_hpacc_template_const_value (work, mangled, result)
-     struct work_stuff *work ATTRIBUTE_UNUSED;
-     const char **mangled;
-     string *result;
-{
-  int unsigned_const;
-
-  if (**mangled != 'U' && **mangled != 'S')
-    return 0;
-
-  unsigned_const = (**mangled == 'U');
-
-  (*mangled)++;
-
-  switch (**mangled)
-    {
-      case 'N':
-        string_append (result, "-");
-        /* fall through */
-      case 'P':
-        (*mangled)++;
-        break;
-      case 'M':
-        /* special case for -2^31 */
-        string_append (result, "-2147483648");
-        (*mangled)++;
-        return 1;
-      default:
-        return 0;
-    }
-
-  /* We have to be looking at an integer now */
-  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))
-    {
-      char_str[0] = **mangled;
-      string_append (result, char_str);
-      (*mangled)++;
-    }
-
-  if (unsigned_const)
-    string_append (result, "U");
-
-  /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
-     with L or LL suffixes. pai/1997-09-03 */
-
-  return 1; /* success */
-}
-
-/* Handle a template's literal parameter for HP aCC (extension from ARM)
-   **mangled is pointing to the 'A' */
-
-static int
-do_hpacc_template_literal (work, mangled, result)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-{
-  int literal_len = 0;
-  char * recurse;
-  char * recurse_dem;
-
-  if (**mangled != 'A')
-    return 0;
-
-  (*mangled)++;
-
-  literal_len = consume_count (mangled);
-
-  if (literal_len <= 0)
-    return 0;
-
-  /* Literal parameters are names of arrays, functions, etc.  and the
-     canonical representation uses the address operator */
-  string_append (result, "&");
-
-  /* Now recursively demangle the literal name */
-  recurse = (char *) xmalloc (literal_len + 1);
-  memcpy (recurse, *mangled, literal_len);
-  recurse[literal_len] = '\000';
-
-  recurse_dem = cplus_demangle (recurse, work->options);
-
-  if (recurse_dem)
-    {
-      string_append (result, recurse_dem);
-      free (recurse_dem);
-    }
-  else
-    {
-      string_appendn (result, *mangled, literal_len);
-    }
-  (*mangled) += literal_len;
-  free (recurse);
-
-  return 1;
-}
-
-static int
-snarf_numeric_literal (args, arg)
-     const char ** args;
-     string * arg;
-{
-  if (**args == '-')
-    {
-      char_str[0] = '-';
-      string_append (arg, char_str);
-      (*args)++;
-    }
-  else if (**args == '+')
-    (*args)++;
-
-  if (!ISDIGIT ((unsigned char)**args))
-    return 0;
-
-  while (ISDIGIT ((unsigned char)**args))
-    {
-      char_str[0] = **args;
-      string_append (arg, char_str);
-      (*args)++;
-    }
-
-  return 1;
-}
-
-/* Demangle the next argument, given by MANGLED into RESULT, which
-   *should be an uninitialized* string.  It will be initialized here,
-   and free'd should anything go wrong.  */
-
-static int
-do_arg (work, mangled, result)
-     struct work_stuff *work;
-     const char **mangled;
-     string *result;
-{
-  /* Remember where we started so that we can record the type, for
-     non-squangling type remembering.  */
-  const char *start = *mangled;
-
-  string_init (result);
-
-  if (work->nrepeats > 0)
-    {
-      --work->nrepeats;
-
-      if (work->previous_argument == 0)
-       return 0;
-
-      /* We want to reissue the previous type in this argument list.  */
-      string_appends (result, work->previous_argument);
-      return 1;
-    }
-
-  if (**mangled == 'n')
-    {
-      /* A squangling-style repeat.  */
-      (*mangled)++;
-      work->nrepeats = consume_count(mangled);
-
-      if (work->nrepeats <= 0)
-       /* This was not a repeat count after all.  */
-       return 0;
-
-      if (work->nrepeats > 9)
-       {
-         if (**mangled != '_')
-           /* The repeat count should be followed by an '_' in this
-              case.  */
-           return 0;
-         else
-           (*mangled)++;
-       }
-
-      /* Now, the repeat is all set up.  */
-      return do_arg (work, mangled, result);
-    }
-
-  /* Save the result in WORK->previous_argument so that we can find it
-     if it's repeated.  Note that saving START is not good enough: we
-     do not want to add additional types to the back-referenceable
-     type vector when processing a repeated type.  */
-  if (work->previous_argument)
-    string_delete (work->previous_argument);
-  else
-    work->previous_argument = (string*) xmalloc (sizeof (string));
-
-  if (!do_type (work, mangled, work->previous_argument))
-    return 0;
-
-  string_appends (result, work->previous_argument);
-
-  remember_type (work, start, *mangled - start);
-  return 1;
-}
-
-static void
-remember_type (work, start, len)
-     struct work_stuff *work;
-     const char *start;
-     int len;
-{
-  char *tem;
-
-  if (work->forgetting_types)
-    return;
-
-  if (work -> ntypes >= work -> typevec_size)
-    {
-      if (work -> typevec_size == 0)
-       {
-         work -> typevec_size = 3;
-         work -> typevec
-           = (char **) xmalloc (sizeof (char *) * work -> typevec_size);
-       }
-      else
-       {
-         work -> typevec_size *= 2;
-         work -> typevec
-           = (char **) xrealloc ((char *)work -> typevec,
-                                 sizeof (char *) * work -> typevec_size);
-       }
-    }
-  tem = xmalloc (len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> typevec[work -> ntypes++] = tem;
-}
-
-
-/* Remember a K type class qualifier. */
-static void
-remember_Ktype (work, start, len)
-     struct work_stuff *work;
-     const char *start;
-     int len;
-{
-  char *tem;
-
-  if (work -> numk >= work -> ksize)
-    {
-      if (work -> ksize == 0)
-       {
-         work -> ksize = 5;
-         work -> ktypevec
-           = (char **) xmalloc (sizeof (char *) * work -> ksize);
-       }
-      else
-       {
-         work -> ksize *= 2;
-         work -> ktypevec
-           = (char **) xrealloc ((char *)work -> ktypevec,
-                                 sizeof (char *) * work -> ksize);
-       }
-    }
-  tem = xmalloc (len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> ktypevec[work -> numk++] = tem;
-}
-
-/* Register a B code, and get an index for it. B codes are registered
-   as they are seen, rather than as they are completed, so map<temp<char> >
-   registers map<temp<char> > as B0, and temp<char> as B1 */
-
-static int
-register_Btype (work)
-     struct work_stuff *work;
-{
-  int ret;
-
-  if (work -> numb >= work -> bsize)
-    {
-      if (work -> bsize == 0)
-       {
-         work -> bsize = 5;
-         work -> btypevec
-           = (char **) xmalloc (sizeof (char *) * work -> bsize);
-       }
-      else
-       {
-         work -> bsize *= 2;
-         work -> btypevec
-           = (char **) xrealloc ((char *)work -> btypevec,
-                                 sizeof (char *) * work -> bsize);
-       }
-    }
-  ret = work -> numb++;
-  work -> btypevec[ret] = NULL;
-  return(ret);
-}
-
-/* Store a value into a previously registered B code type. */
-
-static void
-remember_Btype (work, start, len, index)
-     struct work_stuff *work;
-     const char *start;
-     int len, index;
-{
-  char *tem;
-
-  tem = xmalloc (len + 1);
-  memcpy (tem, start, len);
-  tem[len] = '\0';
-  work -> btypevec[index] = tem;
-}
-
-/* Lose all the info related to B and K type codes. */
-static void
-forget_B_and_K_types (work)
-     struct work_stuff *work;
-{
-  int i;
-
-  while (work -> numk > 0)
-    {
-      i = --(work -> numk);
-      if (work -> ktypevec[i] != NULL)
-       {
-         free (work -> ktypevec[i]);
-         work -> ktypevec[i] = NULL;
-       }
-    }
-
-  while (work -> numb > 0)
-    {
-      i = --(work -> numb);
-      if (work -> btypevec[i] != NULL)
-       {
-         free (work -> btypevec[i]);
-         work -> btypevec[i] = NULL;
-       }
-    }
-}
-/* Forget the remembered types, but not the type vector itself.  */
-
-static void
-forget_types (work)
-     struct work_stuff *work;
-{
-  int i;
-
-  while (work -> ntypes > 0)
-    {
-      i = --(work -> ntypes);
-      if (work -> typevec[i] != NULL)
-       {
-         free (work -> typevec[i]);
-         work -> typevec[i] = NULL;
-       }
-    }
-}
-
-/* Process the argument list part of the signature, after any class spec
-   has been consumed, as well as the first 'F' character (if any).  For
-   example:
-
-   "__als__3fooRT0"            =>      process "RT0"
-   "complexfunc5__FPFPc_PFl_i" =>      process "PFPc_PFl_i"
-
-   DECLP must be already initialised, usually non-empty.  It won't be freed
-   on failure.
-
-   Note that g++ differs significantly from ARM and lucid style mangling
-   with regards to references to previously seen types.  For example, given
-   the source fragment:
-
-     class foo {
-       public:
-       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
-     };
-
-     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
-     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
-
-   g++ produces the names:
-
-     __3fooiRT0iT2iT2
-     foo__FiR3fooiT1iT1
-
-   while lcc (and presumably other ARM style compilers as well) produces:
-
-     foo__FiR3fooT1T2T1T2
-     __ct__3fooFiR3fooT1T2T1T2
-
-   Note that g++ bases its type numbers starting at zero and counts all
-   previously seen types, while lucid/ARM bases its type numbers starting
-   at one and only considers types after it has seen the 'F' character
-   indicating the start of the function args.  For lucid/ARM style, we
-   account for this difference by discarding any previously seen types when
-   we see the 'F' character, and subtracting one from the type number
-   reference.
-
- */
-
-static int
-demangle_args (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  string arg;
-  int need_comma = 0;
-  int r;
-  int t;
-  const char *tem;
-  char temptype;
-
-  if (PRINT_ARG_TYPES)
-    {
-      string_append (declp, "(");
-      if (**mangled == '\0')
-       {
-         string_append (declp, "void");
-       }
-    }
-
-  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
-        || work->nrepeats > 0)
-    {
-      if ((**mangled == 'N') || (**mangled == 'T'))
-       {
-         temptype = *(*mangled)++;
-
-         if (temptype == 'N')
-           {
-             if (!get_count (mangled, &r))
-               {
-                 return (0);
-               }
-           }
-         else
-           {
-             r = 1;
-           }
-          if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
-            {
-              /* If we have 10 or more types we might have more than a 1 digit
-                 index so we'll have to consume the whole count here. This
-                 will lose if the next thing is a type name preceded by a
-                 count but it's impossible to demangle that case properly
-                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
-                 Pc, ...)"  or "(..., type12, char *, ...)" */
-              if ((t = consume_count(mangled)) <= 0)
-                {
-                  return (0);
-                }
-            }
-          else
-           {
-             if (!get_count (mangled, &t))
-               {
-                 return (0);
-               }
-           }
-         if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-           {
-             t--;
-           }
-         /* Validate the type index.  Protect against illegal indices from
-            malformed type strings.  */
-         if ((t < 0) || (t >= work -> ntypes))
-           {
-             return (0);
-           }
-         while (work->nrepeats > 0 || --r >= 0)
-           {
-             tem = work -> typevec[t];
-             if (need_comma && PRINT_ARG_TYPES)
-               {
-                 string_append (declp, ", ");
-               }
-             if (!do_arg (work, &tem, &arg))
-               {
-                 return (0);
-               }
-             if (PRINT_ARG_TYPES)
-               {
-                 string_appends (declp, &arg);
-               }
-             string_delete (&arg);
-             need_comma = 1;
-           }
-       }
-      else
-       {
-         if (need_comma && PRINT_ARG_TYPES)
-           string_append (declp, ", ");
-         if (!do_arg (work, mangled, &arg))
-           return (0);
-         if (PRINT_ARG_TYPES)
-           string_appends (declp, &arg);
-         string_delete (&arg);
-         need_comma = 1;
-       }
-    }
-
-  if (**mangled == 'e')
-    {
-      (*mangled)++;
-      if (PRINT_ARG_TYPES)
-       {
-         if (need_comma)
-           {
-             string_append (declp, ",");
-           }
-         string_append (declp, "...");
-       }
-    }
-
-  if (PRINT_ARG_TYPES)
-    {
-      string_append (declp, ")");
-    }
-  return (1);
-}
-
-/* Like demangle_args, but for demangling the argument lists of function
-   and method pointers or references, not top-level declarations.  */
-
-static int
-demangle_nested_args (work, mangled, declp)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-{
-  string* saved_previous_argument;
-  int result;
-  int saved_nrepeats;
-
-  /* The G++ name-mangling algorithm does not remember types on nested
-     argument lists, unless -fsquangling is used, and in that case the
-     type vector updated by remember_type is not used.  So, we turn
-     off remembering of types here.  */
-  ++work->forgetting_types;
-
-  /* For the repeat codes used with -fsquangling, we must keep track of
-     the last argument.  */
-  saved_previous_argument = work->previous_argument;
-  saved_nrepeats = work->nrepeats;
-  work->previous_argument = 0;
-  work->nrepeats = 0;
-
-  /* Actually demangle the arguments.  */
-  result = demangle_args (work, mangled, declp);
-
-  /* Restore the previous_argument field.  */
-  if (work->previous_argument)
-    {
-      string_delete (work->previous_argument);
-      free ((char *) work->previous_argument);
-    }
-  work->previous_argument = saved_previous_argument;
-  --work->forgetting_types;
-  work->nrepeats = saved_nrepeats;
-
-  return result;
-}
-
-static void
-demangle_function_name (work, mangled, declp, scan)
-     struct work_stuff *work;
-     const char **mangled;
-     string *declp;
-     const char *scan;
-{
-  size_t i;
-  string type;
-  const char *tem;
-
-  string_appendn (declp, (*mangled), scan - (*mangled));
-  string_need (declp, 1);
-  *(declp -> p) = '\0';
-
-  /* Consume the function name, including the "__" separating the name
-     from the signature.  We are guaranteed that SCAN points to the
-     separator.  */
-
-  (*mangled) = scan + 2;
-  /* We may be looking at an instantiation of a template function:
-     foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
-     following _F marks the start of the function arguments.  Handle
-     the template arguments first. */
-
-  if (HP_DEMANGLING && (**mangled == 'X'))
-    {
-      demangle_arm_hp_template (work, mangled, 0, declp);
-      /* This leaves MANGLED pointing to the 'F' marking func args */
-    }
-
-  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
-    {
-
-      /* See if we have an ARM style constructor or destructor operator.
-        If so, then just record it, clear the decl, and return.
-        We can't build the actual constructor/destructor decl until later,
-        when we recover the class name from the signature.  */
-
-      if (strcmp (declp -> b, "__ct") == 0)
-       {
-         work -> constructor += 1;
-         string_clear (declp);
-         return;
-       }
-      else if (strcmp (declp -> b, "__dt") == 0)
-       {
-         work -> destructor += 1;
-         string_clear (declp);
-         return;
-       }
-    }
-
-  if (declp->p - declp->b >= 3
-      && declp->b[0] == 'o'
-      && declp->b[1] == 'p'
-      && strchr (cplus_markers, declp->b[2]) != NULL)
-    {
-      /* see if it's an assignment expression */
-      if (declp->p - declp->b >= 10 /* op$assign_ */
-         && memcmp (declp->b + 3, "assign_", 7) == 0)
-       {
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             int len = declp->p - declp->b - 10;
-             if ((int) strlen (optable[i].in) == len
-                 && memcmp (optable[i].in, declp->b + 10, len) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 string_append (declp, "=");
-                 break;
-               }
-           }
-       }
-      else
-       {
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             int len = declp->p - declp->b - 3;
-             if ((int) strlen (optable[i].in) == len
-                 && memcmp (optable[i].in, declp->b + 3, len) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 break;
-               }
-           }
-       }
-    }
-  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
-          && strchr (cplus_markers, declp->b[4]) != NULL)
-    {
-      /* type conversion operator */
-      tem = declp->b + 5;
-      if (do_type (work, &tem, &type))
-       {
-         string_clear (declp);
-         string_append (declp, "operator ");
-         string_appends (declp, &type);
-         string_delete (&type);
-       }
-    }
-  else if (declp->b[0] == '_' && declp->b[1] == '_'
-          && declp->b[2] == 'o' && declp->b[3] == 'p')
-    {
-      /* ANSI.  */
-      /* type conversion operator.  */
-      tem = declp->b + 4;
-      if (do_type (work, &tem, &type))
-       {
-         string_clear (declp);
-         string_append (declp, "operator ");
-         string_appends (declp, &type);
-         string_delete (&type);
-       }
-    }
-  else if (declp->b[0] == '_' && declp->b[1] == '_'
-          && ISLOWER((unsigned char)declp->b[2])
-          && ISLOWER((unsigned char)declp->b[3]))
-    {
-      if (declp->b[4] == '\0')
-       {
-         /* Operator.  */
-         for (i = 0; i < ARRAY_SIZE (optable); i++)
-           {
-             if (strlen (optable[i].in) == 2
-                 && memcmp (optable[i].in, declp->b + 2, 2) == 0)
-               {
-                 string_clear (declp);
-                 string_append (declp, "operator");
-                 string_append (declp, optable[i].out);
-                 break;
-               }
-           }
-       }
-      else
-       {
-         if (declp->b[2] == 'a' && declp->b[5] == '\0')
-           {
-             /* Assignment.  */
-             for (i = 0; i < ARRAY_SIZE (optable); i++)
-               {
-                 if (strlen (optable[i].in) == 3
-                     && memcmp (optable[i].in, declp->b + 2, 3) == 0)
-                   {
-                     string_clear (declp);
-                     string_append (declp, "operator");
-                     string_append (declp, optable[i].out);
-                     break;
-                   }
-               }
-           }
-       }
-    }
-}
-
-/* a mini string-handling package */
-
-static void
-string_need (s, n)
-     string *s;
-     int n;
-{
-  int tem;
-
-  if (s->b == NULL)
-    {
-      if (n < 32)
-       {
-         n = 32;
-       }
-      s->p = s->b = xmalloc (n);
-      s->e = s->b + n;
-    }
-  else if (s->e - s->p < n)
-    {
-      tem = s->p - s->b;
-      n += tem;
-      n *= 2;
-      s->b = xrealloc (s->b, n);
-      s->p = s->b + tem;
-      s->e = s->b + n;
-    }
-}
-
-static void
-string_delete (s)
-     string *s;
-{
-  if (s->b != NULL)
-    {
-      free (s->b);
-      s->b = s->e = s->p = NULL;
-    }
-}
-
-static void
-string_init (s)
-     string *s;
-{
-  s->b = s->p = s->e = NULL;
-}
-
-static void
-string_clear (s)
-     string *s;
-{
-  s->p = s->b;
-}
-
-#if 0
-
-static int
-string_empty (s)
-     string *s;
-{
-  return (s->b == s->p);
-}
-
-#endif
-
-static void
-string_append (p, s)
-     string *p;
-     const char *s;
-{
-  int n;
-  if (s == NULL || *s == '\0')
-    return;
-  n = strlen (s);
-  string_need (p, n);
-  memcpy (p->p, s, n);
-  p->p += n;
-}
-
-static void
-string_appends (p, s)
-     string *p, *s;
-{
-  int n;
-
-  if (s->b != s->p)
-    {
-      n = s->p - s->b;
-      string_need (p, n);
-      memcpy (p->p, s->b, n);
-      p->p += n;
-    }
-}
-
-static void
-string_appendn (p, s, n)
-     string *p;
-     const char *s;
-     int n;
-{
-  if (n != 0)
-    {
-      string_need (p, n);
-      memcpy (p->p, s, n);
-      p->p += n;
-    }
-}
-
-static void
-string_prepend (p, s)
-     string *p;
-     const char *s;
-{
-  if (s != NULL && *s != '\0')
-    {
-      string_prependn (p, s, strlen (s));
-    }
-}
-
-static void
-string_prepends (p, s)
-     string *p, *s;
-{
-  if (s->b != s->p)
-    {
-      string_prependn (p, s->b, s->p - s->b);
-    }
-}
-
-static void
-string_prependn (p, s, n)
-     string *p;
-     const char *s;
-     int n;
-{
-  char *q;
-
-  if (n != 0)
-    {
-      string_need (p, n);
-      for (q = p->p - 1; q >= p->b; q--)
-       {
-         q[n] = q[0];
-       }
-      memcpy (p->b, s, n);
-      p->p += n;
-    }
-}
-
-static void
-string_append_template_idx (s, idx)
-     string *s;
-     int idx;
-{
-  char buf[INTBUF_SIZE + 1 /* 'T' */];
-  sprintf(buf, "T%d", idx);
-  string_append (s, buf);
+  return demangled;
 }