OSDN Git Service

Fix mips64vr4100-elf build failure.
[pf3gnuchains/gcc-fork.git] / gcc / cplus-dem.c
index a7f8680..b67250f 100644 (file)
@@ -1,5 +1,5 @@
 /* Demangler for GNU C++ 
-   Copyright 1989, 1991, 1994, 1995, 1996 Free Software Foundation, Inc.
+   Copyright 1989, 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
    Written by James Clark (jjc@jclark.uucp)
    Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
    
@@ -23,12 +23,20 @@ Boston, MA 02111-1307, USA.  */
 
    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. */
+   available memory.  */
+
+/* This file lives in both GCC and libiberty.  When making changes, please
+   try not to break either.  */
 
 #include <ctype.h>
+#include <sys/types.h>
 #include <string.h>
 #include <stdio.h>
 
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include <demangle.h>
 #undef CURRENT_DEMANGLING_STYLE
 #define CURRENT_DEMANGLING_STYLE work->options
@@ -36,11 +44,13 @@ Boston, MA 02111-1307, USA.  */
 extern char *xmalloc PARAMS((unsigned));
 extern char *xrealloc PARAMS((char *, unsigned));
 
-char *
+static const char *mystrstr PARAMS ((const char *, const char *));
+
+static const char *
 mystrstr (s1, s2)
-  char *s1, *s2;
+     const char *s1, *s2;
 {
-  register char *p = s1;
+  register const char *p = s1;
   register int len = strlen (s2);
 
   for (; (p = strchr (p, *s2)) != 0; p++)
@@ -67,7 +77,7 @@ mystrstr (s1, s2)
    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). */
+   marker symbol (FIXME).  */
 
 #if !defined (CPLUS_MARKER)
 #define CPLUS_MARKER '$'
@@ -81,22 +91,30 @@ void
 set_cplus_marker_for_demangling (ch)
      int ch;
 {
-    cplus_markers[0] = ch;
+  cplus_markers[0] = ch;
 }
 
 /* Stuff that is shared between sub-routines.
* Using a shared structure allows cplus_demangle to be reentrant. */
  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 const_type;      /* A const member function */
+  char **tmpl_argvec;   /* Template function arguments. */
+  int ntmpl_args;       /* The number of template function arguments. */
 };
 
 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -185,12 +203,13 @@ static const struct optable
   {"min",        "<?",         0},             /* old */
   {"mn",         "<?",         DMGL_ANSI},     /* pseudo-ansi */
   {"nop",        "",           0},             /* old (for operator=) */
-  {"rm",         "->*",        DMGL_ANSI}      /* ansi */
+  {"rm",         "->*",        DMGL_ANSI},     /* ansi */
+  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
 };
 
 
 typedef struct string          /* Beware: these aren't required to be */
-{                              /*  '\0' terminated. */
+{                              /*  '\0' terminated.  */
   char *b;                     /* pointer to start of string */
   char *p;                     /* pointer after last character */
   char *e;                     /* pointer after end of allocated space */
@@ -198,9 +217,10 @@ typedef struct string              /* Beware: these aren't required to be */
 
 #define STRING_EMPTY(str)      ((str) -> b == (str) -> p)
 #define PREPEND_BLANK(str)     {if (!STRING_EMPTY(str)) \
-                                  string_prepend(str, " ");}
+    string_prepend(str, " ");}
 #define APPEND_BLANK(str)      {if (!STRING_EMPTY(str)) \
-                                  string_append(str, " ");}
+    string_append(str, " ");}
+#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
 
 #define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/ARM virtual table prefix */
 #define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
@@ -210,14 +230,34 @@ typedef struct string             /* Beware: these aren't required to be */
 static char *
 mop_up PARAMS ((struct work_stuff *, string *, int));
 
+static void
+squangle_mop_up PARAMS ((struct work_stuff *));
+
 #if 0
 static int
-demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *));
+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 *));
+                          string *, int));
+
+static int
+arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
+               const char **));
+
+static void
+demangle_arm_pt PARAMS ((struct work_stuff *, const char **, int, string *));
+
+static int
+demangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
 demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
@@ -239,7 +279,7 @@ static int
 gnu_special PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-arm_special PARAMS ((struct work_stuff *, const char **, string *));
+arm_special PARAMS ((const char **, string *));
 
 static void
 string_need PARAMS ((string *, int));
@@ -279,6 +319,9 @@ 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 *));
 
@@ -296,29 +339,81 @@ 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*)); 
+
 /*  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 0. */
+    no consumption of input and a return of 0.  */
 
 static int
 consume_count (type)
