* utils.c (strcmp_iw): Add a hack to allow "FOO(ARGS)" to
[deliverable/binutils-gdb.git] / gdb / cplus-dem.c
index 911e1b2c731950fdbb47ffe9668e4685a5184b28..b9c6288853f382a41befd58d0d9f7b374858d554 100644 (file)
 #include <ctype.h>
 #include <string.h>
 
-#if !defined (GNU_DEMANGLING) && !defined (ARM_DEMANGLING)
-# define GNU_DEMANGLING 1
-#endif
-
-/* This is '$' on systems where the assembler can deal with that.
-   Where the assembler can't, it's '.' (but on many systems '.' is
-   used for other things).  */
+/* 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
 
+static const char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
+
 #ifndef __STDC__
 #define const
 #endif
@@ -91,11 +101,8 @@ static const struct optable
   "ami",         "-=",         DMGL_ANSI,      /* ansi */
   "mult",        "*",          0,              /* old */
   "ml",                  "*",          DMGL_ANSI,      /* ansi */
-#ifdef ARM_DEMANGLING
-  "amu",         "*=",         DMGL_ANSI,      /* ansi */
-#else
-  "aml",         "*=",         DMGL_ANSI,      /* ansi */
-#endif
+  "amu",         "*=",         DMGL_ANSI,      /* ansi (ARM/Lucid) */
+  "aml",         "*=",         DMGL_ANSI,      /* ansi (GNU/g++) */
   "convert",     "+",          0,              /* old (unary +) */
   "negate",      "-",          0,              /* old (unary -) */
   "trunc_mod",   "%",          0,              /* old */
@@ -134,11 +141,8 @@ static const struct optable
   "rs",                  ">>",         DMGL_ANSI,      /* ansi */
   "ars",         ">>=",        DMGL_ANSI,      /* ansi */
   "component",   "->",         0,              /* old */
-#ifdef LUCID_DEMANGLING
   "pt",                  "->",         DMGL_ANSI,      /* ansi; Lucid C++ form */
-#else
-  "rf",                  "->",         DMGL_ANSI,      /* ansi */
-#endif
+  "rf",                  "->",         DMGL_ANSI,      /* ansi; ARM/GNU form */
   "indirect",    "*",          0,              /* old */
   "method_call",  "->()",      0,              /* old */
   "addr",        "&",          0,              /* old (unary &) */
@@ -170,36 +174,43 @@ typedef struct string             /* Beware: these aren't required to be */
 #define APPEND_BLANK(str)      {if (!STRING_EMPTY(str)) \
                                   string_append(str, " ");}
 
+#define ARM_VTABLE_STRING "__vtbl__"   /* Lucid/cfront virtual table prefix */
+#define ARM_VTABLE_STRLEN 8            /* strlen (ARM_VTABLE_STRING) */
+
 /* Prototypes for local functions */
 
 static char *
-mop_up PARAMS ((string *, struct work_stuff *, int));
+mop_up PARAMS ((struct work_stuff *, string *, int));
 
 #if 0
 static int
-demangle_method_args PARAMS ((string *, const char **, struct work_stuff *));
+demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *));
 #endif
 
 static int
-demangle_template PARAMS ((string *declp, const char **, struct work_stuff *));
+demangle_template PARAMS ((struct work_stuff *work, const char **, string *));
+
+static int
+demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
+                           int));
 
 static int
-demangle_qualified PARAMS ((string *, const char **, struct work_stuff *));
+demangle_class PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-demangle_class PARAMS ((string *, const char **, struct work_stuff *));
+demangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-demangle_fund_type PARAMS ((const char **, string *, struct work_stuff *));
+demangle_signature PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-demangle_signature PARAMS ((string *, const char **, struct work_stuff *));
+demangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-demangle_prefix PARAMS ((string *, const char **, struct work_stuff *));
+gnu_special PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-gnu_special PARAMS ((string *, const char **, struct work_stuff *));
+cfront_special PARAMS ((struct work_stuff *, const char **, string *));
 
 static void
 string_need PARAMS ((string *, int));
@@ -240,20 +251,23 @@ static int
 consume_count PARAMS ((const char **));
 
 static int