-    const char **type;
+     const char **type;
 {
-    int count = 0;
+  int count = 0;
 
-    while (isdigit (**type))
-      {
-       count *= 10;
-       count += **type - '0';
-       (*type)++;
-      }
-    return (count);
+  while (isdigit (**type))
+    {
+      count *= 10;
+      count += **type - '0';
+      (*type)++;
+    }
+  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 (**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;
 }
 
 int
@@ -327,7 +422,7 @@ cplus_demangle_opname (opname, result, options)
      char *result;
      int options;
 {
-  int len, i, len1, ret;
+  int len, len1, ret;
   string type;
   struct work_stuff work[1];
   const char *tem;
@@ -338,7 +433,7 @@ cplus_demangle_opname (opname, result, options)
   work->options = options;
   
   if (opname[0] == '_' && opname[1] == '_'
-         && opname[2] == 'o' && opname[3] == 'p')
+      && opname[2] == 'o' && opname[3] == 'p')
     {
       /* ANSI.  */
       /* type conversion operator.  */
@@ -358,6 +453,7 @@ cplus_demangle_opname (opname, result, options)
       if (opname[4] == '\0')
        {
          /* Operator.  */
+         size_t i;
          for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
            {
              if (strlen (optable[i].in) == 2
@@ -374,7 +470,8 @@ cplus_demangle_opname (opname, result, options)
        {
          if (opname[2] == 'a' && opname[5] == '\0')
            {
-             /* Assignment. */
+             /* Assignment.  */
+             size_t i;
              for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
                {
                  if (strlen (optable[i].in) == 3
@@ -390,14 +487,15 @@ cplus_demangle_opname (opname, result, options)
        }
     }
   else if (len >= 3 
-      && opname[0] == 'o'
-      && opname[1] == 'p'
-      && strchr (cplus_markers, opname[2]) != NULL)
+          && 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 < sizeof (optable) / sizeof (optable[0]); i++)
            {
              len1 = len - 10;
@@ -414,6 +512,7 @@ cplus_demangle_opname (opname, result, options)
        }
       else
        {
+         size_t i;
          for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
            {
              len1 = len - 3;
@@ -441,6 +540,7 @@ cplus_demangle_opname (opname, result, options)
          ret = 1;
        }
     }
+  squangle_mop_up (work);
   return ret;
 
 }
@@ -455,7 +555,7 @@ cplus_mangle_opname (opname, options)
      const char *opname;
      int options;
 {
-  int i;
+  size_t i;
   int len;
 
   len = strlen (opname);
@@ -469,21 +569,6 @@ cplus_mangle_opname (opname, options)
   return (0);
 }
 
-/* check to see whether MANGLED can match TEXT in the first TEXT_LEN
-   characters. */
-
-int cplus_match (mangled, text, text_len)
-     const char *mangled;
-     char *text;
-     int text_len;
-{
-  if (strncmp (mangled, text, text_len) != 0) {
-    return(0); /* cannot match either */
-  } else {
-    return(1); /* matches mangled, may match demangled */
-  }
-}
-
 /* char *cplus_demangle (const char *mangled, int options)
 
    If MANGLED is a mangled function name produced by GNU C++, then
@@ -517,18 +602,44 @@ cplus_demangle (mangled, options)
      const char *mangled;
      int options;
 {
+  char *ret;
+  struct work_stuff work[1];
+  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;
+
+  ret = internal_cplus_demangle (work, mangled);
+  squangle_mop_up (work);
+  return (ret);
+}
+  
+
+/* 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 intializes 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;
-  struct work_stuff work[1];
   char *demangled = NULL;
+  int s1,s2,s3,s4;
+  s1 = work->constructor;
+  s2 = work->destructor;
+  s3 = work->static_type;
+  s4 = work->const_type;
+  work->constructor = work->destructor = 0;
+  work->static_type = work->const_type = 0;
 
   if ((mangled != NULL) && (*mangled != '\0'))
     {
-      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;
-      
       string_init (&decl);
 
       /* First check to see if gnu style demangling is active and if the
@@ -536,7 +647,7 @@ cplus_demangle (mangled, options)
         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. */
+        example.  */
 
       if ((AUTO_DEMANGLING || GNU_DEMANGLING))
        {
@@ -552,19 +663,43 @@ cplus_demangle (mangled, options)
        }
       if (work->constructor == 2)
         {
-          string_prepend(&decl, "global constructors keyed to ");
+          string_prepend (&decl, "global constructors keyed to ");
           work->constructor = 0;
         }
       else if (work->destructor == 2)
         {
-          string_prepend(&decl, "global destructors keyed to ");
+          string_prepend (&decl, "global destructors keyed to ");
           work->destructor = 0;
         }
       demangled = mop_up (work, &decl, success);
     }
+  work->constructor = s1;
+  work->destructor = s2;
+  work->static_type = s3;
+  work->const_type = 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);
+    }
+}
+
+/* Clear out any mangled storage */
+
 static char *
 mop_up (work, declp, success)
      struct work_stuff *work;
@@ -573,16 +708,28 @@ mop_up (work, declp, success)
 {
   char *demangled = NULL;
 
-  /* Discard the remembered types, if any. */
+  /* Discard the remembered types, if any.  */
   
   forget_types (work);
   if (work -> typevec != NULL)
     {
       free ((char *) work -> typevec);
+      work -> typevec = NULL;
     }
-  
+  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 demangling was successful, ensure that the demangled string is null
-     terminated and return it.  Otherwise, free the demangling decl. */
+     terminated and return it.  Otherwise, free the demangling decl.  */
   
   if (!success)
     {
@@ -624,8 +771,7 @@ DESCRIPTION
 
        Demangling GNU style mangled names is nasty because there is no
        explicit token that marks the start of the outermost function
-       argument list.
-*/
+       argument list.  */
 
 static int
 demangle_signature (work, mangled, declp)
@@ -636,6 +782,7 @@ demangle_signature (work, mangled, 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;
@@ -644,239 +791,656 @@ demangle_signature (work, mangled, declp)
     {
       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 '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 'S':
+         /* Static member function */
+         if (oldmangled == NULL)
+           {
+             oldmangled = *mangled;
+           }
+         (*mangled)++;
+         work -> static_type = 1;
+         break;
 
-         case 'C':
-           /* a const member function */
-           if (oldmangled == NULL)
-             {
-               oldmangled = *mangled;
-             }
-           (*mangled)++;
-           work -> const_type = 1;
-           break;
+       case 'C':
+         /* a const member function */
+         if (oldmangled == NULL)
+           {
+             oldmangled = *mangled;
+           }
+         (*mangled)++;
+         work -> const_type = 1;
+         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;
-             }
-           success = demangle_class (work, mangled, declp);
-           if (success)
-             {
-               remember_type (work, oldmangled, *mangled - oldmangled);
-             }
-           if (AUTO_DEMANGLING || GNU_DEMANGLING)
-             {
-               expect_func = 1;
-             }
-           oldmangled = NULL;
-           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;
+           }
+         success = demangle_class (work, mangled, declp);
+         if (success)
+           {
+             remember_type (work, oldmangled, *mangled - oldmangled);
+           }
+         if (AUTO_DEMANGLING || GNU_DEMANGLING)
+           {
+             expect_func = 1;
+           }
+         oldmangled = NULL;
+         break;
          
-         case 'F':
-           /* Function */
-           /* ARM style demangling includes a specific 'F' character after
+       case 'F':
+         /* Function */
+         /* ARM 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. */
+            with either style.  */
 
-           oldmangled = NULL;
-           func_done = 1;
-           (*mangled)++;
+         oldmangled = NULL;
+         func_done = 1;
+         (*mangled)++;
 
-           /* For lucid/ARM 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() */
+         /* For lucid/ARM 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)
-             {
-               forget_types (work);
-             }
-           success = demangle_args (work, mangled, declp);
-           break;
+         if (LUCID_DEMANGLING || ARM_DEMANGLING)
+           {
+             forget_types (work);
+           }
+         success = demangle_args (work, mangled, declp);
+         break;
          
-         case 't':
-           /* G++ Template */
-           string_init(&trawname); 
-           string_init(&tname);
-            if (oldmangled == NULL)
-              {
-                oldmangled = *mangled;
-              }
-           success = demangle_template (work, mangled, &tname, &trawname);
-            if (success)
-              {
-                remember_type (work, oldmangled, *mangled - oldmangled);
-              }
-           string_append(&tname, "::");
-           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 't':
+         /* G++ Template */
+         string_init(&trawname); 
+         string_init(&tname);
+         if (oldmangled == NULL)
+           {
+             oldmangled = *mangled;
+           }
+         success = demangle_template (work, mangled, &tname, &trawname, 1);
+         if (success)
+           {
+             remember_type (work, oldmangled, *mangled - oldmangled);
+           }
+         string_append(&tname, (work -> options & DMGL_JAVA) ? "." : "::");
+         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 (GNU_DEMANGLING && expect_return_type) 
+           {
+             /* Read the return type. */
+             string return_type;
+             string_init (&return_type);
+
+             (*mangled)++;
+             success = do_type (work, mangled, &return_type);
+             APPEND_BLANK (&return_type);
 
-         case '_':
+             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. */
+              reject the entire demangling.  */
            success = 0;
-           break;
+         break;
 
-         default:
-           if (AUTO_DEMANGLING || GNU_DEMANGLING)
+       case 'H':
+         if (GNU_DEMANGLING) 
+           {
+             /* A G++ template function.  Read the template arguments. */
+             success = demangle_template (work, mangled, declp, 0, 0);
+             if (!(work->constructor & 1))
+               expect_return_type = 1;
+             (*mangled)++;
+             break;
+           }
+         else
+           /* fall through */
+           {;}
+
+       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-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;
+           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, 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 && work -> static_type && PRINT_ARG_TYPES)
+    {
+      string_append (declp, " static");
+    }
+  if (success && work -> const_type && PRINT_ARG_TYPES)
+    {
+      string_append (declp, " const");
+    }
+  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')
              {
-               /* Assume we have stumbled onto the first outermost function
-                  argument token, and start processing args. */
-               func_done = 1;
-               success = demangle_args (work, mangled, declp);
+               (*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
              {
-               /* Non-GNU demanglers use a specific token to mark the start
-                  of the outermost function argument tokens.  Typically 'F',
-                  for ARM-demangling, for example.  So if we find something
-                  we are not prepared for, it must be an error. */
-               success = 0;
+               /* temp is initialized in do_type */
+               success = do_type (work, mangled, &temp);
+               if (success)
+                 {
+                   string_appends (tname, &temp);
+                 }
+               string_delete(&temp);
+               if (!success)
+                 {
+                   break;
+                 }
              }
-           break;
+         need_comma = 1;
+       }
+
+    }
+  if (tname->p[-1] == '>')
+    string_append (tname, " ");
+  string_append (tname, "> class");
+  return (success);
+}
+
+static int
+demangle_integral_value (work, mangled, s)
+     struct work_stuff *work;
+     const char** mangled;
+     string* s;
+{
+  int success;
+
+  if (**mangled == 'E')
+    {
+      int need_operator = 0;
+      
+      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 < sizeof (optable) / sizeof (optable [0]);
+                  ++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);
+       }
+
+      if (**mangled != 'W')
+         success = 0;
+      else 
+       {
+         string_appendn (s, ")", 1);
+         (*mangled)++;
+       }
+    }
+  else if (**mangled == 'Q' || **mangled == 'K')
+    success = demangle_qualified (work, mangled, s, 0, 1);
+  else
+    {
+      success = 0;
+
+      if (**mangled == 'm')
+       {
+         string_appendn (s, "-", 1);
+         (*mangled)++;
+       }
+      while (isdigit (**mangled))      
+       {
+         string_appendn (s, *mangled, 1);
+         (*mangled)++;
+         success = 1;
+       }
+    }
+  
+  return success;
+}
+
+static int 
+demangle_template_value_parm (work, mangled, s)
+     struct work_stuff *work;
+     const char **mangled;
+     string* s;
+{
+  const char *old_p = *mangled;
+  int is_pointer = 0;
+  int is_real = 0;
+  int is_integral = 0;
+  int is_char = 0;
+  int is_bool = 0;
+  int done = 0;
+  int success = 1;
+
+  while (*old_p && !done)
+    {  
+      switch (*old_p)
+       {
+       case 'P':
+       case 'p':
+       case 'R':
+         done = is_pointer = 1;
+         break;
+       case 'C':       /* const */
+       case 'S':       /* explicitly signed [char] */
+       case 'U':       /* unsigned */
+       case 'V':       /* volatile */
+       case 'F':       /* function */
+       case 'M':       /* member function */
+       case 'O':       /* ??? */
+       case 'J':       /* complex */
+         old_p++;
+         continue;
+       case 'E':       /* expression */
+       case 'Q':       /* qualified name */
+       case 'K':       /* qualified name */
+         done = is_integral = 1;
+         break;
+       case 'B':       /* squangled name */
+         done = is_integral = 1;
+         break;
+       case 'T':       /* remembered type */
+         abort ();
+         break;
+       case 'v':       /* void */
+         abort ();
+         break;
+       case 'x':       /* long long */
+       case 'l':       /* long */
+       case 'i':       /* int */
+       case 's':       /* short */
+       case 'w':       /* wchar_t */
+         done = is_integral = 1;
+         break;
+       case 'b':       /* bool */
+         done = is_bool = 1;
+         break;
+       case 'c':       /* char */
+         done = is_char = 1;
+         break;
+       case 'r':       /* long double */
+       case 'd':       /* double */
+       case 'f':       /* float */
+         done = is_real = 1;
+         break;
+       default:
+         /* it's probably user defined type, let's assume
+            it's integral, it seems hard to figure out
+            what it really is */
+         done = is_integral = 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
+       {
+         char buf[10];
+         sprintf(buf, "T%d", idx);
+         string_append (s, buf);
+       }
+    }
+  else if (is_integral)
+    success = demangle_integral_value (work, mangled, s);
+  else if (is_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)
+       return -1;
+      tmp[0] = (char)val;
+      tmp[1] = '\0';
+      string_appendn (s, &tmp[0], 1);
+      string_appendn (s, "'", 1);
+    }
+  else if (is_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 (is_real)
+    {
+      if (**mangled == 'm')
+       {
+         string_appendn (s, "-", 1);
+         (*mangled)++;
+       }
+      while (isdigit (**mangled))      
+       {
+         string_appendn (s, *mangled, 1);
+         (*mangled)++;
        }
-/*
-      if (AUTO_DEMANGLING || GNU_DEMANGLING)
-*/
+      if (**mangled == '.') /* fraction */
        {
-         if (success && expect_func)
+         string_appendn (s, ".", 1);
+         (*mangled)++;
+         while (isdigit (**mangled))   
            {
-             func_done = 1;
-             success = demangle_args (work, mangled, declp);
+             string_appendn (s, *mangled, 1);
+             (*mangled)++;
            }
        }
-    }
-  if (success && !func_done)
-    {
-      if (AUTO_DEMANGLING || GNU_DEMANGLING)
+      if (**mangled == 'e') /* exponent */
        {
-         /* 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, 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);
+         string_appendn (s, "e", 1);
+         (*mangled)++;
+         while (isdigit (**mangled))   
+           {
+             string_appendn (s, *mangled, 1);
+             (*mangled)++;
+           }
        }
     }
-  if (success && work -> static_type && PRINT_ARG_TYPES)
-    {
-      string_append (declp, " static");
-    }
-  if (success && work -> const_type && PRINT_ARG_TYPES)
+  else if (is_pointer)
     {
-      string_append (declp, " const");
+      int symbol_len = consume_count (mangled);
+      if (symbol_len == 0)
+       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';
+         q = internal_cplus_demangle (work, p);
+         string_appendn (s, "&", 1);
+         if (q)
+           {
+             string_append (s, q);
+             free (q);
+           }
+         else
+           string_append (s, p);
+         free (p);
+       }
+      *mangled += symbol_len;
     }
-  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);
+  return success;
 }
 
-#endif
-
 static int
-demangle_template (work, mangled, tname, trawname)
+demangle_template (work, mangled, tname, trawname, is_type)
      struct work_stuff *work;
      const char **mangled;
      string *tname;
      string *trawname;
+     int is_type;
 {
   int i;
-  int is_pointer;
-  int is_real;
-  int is_integral;
-  int is_char;
-  int is_bool;
   int r;
   int need_comma = 0;
   int success = 0;
-  int done;
-  const char *old_p;
   const char *start;
-  int symbol_len;
+  int is_java_array = 0;
   string temp;
 
   (*mangled)++;
-  start = *mangled;
-  /* get template name */
-  if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+  if (is_type)
     {
-      return (0);
+      start = *mangled;
+      /* get template name */
+      if (**mangled == 'z')
+       {
+         int idx;
+         (*mangled)++;
+         (*mangled)++;
+
+         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 (work->tmpl_argvec)
+           {
+             string_append (tname, work->tmpl_argvec[idx]);
+             if (trawname)
+               string_append (trawname, work->tmpl_argvec[idx]);
+           }
+         else
+           {
+             char buf[10];
+             sprintf(buf, "T%d", idx);
+             string_append (tname, buf);
+             if (trawname)
+               string_append (trawname, work->tmpl_argvec[idx]);
+           }
+       }
+      else
+       {
+         if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+           {
+             return (0);
+           }
+         if (trawname)
+           string_appendn (trawname, *mangled, r);
+         is_java_array = (work -> options & DMGL_JAVA)
+           && strncmp (*mangled, "JArray1Z", 8) == 0;
+         if (! is_java_array)
+           {
+             string_appendn (tname, *mangled, r);
+           }
+         *mangled += r;
+       }
     }
-  if (trawname)
-    string_appendn (trawname, *mangled, r);
-  string_appendn (tname, *mangled, r);
-  *mangled += r;
-  string_append (tname, "<");
+  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)
@@ -892,6 +1456,15 @@ demangle_template (work, mangled, tname, trawname)
          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)
@@ -899,208 +1472,112 @@ demangle_template (work, mangled, tname, trawname)
              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 && 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 */
-         old_p  = *mangled;
-         is_pointer = 0;
-         is_real = 0;
-         is_integral = 0;
-          is_char = 0;
-         is_bool = 0;
-         done = 0;
+
          /* temp is initialized in do_type */
          success = do_type (work, mangled, &temp);
-/*
-         if (success)
+         /*
+           if (success)
            {
-             string_appends (tname, &temp);
+           string_appends (s, &temp);
            }
-*/
+           */
          string_delete(&temp);
          if (!success)
            {
              break;
            }
-/*
-         string_append (tname, "=");
-*/
-         while (*old_p && !done)
-           {   
-             switch (*old_p)
-               {
-                 case 'P':
-                 case 'p':
-                 case 'R':
-                   done = is_pointer = 1;
-                   break;
-                 case 'C':     /* const */
-                 case 'S':     /* explicitly signed [char] */
-                 case 'U':     /* unsigned */
-                 case 'V':     /* volatile */
-                 case 'F':     /* function */
-                 case 'M':     /* member function */
-                 case 'O':     /* ??? */
-                   old_p++;
-                   continue;
-                 case 'Q':     /* qualified name */
-                    done = is_integral = 1;
-                    break;
-                 case 'T':     /* remembered type */
-                   abort ();
-                   break;
-                 case 'v':     /* void */
-                   abort ();
-                   break;
-                 case 'x':     /* long long */
-                 case 'l':     /* long */
-                 case 'i':     /* int */
-                 case 's':     /* short */
-                 case 'w':     /* wchar_t */
-                   done = is_integral = 1;
-                   break;
-                 case 'b':     /* bool */
-                   done = is_bool = 1;
-                   break;
-                 case 'c':     /* char */
-                   done = is_char = 1;
-                   break;
-                 case 'r':     /* long double */
-                 case 'd':     /* double */
-                 case 'f':     /* float */
-                   done = is_real = 1;
-                   break;
-                 default:
-                   /* it's probably user defined type, let's assume
-                      it's integral, it seems hard to figure out
-                      what it really is */
-                   done = is_integral = 1;
-               }
-           }
-         if (is_integral)
-           {
-             if (**mangled == 'm')
-               {
-                 string_appendn (tname, "-", 1);
-                 (*mangled)++;
-               }
-             while (isdigit (**mangled))       
-               {
-                 string_appendn (tname, *mangled, 1);
-                 (*mangled)++;
-               }
-           }
-         else if (is_char)
+         /*
+           string_append (s, "=");
+           */
+
+         if (!is_type)
            {
-            char tmp[2];
-            int val;
-              if (**mangled == 'm')
-                {
-                  string_appendn (tname, "-", 1);
-                  (*mangled)++;
-                }
-             string_appendn (tname, "'", 1);
-              val = consume_count(mangled);
-             if (val == 0)
-               {
-                 success = 0;
-                 break;
-                }
-              tmp[0] = (char)val;
-              tmp[1] = '\0';
-              string_appendn (tname, &tmp[0], 1);
-             string_appendn (tname, "'", 1);
-           }
-         else if (is_bool)
-           {
-             int val = consume_count (mangled);
-             if (val == 0)
-               string_appendn (tname, "false", 5);
-             else if (val == 1)
-               string_appendn (tname, "true", 4);
-             else
-               success = 0;
+             s = &param;
+             string_init (s);
            }
-         else if (is_real)
+         else
+           s = tname;
+
+         success = demangle_template_value_parm (work, mangled, s);
+
+         if (!success)
            {
-             if (**mangled == 'm')
-               {
-                 string_appendn (tname, "-", 1);
-                 (*mangled)++;
-               }
-             while (isdigit (**mangled))       
-               {
-                 string_appendn (tname, *mangled, 1);
-                 (*mangled)++;
-               }
-             if (**mangled == '.') /* fraction */
-               {
-                 string_appendn (tname, ".", 1);
-                 (*mangled)++;
-                 while (isdigit (**mangled))   
-                   {
-                     string_appendn (tname, *mangled, 1);
-                     (*mangled)++;
-                   }
-               }
-             if (**mangled == 'e') /* exponent */
-               {
-                 string_appendn (tname, "e", 1);
-                 (*mangled)++;
-                 while (isdigit (**mangled))   
-                   {
-                     string_appendn (tname, *mangled, 1);
-                     (*mangled)++;
-                   }
-               }
+             if (!is_type)
+               string_delete (s);
+             success = 0;
+             break;
            }
-         else if (is_pointer)
+
+         if (!is_type)
            {
-             if (!get_count (mangled, &symbol_len))
-               {
-                 success = 0;
-                 break;
-               }
-             if (symbol_len == 0)
-               string_appendn (tname, "0", 1);
-             else
-               {
-                 char *p = xmalloc (symbol_len + 1), *q;
-                 strncpy (p, *mangled, symbol_len);
-                 p [symbol_len] = '\0';
-                 q = cplus_demangle (p, work->options);
-                 string_appendn (tname, "&", 1);
-                 if (q)
-                   {
-                     string_append (tname, q);
-                     free (q);
-                   }
-                 else
-                   string_append (tname, p);
-                 free (p);
-               }
-             *mangled += symbol_len;
+             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 (tname->p[-1] == '>')
-    string_append (tname, " ");
-  string_append (tname, ">");
+  if (is_java_array)
+    {
+      string_append (tname, "[]");
+    }
+  else
+    {
+      if (tname->p[-1] == '>')
+       string_append (tname, " ");
+      string_append (tname, ">");
+    }
   
-/*
-      if (work -> static_type)
-       {
-         string_append (declp, *mangled + 1);
-         *mangled += strlen (*mangled);
-         success = 1;
-       }
-      else
-       {
-         success = demangle_args (work, mangled, declp);
-       }
+  /*
+    if (work -> static_type)
+    {
+    string_append (declp, *mangled + 1);
+    *mangled += strlen (*mangled);
+    success = 1;
     }
-*/
+    else
+    {
+    success = demangle_args (work, mangled, declp);
+    }
+    }
+    */
   return (success);
 }
 
@@ -1114,14 +1591,14 @@ arm_pt (work, mangled, n, anchor, args)
   /* ARM template? */
   if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__")))
     {
-       int len;
-        *args = *anchor + 6;
-       len = consume_count (args);
-        if (*args + len == mangled + n && **args == '_')
-         {
-           ++*args;
-           return 1;
-         }
+      int len;
+      *args = *anchor + 6;
+      len = consume_count (args);
+      if (*args + len == mangled + n && **args == '_')
+       {
+         ++*args;
+         return 1;
+       }
     }
   return 0;
 }