-demangle_args PARAMS ((string *, const char **, struct work_stuff *));
+demangle_args PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-do_type PARAMS ((const char **, string *, struct work_stuff *));
+do_type PARAMS ((struct work_stuff *, const char **, string *));
 
 static int
-do_arg PARAMS ((const char **, string *, struct work_stuff*));
+do_arg PARAMS ((struct work_stuff *, const char **, string *));
 
 static void
-demangle_function_name PARAMS ((string *, const char **, struct work_stuff*,
+demangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
                                const char *));
 
 static void
-remember_type PARAMS ((const char *, int, struct work_stuff *));
+remember_type PARAMS ((struct work_stuff *, const char *, int));
+
+static void
+forget_types PARAMS ((struct work_stuff *));
 
 #if 0
 static void
@@ -347,20 +361,36 @@ cplus_demangle (mangled, options)
       work -> options = options;
       
       string_init (&decl);
-      success = demangle_prefix (&decl, &mangled, work);
+
+      /* 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)
+         && (strpbrk (mangled, cplus_markers)) != NULL)
+       {
+         success = gnu_special (work, &mangled, &decl);
+       }
+      else
+       {
+         success = demangle_prefix (work, &mangled, &decl);
+       }
       if (success && (*mangled != '\0'))
        {
-         success = demangle_signature (&decl, &mangled, work);
+         success = demangle_signature (work, &mangled, &decl);
        }
-      demangled = mop_up (&decl, work, success);
+      demangled = mop_up (work, &decl, success);
     }
   return (demangled);
 }
 
 static char *
-mop_up (declp, work, success)
-     string *declp;
+mop_up (work, declp, success)
      struct work_stuff *work;
+     string *declp;
      int success;
 {
   int i;
@@ -368,13 +398,7 @@ mop_up (declp, work, success)
 
   /* Discard the remembered types, if any. */
   