@@ -1139,26 +1616,26 @@ demangle_arm_pt (work, mangled, n, declp)
 
   /* ARM template? */
   if (arm_pt (work, *mangled, n, &p, &args))
-  {
-    string arg;
-    string_init (&arg);
-    string_appendn (declp, *mangled, p - *mangled);
-    string_append (declp, "<");
-    /* should do error checking here */
-    while (args < e) {
-      string_clear (&arg);
-      do_type (work, &args, &arg);
-      string_appends (declp, &arg);
-      string_append (declp, ",");
-    }
-    string_delete (&arg);
-    --declp->p;
-    string_append (declp, ">");
-  }
+    {
+      string arg;
+      string_init (&arg);
+      string_appendn (declp, *mangled, p - *mangled);
+      string_append (declp, "<");
+      /* should do error checking here */
+      while (args < e) {
+       string_clear (&arg);
+       do_type (work, &args, &arg);
+       string_appends (declp, &arg);
+       string_append (declp, ",");
+      }
+      string_delete (&arg);
+      --declp->p;
+      string_append (declp, ">");
+    }
   else
-  {
-    string_appendn (declp, *mangled, n);
-  }
+    {
+      string_appendn (declp, *mangled, n);
+    }
   *mangled += n;
 }
 
@@ -1173,10 +1650,10 @@ demangle_class_name (work, mangled, declp)
 
   n = consume_count (mangled);
   if (strlen (*mangled) >= n)