-  for (i = 0; i < work -> ntypes; i++)
-    {
-      if (work -> typevec[i] != NULL)
-       {
-         free (work -> typevec[i]);
-       }
-    }
+  forget_types (work);
   if (work -> typevec != NULL)
     {
       free ((char *) work -> typevec);
@@ -404,8 +428,8 @@ LOCAL FUNCTION
 SYNOPSIS
 
        static int
-       demangle_signature (string *declp, const char **mangled,
-                           struct work_stuff *work);
+       demangle_signature (struct work_stuff *work, const char **mangled,
+                           string *declp);
 
 DESCRIPTION
 
@@ -427,33 +451,31 @@ DESCRIPTION
 */
 
 static int
-demangle_signature (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+demangle_signature (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int success = 1;
   int func_done = 0;
-#ifdef GNU_DEMANGLING
   int expect_func = 0;
-#endif
-#ifndef LONGERNAMES
-  const char *premangle;
-#endif
-
-#ifndef LONGERNAMES
-  premangle = *mangled;
-#endif
+  const char *oldmangled;
 
   while (success && (**mangled != '\0'))
     {
       switch (**mangled)
        {
          case 'Q':
-           success = demangle_qualified (declp, mangled, work);
-#ifdef GNU_DEMANGLING
-           expect_func = 1;
-#endif
+           oldmangled = *mangled;
+           success = demangle_qualified (work, mangled, declp, 1);
+           if (success)
+             {
+               remember_type (work, oldmangled, *mangled - oldmangled);
+             }
+           if (AUTO_DEMANGLING || GNU_DEMANGLING)
+             {
+               expect_func = 1;
+             }
            break;
          
          case 'S':
@@ -470,16 +492,16 @@ demangle_signature (declp, mangled, work)
          
          case '0': case '1': case '2': case '3': case '4':
          case '5': case '6': case '7': case '8': case '9':
-           success = demangle_class (declp, mangled, work);
-#ifndef LONGERNAMES
+           oldmangled = *mangled;
+           success = demangle_class (work, mangled, declp);
            if (success)
              {
-               remember_type (premangle, *mangled - premangle, work);
+               remember_type (work, oldmangled, *mangled - oldmangled);
+             }
+           if (AUTO_DEMANGLING || GNU_DEMANGLING)
+             {
+               expect_func = 1;
              }
-#endif
-#ifdef GNU_DEMANGLING
-           expect_func = 1;
-#endif
            break;
          
          case 'F':
@@ -488,14 +510,25 @@ demangle_signature (declp, mangled, work)
             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. */
+
            func_done = 1;
            (*mangled)++;
-           success = demangle_args (declp, mangled, work);
+
+           /* For lucid/cfront 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 || CFRONT_DEMANGLING)
+             {
+               forget_types (work);
+             }
+           success = demangle_args (work, mangled, declp);
            break;
          
          case 't':
            /* Template */
-           success = demangle_template (declp, mangled, work);
+           success = demangle_template (work, mangled, declp);
            break;
 
          case '_':
@@ -508,39 +541,44 @@ demangle_signature (declp, mangled, work)
            break;
 
          default:
-#ifdef GNU_DEMANGLING
-           /* Assume we have stumbled onto the first outermost function
-              argument token, and start processing args. */
-           func_done = 1;
-           success = demangle_args (declp, mangled, work);
-#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;
-#endif
+           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;
        }
-#ifdef GNU_DEMANGLING
-      if (success && expect_func)
+      if (AUTO_DEMANGLING || GNU_DEMANGLING)
        {
-         func_done = 1;
-         success = demangle_args (declp, mangled, work);
+         if (success && expect_func)
+           {
+             func_done = 1;
+             success = demangle_args (work, mangled, declp);
+           }
        }
-#endif
     }
   if (success && !func_done)
     {
-#ifdef 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_DEMANGLING, 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 (declp, mangled, work);
-#endif
+      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)
     {
@@ -556,10 +594,10 @@ demangle_signature (declp, mangled, work)
 #if 0
 
 static int
-demangle_method_args (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+demangle_method_args (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int success = 0;
 
@@ -571,7 +609,7 @@ demangle_method_args (declp, mangled, work)
     }
   else
     {
-      success = demangle_args (declp, mangled, work);
+      success = demangle_args (work, mangled, declp);
     }
   return (success);
 }
@@ -579,10 +617,10 @@ demangle_method_args (declp, mangled, work)
 #endif
 
 static int
-demangle_template (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+demangle_template (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int i;
   string tname;
@@ -626,7 +664,7 @@ demangle_template (declp, mangled, work)
       if (**mangled == 'Z')
        {
          (*mangled)++;
-         success = do_type (mangled, &temp, work);
+         success = do_type (work, mangled, &temp);
          string_appendn (&temp, "", 1);
          if (success)
            {
@@ -646,7 +684,7 @@ demangle_template (declp, mangled, work)
          is_real = 0;
          is_integral = 0;
          done = 0;
-         success = do_type (mangled, &temp, work);
+         success = do_type (work, mangled, &temp);
          string_appendn (&temp, "", 1);
          if (success)
            {
@@ -785,7 +823,7 @@ demangle_template (declp, mangled, work)
        }
       else
        {
-         success = demangle_args (declp, mangled, work);
+         success = demangle_args (work, mangled, declp);
        }
     }
   return (success);
@@ -800,8 +838,8 @@ LOCAL FUNCTION
 SYNOPSIS
 
        static int
-       demangle_class (string *declp, const char **mangled,
-                       struct work_stuff *work)
+       demangle_class (struct work_stuff *work, const char **mangled,
+                       strint *declp)
 
 DESCRIPTION
 
@@ -827,10 +865,10 @@ DESCRIPTION
 */
 
 static int
-demangle_class (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+demangle_class (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int n;
   int success = 0;
@@ -864,8 +902,8 @@ LOCAL FUNCTION
 SYNOPSIS
 
        static int
-       demangle_prefix (string *declp, const char **mangled,
-                        struct work_stuff *work)
+       demangle_prefix (struct work_stuff *work, const char **mangled,
+                        string *declp);
 
 DESCRIPTION
 
@@ -887,17 +925,31 @@ DESCRIPTION
  */
 
 static int
-demangle_prefix (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+demangle_prefix (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int success = 1;
   const char *scan;
+  int i;
+
+  scan = strstr (*mangled, "__");
 
-  if ((scan = strstr (*mangled, "__")) == NULL)
+  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 = gnu_special (declp, mangled, work);
+      success = 0;
     }
   else if (work -> static_type)
     {
@@ -917,19 +969,23 @@ demangle_prefix (declp, mangled, work)
       /* Mangled name starts with "__".  Skip over any leading '_' characters,
         then find the next "__" that separates the prefix from the signature.
         */
-      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
+      if (!(CFRONT_DEMANGLING || LUCID_DEMANGLING)
+         || (cfront_special (work, mangled, declp) == 0))
        {
-         demangle_function_name (declp, mangled, work, scan);
+         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
+           {
+             demangle_function_name (work, mangled, declp, scan);
+           }
        }
     }
   else if (*(scan + 2) != '\0')
@@ -937,7 +993,7 @@ demangle_prefix (declp, mangled, work)
       /* Mangled name does not start with "__" but does have one somewhere
         in there with non empty stuff after it.  Looks like a global
         function name. */
-      demangle_function_name (declp, mangled, work, scan);
+      demangle_function_name (work, mangled, declp, scan);
     }
   else
     {
@@ -956,8 +1012,8 @@ LOCAL FUNCTION
 SYNOPSIS
 
        static int
-       gnu_special (string *declp, const char **mangled,
-                    struct work_stuff *work)
+       gnu_special (struct work_stuff *work, const char **mangled,
+                    string *declp);
 
 
 DESCRIPTION
@@ -966,22 +1022,23 @@ DESCRIPTION
        the normal pattern.  For example:
 
                _$_3foo         (destructor for class foo)
-               _vt$foo         (virtual table)
+               _vt$foo         (foo virtual table)
+               _vt$foo$bar     (foo::bar virtual table)
                _3foo$varname   (static data member)
  */
 
 static int
-gnu_special (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+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] == '_'
-      && (*mangled)[1] == CPLUS_MARKER
+      && strchr (cplus_markers, (*mangled)[1]) != NULL
       && (*mangled)[2] == '_')
     {
       /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
@@ -991,21 +1048,29 @@ gnu_special (declp, mangled, work)
   else if ((*mangled)[0] == '_'
           && (*mangled)[1] == 'v'
           && (*mangled)[2] == 't'
-          && (*mangled)[3] == CPLUS_MARKER)
+          && 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. */
       (*mangled) += 4;
-      n = strlen (*mangled);
-      string_appendn (declp, *mangled, n);
+      while (**mangled != '\0')
+       {
+         n = strcspn (*mangled, cplus_markers);
+         string_appendn (declp, *mangled, n);
+         (*mangled) += n;
+         if (**mangled != '\0')
+           {
+             string_append (declp, "::");
+             (*mangled)++;
+           }
+       }
       string_append (declp, " virtual table");
-      (*mangled) += n;
     }
   else if ((*mangled)[0] == '_'
           && isdigit ((*mangled)[1])
-          && (p = strchr (*mangled, CPLUS_MARKER)) != NULL)
+          && (p = strpbrk (*mangled, cplus_markers)) != NULL)
     {
       /* static data member, "_3foo$varname" for example */
       (*mangled)++;
@@ -1024,47 +1089,158 @@ gnu_special (declp, mangled, work)
   return (success);
 }
 
-/* Do a qualified name, such as "Q25Outer5Inner" for "Outer::Inner" */
+/*
+
+LOCAL FUNCTION
+
+       cfront_special -- special handling of cfront/lucid mangled strings
+
+SYNOPSIS
+
+       static int
+       cfront_special (struct work_stuff *work, const char **mangled,
+                       string *declp);
+
+
+DESCRIPTION
+
+       Process some special cfront 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
-demangle_qualified (declp, mangled, work)
-     string *declp;
-     const char **mangled;
+cfront_special (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   int n;
-  string class;
-  string tmp;
+  int i;
+  int success = 1;
+  const char *p;
+
+  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
+    {
+      /* Found a cfront 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. */
+      (*mangled) += ARM_VTABLE_STRLEN;
+      while (**mangled != '\0')
+       {
+         n = consume_count (mangled);
+         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);
+
+DESCRIPTION
+
+       Demangle a qualified name, such as "Q25Outer5Inner" which is
+       the mangled form of "Outer::Inner".  The demangled output is
+       appended to the result string.
+
+       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)
+     struct work_stuff *work;
+     const char **mangled;
+     string *result;
+     int isfuncname;
+{
+  int qualifiers;
+  int namelength;
   int success = 0;
 
-  n = (*mangled)[1] - '0';
-  if (n >= 0 && n <= 9)
+  qualifiers = (*mangled)[1] - '0';
+  if (qualifiers > 0 && qualifiers < 10)
     {
+      /* Assume success until we discover otherwise.  Skip over the 'Q', the
+        qualifier count, and any '_' between the qualifier count and the
+        first name (cfront qualified names). */
+
+      success = 1;
       if ((*mangled)[2] == '_')
        {
-         /* cfront style */
          (*mangled)++;
        }
       (*mangled) += 2;
-      string_init (&class);
-      while (n-- > 0)
+
+
+      /* Pick off the names and append them to the result string as they
+        are found, separated by '::'. */
+
+      while (qualifiers-- > 0)
        {
-         success = do_type (mangled, &tmp, work);
-         string_appends (&class, &tmp);
-         string_append (&class, "::");
-         if (n == 0 && (work -> constructor || work -> destructor))
+         namelength = consume_count (mangled);
+         if (strlen (*mangled) < namelength)
            {
-             if (work -> destructor)
-               {
-                 string_append (&class, "~");
-               }
-             string_appends (&class, &tmp);
+             /* Simple sanity check failed */
+             success = 0;
+             break;
+           }
+         string_appendn (result, *mangled, namelength);
+         if (qualifiers > 0)
+           {
+             string_appendn (result, "::", 2);
            }
-         string_delete (&tmp);
+         *mangled += namelength;
+       }
+
+      /* 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 && (work -> constructor || work -> destructor))
+       {
+         string_appendn (result, "::", 2);
+         if (work -> destructor)
+           {
+             string_append (result, "~");
+           }
+         string_appendn (result, (*mangled) - namelength, namelength);
        }
-      work -> constructor = work -> destructor = 0;
-      string_prependn (declp, class.b, class.p - class.b);
-      string_delete (&class);
     }
   return (success);
 }
@@ -1125,10 +1301,10 @@ get_count (type, count)
 /* result will be initialised here; it will be freed on failure */
 
 static int
-do_type (type, result, work)
-     const char **type;
-     string *result;
+do_type (work, mangled, result)
      struct work_stuff *work;
+     const char **mangled;
+     string *result;
 {
   int n;
   int done;
@@ -1146,56 +1322,38 @@ do_type (type, result, work)
   while (success && !done)
     {
       int member;
-      switch (**type)
+      switch (**mangled)
        {
-       /* A qualified name, such as "Outer::Inner".  Note qualifier count
-          is limited to a single digit (0-9 qualifiers). */
-       case 'Q':
-         n = (*type)[1] - '0';
-         if (n < 0 || n > 9)
-           {
-             success = 0;
-           }
-         if ((*type)[2] == '_') /* cfront style */
-           {
-             (*type)++;
-           }
-         *type += 2;
-         while (n-- > 0)
-           {
-             do_type (type, result, work);
-           }
-         break;
 
        /* A pointer type */
        case 'P':
-         (*type)++;
+         (*mangled)++;
          string_prepend (&decl, "*");
          break;
 
        /* A reference type */
        case 'R':
-         (*type)++;
+         (*mangled)++;
          string_prepend (&decl, "&");
          break;
 
        /* A back reference to a previously seen type */
        case 'T':
-         (*type)++;
-         if (!get_count (type, &n) || n >= work -> ntypes)
+         (*mangled)++;
+         if (!get_count (mangled, &n) || n >= work -> ntypes)
            {
              success = 0;
            }
          else
            {
              remembered_type = work -> typevec[n];
-             type = &remembered_type;
+             mangled = &remembered_type;
            }
          break;
 
        /* A function */
        case 'F':
-         (*type)++;
+         (*mangled)++;
          if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
            {
              string_prepend (&decl, "(");
@@ -1204,14 +1362,14 @@ do_type (type, result, work)
          /* 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_args (&decl, type, work)
-             || (**type != '_' && **type != '\0'))
+         if (!demangle_args (work, mangled, &decl)
+             || (**mangled != '_' && **mangled != '\0'))
            {
              success = 0;
            }
-         if (success && (**type == '_'))
+         if (success && (**mangled == '_'))
            {
-             (*type)++;
+             (*mangled)++;
            }
          break;
 
@@ -1221,49 +1379,49 @@ do_type (type, result, work)
            constp = 0;
            volatilep = 0;
 
-           member = **type == 'M';
-           (*type)++;
-           if (!isdigit (**type))
+           member = **mangled == 'M';
+           (*mangled)++;
+           if (!isdigit (**mangled))
              {
                success = 0;
                break;
              }
-           n = consume_count (type);
-           if (strlen (*type) < n)
+           n = consume_count (mangled);
+           if (strlen (*mangled) < n)
              {
                success = 0;
                break;
              }
            string_append (&decl, ")");
            string_prepend (&decl, "::");
-           string_prependn (&decl, *type, n);
+           string_prependn (&decl, *mangled, n);
            string_prepend (&decl, "(");
-           *type += n;
+           *mangled += n;
            if (member)
              {
-               if (**type == 'C')
+               if (**mangled == 'C')
                  {
-                   (*type)++;
+                   (*mangled)++;
                    constp = 1;
                  }
-               if (**type == 'V')
+               if (**mangled == 'V')
                  {
-                   (*type)++;
+                   (*mangled)++;
                    volatilep = 1;
                  }
-               if (*(*type)++ != 'F')
+               if (*(*mangled)++ != 'F')
                  {
                    success = 0;
                    break;
                  }
              }
-           if ((member && !demangle_args (&decl, type, work))
-               || **type != '_')
+           if ((member && !demangle_args (work, mangled, &decl))
+               || **mangled != '_')
              {
                success = 0;
                break;
              }
-           (*type)++;
+           (*mangled)++;
            if (! PRINT_ANSI_QUALIFIERS)
              {
                break;
@@ -1282,9 +1440,9 @@ do_type (type, result, work)
          }
 
        case 'C':
-         if ((*type)[1] == 'P')
+         if ((*mangled)[1] == 'P')
            {
-             (*type)++;
+             (*mangled)++;
              if (PRINT_ANSI_QUALIFIERS)
                {
                  if (!STRING_EMPTY (&decl))
@@ -1303,7 +1461,17 @@ do_type (type, result, work)
        }
     }
 
-  success = demangle_fund_type (type, result, work);
+  switch (**mangled)
+    {
+      /* A qualified name, such as "Outer::Inner". */
+      case 'Q':
+        success = demangle_qualified (work, mangled, result, 0);
+       break;
+
+      default:
+       success = demangle_fund_type (work, mangled, result);
+       break;
+    }
 
   if (success)
     {
@@ -1335,10 +1503,10 @@ do_type (type, result, work)
    */
 
 static int
-demangle_fund_type (type, result, work)
-     const char **type;
-     string *result;
+demangle_fund_type (work, mangled, result)
      struct work_stuff *work;
+     const char **mangled;
+     string *result;
 {
   int done = 0;
   int success = 1;
@@ -1348,10 +1516,10 @@ demangle_fund_type (type, result, work)
 
   while (!done)
     {
-      switch (**type)
+      switch (**mangled)
        {
          case 'C':
-           (*type)++;
+           (*mangled)++;
            if (PRINT_ANSI_QUALIFIERS)
              {
                APPEND_BLANK (result);
@@ -1359,17 +1527,17 @@ demangle_fund_type (type, result, work)
              }
            break;
          case 'U':
-           (*type)++;
+           (*mangled)++;
            APPEND_BLANK (result);
            string_append (result, "unsigned");
            break;
          case 'S': /* signed char only */
-           (*type)++;
+           (*mangled)++;
            APPEND_BLANK (result);
            string_append (result, "signed");
            break;
          case 'V':
-           (*type)++;
+           (*mangled)++;
            if (PRINT_ANSI_QUALIFIERS)
              {
                APPEND_BLANK (result);
@@ -1384,59 +1552,59 @@ demangle_fund_type (type, result, work)
 
   /* Now pick off the fundamental type.  There can be only one. */
 
-  switch (**type)
+  switch (**mangled)
     {
       case '\0':
       case '_':
        break;
       case 'v':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "void");
        break;
       case 'x':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "long long");
        break;
       case 'l':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "long");
        break;
       case 'i':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "int");
        break;
       case 's':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "short");
        break;
       case 'c':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "char");
        break;
       case 'r':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "long double");
        break;
       case 'd':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "double");
        break;
       case 'f':
-       (*type)++;
+       (*mangled)++;
        APPEND_BLANK (result);
        string_append (result, "float");
        break;
       case 'G':
-       (*type)++;
-       if (!isdigit (**type))
+       (*mangled)++;
+       if (!isdigit (**mangled))
          {
            success = 0;
            break;
@@ -1453,15 +1621,15 @@ demangle_fund_type (type, result, work)
       case '7':
       case '8':
       case '9':
-       n = consume_count (type);
-       if (strlen (*type) < n)
+       n = consume_count (mangled);
+       if (strlen (*mangled) < n)
          {
            success = 0;
            break;
          }
        APPEND_BLANK (result);
-       string_appendn (result, *type, n);
-       *type += n;
+       string_appendn (result, *mangled, n);
+       *mangled += n;
        break;
       default:
        success = 0;
@@ -1474,29 +1642,29 @@ demangle_fund_type (type, result, work)
 /* `result' will be initialized in do_type; it will be freed on failure */
 
 static int
-do_arg (type, result, work)
-     const char **type;
-     string *result;
+do_arg (work, mangled, result)
      struct work_stuff *work;
+     const char **mangled;
+     string *result;
 {
-  const char *start = *type;
+  const char *start = *mangled;
 
-  if (!do_type (type, result, work))
+  if (!do_type (work, mangled, result))
     {
       return (0);
     }
   else
     {
-      remember_type (start, *type - start, work);
+      remember_type (work, start, *mangled - start);
       return (1);
     }
 }
 
 static void
-remember_type (start, len, work)
+remember_type (work, start, len)
+     struct work_stuff *work;
      const char *start;
      int len;
-     struct work_stuff *work;
 {
   char *tem;
 
@@ -1522,6 +1690,25 @@ remember_type (start, len, work)
   work -> typevec[work -> ntypes++] = tem;
 }
 
+/* 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:
@@ -1530,13 +1717,45 @@ remember_type (start, len, work)
    "complexfunc5__FPFPc_PFl_i" =>      process "PFPc_PFl_i"
 
    DECLP must be already initialised, usually non-empty.  It won't be freed
-   on failure */
+   on failure.
+
+   Note that g++ differs significantly from cfront 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 cfront as well) produces:
+
+     foo__FiR3fooT1T2T1T2
+     __ct__3fooFiR3fooT1T2T1T2
+
+   Note that g++ bases it's type numbers starting at zero and counts all
+   previously seen types, while lucid/cfront bases it's 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/cfront 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 (declp, type, work)
-     string *declp;
-     const char **type;
+demangle_args (work, mangled, declp)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
 {
   string arg;
   int need_comma = 0;
@@ -1548,21 +1767,21 @@ demangle_args (declp, type, work)
   if (PRINT_ARG_TYPES)
     {
       string_append (declp, "(");
-      if (**type == '\0')
+      if (**mangled == '\0')
        {
          string_append (declp, "void");
        }
     }
 
-  while (**type != '_' && **type != '\0' && **type != 'e')
+  while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
     {
-      if ((**type == 'N') || (**type == 'T'))
+      if ((**mangled == 'N') || (**mangled == 'T'))
        {
-         temptype = *(*type)++;
+         temptype = *(*mangled)++;
          
          if (temptype == 'N')
            {
-             if (!get_count (type, &r))
+             if (!get_count (mangled, &r))
                {
                  return (0);
                }
@@ -1571,14 +1790,17 @@ demangle_args (declp, type, work)
            {
              r = 1;
            }
-         if (!get_count (type, &t))
+         if (!get_count (mangled, &t))
            {
              return (0);
            }
-#ifdef ARM_DEMANGLING
-         t--;
-#endif
-         if (t >= work -> ntypes)
+         if (LUCID_DEMANGLING || CFRONT_DEMANGLING)
+           {
+             t--;
+           }
+         /* Validate the type index.  Protect against illegal indices from
+            malformed type strings. */
+         if ((t < 0) || (t >= work -> ntypes))
            {
              return (0);
            }
@@ -1589,7 +1811,7 @@ demangle_args (declp, type, work)
                {
                  string_append (declp, ", ");
                }
-             if (!do_arg (&tem, &arg, work))
+             if (!do_arg (work, &tem, &arg))
                {
                  return (0);
                }
@@ -1607,7 +1829,7 @@ demangle_args (declp, type, work)
            {
              string_append (declp, ", ");
            }
-         if (!do_arg (type, &arg, work))
+         if (!do_arg (work, mangled, &arg))
            {
              return (0);
            }
@@ -1620,9 +1842,9 @@ demangle_args (declp, type, work)
        }
     }
 
-  if (**type == 'e')
+  if (**mangled == 'e')
     {
-      (*type)++;
+      (*mangled)++;
       if (PRINT_ARG_TYPES)
        {
          if (need_comma)
@@ -1641,10 +1863,10 @@ demangle_args (declp, type, work)
 }
 
 static void
-demangle_function_name (declp, mangled, work, scan)
-     string *declp;
-     const char **mangled;
+demangle_function_name (work, mangled, declp, scan)
      struct work_stuff *work;
+     const char **mangled;
+     string *declp;
      const char *scan;
 {
   int i;
@@ -1662,32 +1884,32 @@ demangle_function_name (declp, mangled, work, scan)
 
   (*mangled) = scan + 2;
 
-#ifdef ARM_DEMANGLING
+  if (LUCID_DEMANGLING || CFRONT_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. */
+      /* 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 (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;
+       }
     }
 
-#endif
-
   if (declp->p - declp->b >= 3 
       && declp->b[0] == 'o'
       && declp->b[1] == 'p'
-      && declp->b[2] == CPLUS_MARKER)
+      && strchr (cplus_markers, declp->b[2]) != NULL)
     {
       /* see if it's an assignment expression */
       if (declp->p - declp->b >= 10 /* op$assign_ */
@@ -1727,7 +1949,7 @@ demangle_function_name (declp, mangled, work, scan)
     {
       /* type conversion operator */
       tem = declp->b + 5;
-      if (do_type (&tem, &type, work))
+      if (do_type (work, &tem, &type))
        {
          string_clear (declp);
          string_append (declp, "operator ");
@@ -1740,7 +1962,7 @@ demangle_function_name (declp, mangled, work, scan)
       /* ANSI.  */
       /* type conversion operator.  */
       tem = declp->b + 4;
-      if (do_type (&tem, &type, work))
+      if (do_type (work, &tem, &type))
        {
          string_clear (declp);
          string_append (declp, "operator ");
@@ -1994,20 +2216,56 @@ xrealloc (oldmem, size)
   return (newmem);
 }
 
+#include <stdio.h>
+
+enum demangling_styles current_demangling_style = gnu_demangling;
+
 main (argc, argv)
   int argc;
   char **argv;
 {
   char mangled_name[128];
   char *result;
-  
-  if (argc > 1)
+  int c;
+  extern char *optarg;
+  extern int optind;
+
+  while ((c = getopt (argc, argv, "s:?")) != EOF)
     {
-      argc--;
-      argv++;
-      while (argc-- > 0)
+      switch (c)
        {
-         demangle_it (*argv);
+         case '?':
+           fprintf (stderr, "usage: demangle [-s style] [arg1 [arg2]] ...\n");
+           fprintf (stderr, "style = { gnu, lucid, cfront }\n");
+           fprintf (stderr, "reads args from stdin if none supplied\n");
+           exit (0);
+           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, "cfront") == 0)
+             {
+               current_demangling_style = cfront_demangling;
+             }
+           else
+             {
+               fprintf (stderr, "unknown demangling style `%s'\n", optarg);
+               exit (1);
+             }
+           break;
+       }
+    }
+  if (optind < argc)
+    {
+      for ( ; optind < argc; optind++)
+       {
+         demangle_it (argv[optind]);
        }
     }
   else
@@ -2019,4 +2277,4 @@ main (argc, argv)
     }
 }
 
-#endif
+#endif /* main */
This page took 0.042346 seconds and 4 git commands to generate.