-  {
-    demangle_arm_pt (work, mangled, n, declp);
-    success = 1;
-  }
+    {
+      demangle_arm_pt (work, mangled, n, declp);
+      success = 1;
+    }
 
   return (success);
 }
@@ -1223,9 +1700,11 @@ demangle_class (work, mangled, declp)
      string *declp;
 {
   int success = 0;
+  int btype;
   string class_name;
 
   string_init (&class_name);
+  btype = register_Btype (work);
   if (demangle_class_name (work, mangled, &class_name))
     {
       if ((work->constructor & 1) || (work->destructor & 1))
@@ -1241,7 +1720,9 @@ demangle_class (work, mangled, declp)
              work -> constructor -= 1; 
            }
        }
-      string_prepend (declp, "::");
+      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
+      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
+      string_prepend (declp, (work -> options & DMGL_JAVA) ? "." : "::");
       string_prepends (declp, &class_name);
       success = 1;
     }
@@ -1326,9 +1807,9 @@ demangle_prefix (work, mangled, declp)
       work->constructor = 2;
     }
 
-/*  This block of code is a reduction in strength time optimization
-    of:
-       scan = mystrstr (*mangled, "__"); */
+  /*  This block of code is a reduction in strength time optimization
+      of:
+      scan = mystrstr (*mangled, "__"); */
 
   {
     scan = *mangled;
@@ -1343,7 +1824,7 @@ demangle_prefix (work, mangled, declp)
   if (scan != NULL)
     {
       /* We found a sequence of two or more '_', ensure that we start at
-        the last pair in the sequence. */
+        the last pair in the sequence.  */
       i = strspn (scan, "_");
       if (i > 2)
        {
@@ -1362,8 +1843,9 @@ demangle_prefix (work, mangled, declp)
          success = 0;
        }
     }
-  else if ((scan == *mangled) &&
-          (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
+  else if ((scan == *mangled)
+          && (isdigit (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>
@@ -1380,7 +1862,8 @@ demangle_prefix (work, mangled, declp)
        {
          /* 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.  */
+            this style of constructor for cfront demangling.  A GNU
+            style member-template constructor starts with 'H'. */
          if (!(LUCID_DEMANGLING || ARM_DEMANGLING))
            work -> constructor += 1;
          *mangled = scan + 2;
@@ -1392,7 +1875,7 @@ demangle_prefix (work, mangled, declp)
         then find the next "__" that separates the prefix from the signature.
         */
       if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
-         || (arm_special (work, mangled, declp) == 0))
+         || (arm_special (mangled, declp) == 0))
        {
          while (*scan == '_')
            {
@@ -1412,7 +1895,7 @@ demangle_prefix (work, mangled, declp)
     }
   else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
     {
-      /* Cfront-style parameterized type.  Handled later as a signature. */
+      /* Cfront-style parameterized type.  Handled later as a signature.  */
       success = 1;
 
       /* ARM template? */
@@ -1422,7 +1905,7 @@ demangle_prefix (work, mangled, declp)
     {
       /* 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. */
+        function name.  */
       demangle_function_name (work, mangled, declp, scan);
     }
   else
@@ -1491,14 +1974,14 @@ gnu_special (work, mangled, declp)
                && (*mangled)[2] == 'v'
                && (*mangled)[3] == 't'
                && (*mangled)[4] == '_')
-            || ((*mangled)[1] == 'v'
-                && (*mangled)[2] == 't'
-                && strchr (cplus_markers, (*mangled)[3]) != NULL)))
+              || ((*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. */
+        to do.  */
       if ((*mangled)[2] == 'v')
        (*mangled) += 5; /* New style, with thunks: "__vt_" */
       else
@@ -1509,15 +1992,25 @@ gnu_special (work, mangled, declp)
          switch (**mangled)
            {
            case 'Q':
+           case 'K':
              success = demangle_qualified (work, mangled, declp, 0, 1);
              break;
            case 't':
-             success = demangle_template (work, mangled, declp, 0);
+             success = demangle_template (work, mangled, declp, 0, 1);
              break;
            default:
              if (isdigit(*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 > strlen (*mangled))
+                   {
+                     success = 1;
+                     break;
+                   }
                }
              else
                {
@@ -1531,7 +2024,8 @@ gnu_special (work, mangled, declp)
            {
              if (p != NULL)
                {
-                 string_append (declp, "::");
+                 string_append (declp,
+                                (work -> options & DMGL_JAVA) ? "." : "::");
                  (*mangled)++;
                }
            }
@@ -1552,23 +2046,24 @@ gnu_special (work, mangled, declp)
       (*mangled)++;
       switch (**mangled)
        {
-         case 'Q':
-           success = demangle_qualified (work, mangled, declp, 0, 1);
-           break;
-         case 't':
-           success = demangle_template (work, mangled, declp, 0);
-           break;
-         default:
-           n = consume_count (mangled);
-           string_appendn (declp, *mangled, n);
-           (*mangled) += n;
+       case 'Q':
+       case 'K':
+         success = demangle_qualified (work, mangled, declp, 0, 1);
+         break;
+       case 't':
+         success = demangle_template (work, mangled, declp, 0, 1);
+         break;
+       default:
+         n = consume_count (mangled);
+         string_appendn (declp, *mangled, n);
+         (*mangled) += n;
        }
       if (success && (p == *mangled))
        {
          /* Consumed everything up to the cplus_marker, append the
-            variable name. */
+            variable name.  */
          (*mangled)++;
-         string_append (declp, "::");
+         string_append (declp, (work -> options & DMGL_JAVA) ? "." : "::");
          n = strlen (*mangled);
          string_appendn (declp, *mangled, n);
          (*mangled) += n;
@@ -1581,7 +2076,7 @@ gnu_special (work, mangled, declp)
   else if (strncmp (*mangled, "__thunk_", 8) == 0)
     {
       int delta = ((*mangled) += 8, consume_count (mangled));
-      char *method = cplus_demangle (++*mangled, work->options);
+      char *method = internal_cplus_demangle (work, ++*mangled);
       if (method)
        {
          char buf[50];
@@ -1597,6 +2092,29 @@ gnu_special (work, mangled, declp)
          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);
+         break;
+       default:
+         success = demangle_fund_type (work, mangled, declp);
+         break;
+       }
+      if (success && **mangled != '\0')
+       success = 0;
+      if (success)
+       string_append (declp, p);
+    }
   else
     {
       success = 0;
@@ -1613,8 +2131,8 @@ LOCAL FUNCTION
 SYNOPSIS
 
        static int
-       arm_special (struct work_stuff *work, const char **mangled,
-                       string *declp);
+       arm_special (const char **mangled,
+                    string *declp);
 
 
 DESCRIPTION
@@ -1628,8 +2146,7 @@ DESCRIPTION
  */
 
 static int
-arm_special (work, mangled, declp)
-     struct work_stuff *work;
+arm_special (mangled, declp)
      const char **mangled;
      string *declp;
 {
@@ -1642,7 +2159,7 @@ arm_special (work, mangled, declp)
       /* 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. */
+        to do.  */
       scan = *mangled + ARM_VTABLE_STRLEN;
       while (*scan != '\0')        /* first check it can be demangled */
         {
@@ -1718,7 +2235,7 @@ demangle_qualified (work, mangled, result, isfuncname, append)
      int isfuncname;
      int append;
 {
-  int qualifiers;
+  int qualifiers = 0;
   int namelength;
   int success = 1;
   const char *p;
@@ -1726,7 +2243,20 @@ demangle_qualified (work, mangled, result, isfuncname, append)
   string temp;
 
   string_init (&temp);
-  switch ((*mangled)[1])
+
+  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
@@ -1780,15 +2310,34 @@ demangle_qualified (work, mangled, result, isfuncname, append)
     return success;
 
   /* Pick off the names and collect them in the temp buffer in the order
-     in which they are found, separated by '::'. */
+     in which they are found, separated by '::'.  */
 
   while (qualifiers-- > 0)
     {
+      int remember_K = 1;
       if (*mangled[0] == '_') 
        *mangled = *mangled + 1;
       if (*mangled[0] == 't')
        {
-         success = demangle_template(work, mangled, &temp, 0);
+         success = demangle_template(work, mangled, &temp, 0, 1);
+         if (!success) break;
+       }
+      else if (*mangled[0] == 'X')
+       {
+         success = do_type (work, mangled, &temp);
+         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
@@ -1796,27 +2345,33 @@ demangle_qualified (work, mangled, result, isfuncname, append)
          namelength = consume_count (mangled);
          if (strlen (*mangled) < namelength)
            {
-           /* Simple sanity check failed */
-              success = 0;
-              break;
+             /* Simple sanity check failed */
+             success = 0;
+             break;
            }
          string_appendn (&temp, *mangled, namelength);
          *mangled += namelength;
        }
+
+      if (remember_K)
+        {
+        remember_Ktype (work, temp.b, LEN_STRING (&temp));
+        }
+
       if (qualifiers > 0)
         {
-          string_appendn (&temp, "::", 2);
+          string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::");
         }
     }
 
   /* 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. */
+     we already have a pointer to the name and the length of the name.  */
 
   if (isfuncname && (work->constructor & 1 || work->destructor & 1))
     {
-      string_appendn (&temp, "::", 2);
+      string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::");
       if (work -> destructor & 1)
        {
          string_append (&temp, "~");
@@ -1825,7 +2380,7 @@ demangle_qualified (work, mangled, result, isfuncname, append)
     }
 
   /* Now either prepend the temp buffer to the result, or append it, 
-     depending upon the state of the append flag. */
+     depending upon the state of the append flag.  */
 
   if (append)
     {
@@ -1835,7 +2390,7 @@ demangle_qualified (work, mangled, result, isfuncname, append)
     {
       if (!STRING_EMPTY (result))
        {
-         string_appendn (&temp, "::", 2);
+         string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::");
        }
       string_prepends (result, &temp);
     }
@@ -1912,7 +2467,9 @@ do_type (work, mangled, result)
   const char *remembered_type;
   int constp;
   int volatilep;
+  string btype;
 
+  string_init (&btype);
   string_init (&decl);
   string_init (result);
 
@@ -1924,20 +2481,21 @@ do_type (work, mangled, result)
       switch (**mangled)
        {
 
-       /* A pointer type */
+         /* A pointer type */
        case 'P':
        case 'p':
          (*mangled)++;
-         string_prepend (&decl, "*");
+         if (! (work -> options & DMGL_JAVA))
+           string_prepend (&decl, "*");
          break;
 
-       /* A reference type */
+         /* A reference type */
        case 'R':
          (*mangled)++;
          string_prepend (&decl, "&");
          break;
 
-       /* An array */
+         /* An array */
        case 'A':
          {
            const char *p = ++(*mangled);
@@ -1973,7 +2531,7 @@ do_type (work, mangled, result)
            }
          break;
 
-       /* A function */
+         /* A function */
        case 'F':
          (*mangled)++;
          if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
@@ -1983,7 +2541,7 @@ do_type (work, mangled, result)
            }
          /* After picking off the function args, we expect to either find the
             function return type (preceded by an '_') or the end of the
-            string. */
+            string.  */
          if (!demangle_args (work, mangled, &decl)
              || (**mangled != '_' && **mangled != '\0'))
            {
@@ -2003,22 +2561,39 @@ do_type (work, mangled, result)
 
            member = **mangled == 'M';
            (*mangled)++;
-           if (!isdigit (**mangled))
+           if (!isdigit (**mangled) && **mangled != 't')
              {
                success = 0;
                break;
              }
-           n = consume_count (mangled);
-           if (strlen (*mangled) < n)
+
+           string_append (&decl, ")");
+           string_prepend (&decl, (work -> options & DMGL_JAVA) ? "." : "::");
+           if (isdigit (**mangled)) 
+             {
+               n = consume_count (mangled);
+               if (strlen (*mangled) < n)
+                 {
+                   success = 0;
+                   break;
+                 }
+               string_prependn (&decl, *mangled, n);
+               *mangled += n;
+             }
+           else
              {
-               success = 0;
-               break;
+               string temp;
+               string_init (&temp);
+               success = demangle_template (work, mangled, &temp, NULL, 1);
+               if (success)
+                 {
+                   string_prependn (&decl, temp.b, temp.p - temp.b);
+                   string_clear (&temp);
+                 }
+               else
+                 break;
              }
-           string_append (&decl, ")");
-           string_prepend (&decl, "::");
-           string_prependn (&decl, *mangled, n);
            string_prepend (&decl, "(");
-           *mangled += n;
            if (member)
              {
                if (**mangled == 'C')
@@ -2061,27 +2636,29 @@ do_type (work, mangled, result)
            break;
          }
         case 'G':
-           (*mangled)++;
-           break;
+         (*mangled)++;
+         break;
 
        case 'C':
-         (*mangled)++;
-/*
-         if ((*mangled)[1] == 'P')
+       case 'V':
+         /*
+           if ((*mangled)[1] == 'P')
            {
-*/
-             if (PRINT_ANSI_QUALIFIERS)
+           */
+         if (PRINT_ANSI_QUALIFIERS)
+           {
+             if (!STRING_EMPTY (&decl))
                {
-                 if (!STRING_EMPTY (&decl))
-                   {
-                     string_prepend (&decl, " ");
-                   }
-                 string_prepend (&decl, "const");
+                 string_prepend (&decl, " ");
                }
-             break;
-/*
+             string_prepend (&decl, 
+                             (**mangled) == 'C' ? "const" : "volatile");
            }
-*/
+         (*mangled)++;
+         break;
+         /*
+           }
+           */
 
          /* fall through */
        default:
@@ -2092,14 +2669,61 @@ do_type (work, mangled, result)
 
   switch (**mangled)
     {
-      /* A qualified name, such as "Outer::Inner". */
-      case 'Q':
+      /* A qualified name, such as "Outer::Inner".  */
+    case 'Q':
+    case 'K':
+      {
+        int btype = register_Btype (work);
         success = demangle_qualified (work, mangled, result, 0, 1);
-       break;
+        remember_Btype (work, result->b, LEN_STRING (result), btype);
+
+        break;
+      }
 
-      default:
-       success = demangle_fund_type (work, mangled, result);
-       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
+         {
+           char buf[10];
+           sprintf(buf, "T%d", idx);
+           string_append (result, buf);
+         }
+
+       success = 1;
+      }
+    break;
+
+    default:
+      success = demangle_fund_type (work, mangled, result);
+      break;
     }
 
   if (success)
@@ -2139,139 +2763,159 @@ demangle_fund_type (work, mangled, result)
 {
   int done = 0;
   int success = 1;
+  string btype;
+  string_init (&btype);
 
-  /* First pick off any type qualifiers.  There can be more than one. */
+  /* First pick off any type qualifiers.  There can be more than one.  */
 
   while (!done)
     {
       switch (**mangled)
        {
-         case 'C':
-           (*mangled)++;
-           if (PRINT_ANSI_QUALIFIERS)
-             {
-               APPEND_BLANK (result);
-               string_append (result, "const");
-             }
-           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 'V':
-           (*mangled)++;
-           if (PRINT_ANSI_QUALIFIERS)
-             {
-               APPEND_BLANK (result);
-               string_append (result, "volatile");
-             }
-           break;
-         default:
-           done = 1;
-           break;
+       case 'C':
+         (*mangled)++;
+         if (PRINT_ANSI_QUALIFIERS)
+           {
+             APPEND_BLANK (result);
+             string_append (result, "const");
+           }
+         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 'V':
+         (*mangled)++;
+         if (PRINT_ANSI_QUALIFIERS)
+           {
+             APPEND_BLANK (result);
+             string_append (result, "volatile");
+           }
+         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. */
+  /* 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");
-       break;
-      case 'c':
-       (*mangled)++;
-       APPEND_BLANK (result);
-       string_append (result, "char");
-       break;
-      case 'w':
-       (*mangled)++;
-       APPEND_BLANK (result);
-       string_append (result, "wchar_t");
-       break;
-      case 'r':
-       (*mangled)++;
-       APPEND_BLANK (result);
-       string_append (result, "long double");
-       break;
-      case 'd':
-       (*mangled)++;
-       APPEND_BLANK (result);
-       string_append (result, "double");
-       break;
-      case 'f':
-       (*mangled)++;
-       APPEND_BLANK (result);
-       string_append (result, "float");
-       break;
-      case 'G':
-       (*mangled)++;
-       if (!isdigit (**mangled))
-         {
-           success = 0;
-           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':
-       APPEND_BLANK (result);
-       if (!demangle_class_name (work, mangled, result)) {
-         --result->p;
+    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");
+      break;
+    case 'c':
+      (*mangled)++;
+      APPEND_BLANK (result);
+      string_append (result, "char");
+      break;
+    case 'w':
+      (*mangled)++;
+      APPEND_BLANK (result);
+      string_append (result, "wchar_t");
+      break;
+    case 'r':
+      (*mangled)++;
+      APPEND_BLANK (result);
+      string_append (result, "long double");
+      break;
+    case 'd':
+      (*mangled)++;
+      APPEND_BLANK (result);
+      string_append (result, "double");
+      break;
+    case 'f':
+      (*mangled)++;
+      APPEND_BLANK (result);
+      string_append (result, "float");
+      break;
+    case 'G':
+      (*mangled)++;
+      if (!isdigit (**mangled))
+       {
          success = 0;
+         break;
        }
-       break;
-      case 't':
-        success = demangle_template(work,mangled, result, 0);
+      /* 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':
+      {
+        int bindex= register_Btype (work);
+        success = demangle_template (work, mangled, &btype, 0, 1);
+        remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
+        string_appends (result, &btype);
         break;
-      default:
-       success = 0;
-       break;
       }
+    default:
+      success = 0;
+      break;
+    }
 
   return (success);
 }
@@ -2310,15 +2954,15 @@ remember_type (work, start, len)
       if (work -> typevec_size == 0)
        {
          work -> typevec_size = 3;
-         work -> typevec =
-           (char **) xmalloc (sizeof (char *) * work -> typevec_size);
+         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);
+         work -> typevec
+           (char **) xrealloc ((char *)work -> typevec,
+                                 sizeof (char *) * work -> typevec_size);
        }
     }
   tem = xmalloc (len + 1);
@@ -2327,7 +2971,113 @@ remember_type (work, start, len)
   work -> typevec[work -> ntypes++] = tem;
 }
 
-/* Forget the remembered types, but not the type vector itself. */
+
+/* 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)
@@ -2452,7 +3202,7 @@ demangle_args (work, mangled, declp)
              t--;
            }
          /* Validate the type index.  Protect against illegal indices from
-            malformed type strings. */
+            malformed type strings.  */
          if ((t < 0) || (t >= work -> ntypes))
            {
              return (0);
@@ -2522,8 +3272,7 @@ demangle_function_name (work, mangled, declp, scan)
      string *declp;
      const char *scan;
 {
-  int i;
-  int len;
+  size_t i;
   string type;
   const char *tem;
 
@@ -2533,7 +3282,7 @@ demangle_function_name (work, mangled, declp, scan)
 
   /* Consume the function name, including the "__" separating the name
      from the signature.  We are guaranteed that SCAN points to the
-     separator. */
+     separator.  */
 
   (*mangled) = scan + 2;
 
@@ -2543,7 +3292,7 @@ demangle_function_name (work, mangled, declp, scan)
       /* 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. */
+        when we recover the class name from the signature.  */
 
       if (strcmp (declp -> b, "__ct") == 0)
        {
@@ -2570,7 +3319,7 @@ demangle_function_name (work, mangled, declp, scan)
        {
          for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
            {
-             len = declp->p - declp->b - 10;
+             int len = declp->p - declp->b - 10;
              if (strlen (optable[i].in) == len
                  && memcmp (optable[i].in, declp->b + 10, len) == 0)
                {
@@ -2612,7 +3361,7 @@ demangle_function_name (work, mangled, declp, scan)
        }
     }
   else if (declp->b[0] == '_' && declp->b[1] == '_'
-         && declp->b[2] == 'o' && declp->b[3] == 'p')
+          && declp->b[2] == 'o' && declp->b[3] == 'p')
     {
       /* ANSI.  */
       /* type conversion operator.  */
@@ -2648,7 +3397,7 @@ demangle_function_name (work, mangled, declp, scan)
        {
          if (declp->b[2] == 'a' && declp->b[5] == '\0')
            {
-             /* Assignment. */
+             /* Assignment.  */
              for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
                {
                  if (strlen (optable[i].in) == 3
@@ -2817,17 +3566,27 @@ string_prependn (p, s, n)
 /* To generate a standalone demangler program for testing purposes,
    just compile and link this file with -DMAIN and libiberty.a.  When
    run, it demangles each command line arg, or each stdin string, and
-   prints the result on stdout. */
+   prints the result on stdout.  */
 
 #ifdef MAIN
 
+#include "getopt.h"
+
+static char *program_name;
+static char *program_version = VERSION;
+static int flags = DMGL_PARAMS | DMGL_ANSI;
+
+static void demangle_it PARAMS ((char *));
+static void usage PARAMS ((FILE *, int));
+static void fatal PARAMS ((char *));
+
 static void
 demangle_it (mangled_name)
-  char *mangled_name;
+     char *mangled_name;
 {
   char *result;
 
-  result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
+  result = cplus_demangle (mangled_name, flags);
   if (result == NULL)
     {
       printf ("%s\n", mangled_name);
@@ -2839,11 +3598,6 @@ demangle_it (mangled_name)
     }
 }
 
-#include "getopt.h"
-
-static char *program_name;
-static char *program_version = VERSION;
-
 static void
 usage (stream, status)
      FILE *stream;
@@ -2851,16 +3605,16 @@ usage (stream, status)
 {    
   fprintf (stream, "\
 Usage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
-       [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
-       [--help] [--version] [arg...]\n",
+      [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
+      [--help] [--version] [arg...]\n",
           program_name);
   exit (status);
 }
 
-#define MBUF_SIZE 512
+#define MBUF_SIZE 32767
 char mbuffer[MBUF_SIZE];
 
-/* Defined in the automatically-generated underscore.c. */
+/* Defined in the automatically-generated underscore.c.  */
 extern int prepends_underscore;
 
 int strip_underscore = 0;
@@ -2869,11 +3623,21 @@ static struct option long_options[] = {
   {"strip-underscores", no_argument, 0, '_'},
   {"format", required_argument, 0, 's'},
   {"help", no_argument, 0, 'h'},
+  {"java", no_argument, 0, 'j'},
   {"no-strip-underscores", no_argument, 0, 'n'},
   {"version", no_argument, 0, 'v'},
   {0, no_argument, 0, 0}
 };
 
+/* More 'friendly' abort that prints the line and file.
+   config.h can #define abort fancy_abort if you like that sort of thing.  */
+
+void
+fancy_abort ()
+{
+  fatal ("Internal gcc abort.");
+}
+
 int
 main (argc, argv)
      int argc;
@@ -2886,44 +3650,47 @@ main (argc, argv)
 
   strip_underscore = prepends_underscore;
 
-  while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
+  while ((c = getopt_long (argc, argv, "_ns:j", long_options, (int *) 0)) != EOF)
     {
       switch (c)
        {
-         case '?':
-           usage (stderr, 1);
-           break;
-         case 'h':
-           usage (stdout, 0);
-         case 'n':
-           strip_underscore = 0;
-           break;
-         case 'v':
-           printf ("GNU %s version %s\n", program_name, program_version);
-           exit (0);
-         case '_':
-           strip_underscore = 1;
-           break;
-         case 's':
-           if (strcmp (optarg, "gnu") == 0)
-             {
-               current_demangling_style = gnu_demangling;
-             }
-           else if (strcmp (optarg, "lucid") == 0)
-             {
-               current_demangling_style = lucid_demangling;
-             }
-           else if (strcmp (optarg, "arm") == 0)
-             {
-               current_demangling_style = arm_demangling;
-             }
-           else
-             {
-               fprintf (stderr, "%s: unknown demangling style `%s'\n",
-                        program_name, optarg);
-               exit (1);
-             }
-           break;
+       case '?':
+         usage (stderr, 1);
+         break;
+       case 'h':
+         usage (stdout, 0);
+       case 'n':
+         strip_underscore = 0;
+         break;
+       case 'v':
+         printf ("GNU %s version %s\n", program_name, program_version);
+         exit (0);
+       case '_':
+         strip_underscore = 1;
+         break;
+       case 'j':
+         flags |= DMGL_JAVA;
+         break;
+       case 's':
+         if (strcmp (optarg, "gnu") == 0)
+           {
+             current_demangling_style = gnu_demangling;
+           }
+         else if (strcmp (optarg, "lucid") == 0)
+           {
+             current_demangling_style = lucid_demangling;
+           }
+         else if (strcmp (optarg, "arm") == 0)
+           {
+             current_demangling_style = arm_demangling;
+           }
+         else
+           {
+             fprintf (stderr, "%s: unknown demangling style `%s'\n",
+                      program_name, optarg);
+             exit (1);
+           }
+         break;
        }
     }
 
@@ -2940,7 +3707,7 @@ main (argc, argv)
        {
          int i = 0;
          c = getchar ();
-         /* Try to read a label. */
+         /* Try to read a label.  */
          while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
            {
              if (i >= MBUF_SIZE-1)
@@ -2962,8 +3729,7 @@ main (argc, argv)
 
              mbuffer[i] = 0;
              
-             result = cplus_demangle (mbuffer + skip_first,
-                                      DMGL_PARAMS | DMGL_ANSI);
+             result = cplus_demangle (mbuffer + skip_first, flags);
              if (result)
                {
                  if (mbuffer[0] == '.')