[plain text]
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <demangle.h>
#undef CURRENT_DEMANGLING_STYLE
#define CURRENT_DEMANGLING_STYLE work->options
extern char *xmalloc PARAMS((unsigned));
extern char *xrealloc PARAMS((char *, unsigned));
char *
mystrstr (s1, s2)
char *s1, *s2;
{
register char *p = s1;
register int len = strlen (s2);
for (; (p = strchr (p, *s2)) != 0; p++)
{
if (strncmp (p, s2, len) == 0)
{
return (p);
}
}
return (0);
}
#if !defined (CPLUS_MARKER)
#define CPLUS_MARKER '$'
#endif
enum demangling_styles current_demangling_style = gnu_demangling;
static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
void
set_cplus_marker_for_demangling (ch)
int ch;
{
cplus_markers[0] = ch;
}
struct work_stuff
{
int options;
char **typevec;
int ntypes;
int typevec_size;
int constructor;
int destructor;
int static_type;
int const_type;
};
#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS)
static const struct optable
{
const char *in;
const char *out;
int flags;
} optable[] = {
{"nw", " new", DMGL_ANSI},
{"dl", " delete", DMGL_ANSI},
{"new", " new", 0},
{"delete", " delete", 0},
{"vn", " new []", DMGL_ANSI},
{"vd", " delete []", DMGL_ANSI},
{"as", "=", DMGL_ANSI},
{"ne", "!=", DMGL_ANSI},
{"eq", "==", DMGL_ANSI},
{"ge", ">=", DMGL_ANSI},
{"gt", ">", DMGL_ANSI},
{"le", "<=", DMGL_ANSI},
{"lt", "<", DMGL_ANSI},
{"plus", "+", 0},
{"pl", "+", DMGL_ANSI},
{"apl", "+=", DMGL_ANSI},
{"minus", "-", 0},
{"mi", "-", DMGL_ANSI},
{"ami", "-=", DMGL_ANSI},
{"mult", "*", 0},
{"ml", "*", DMGL_ANSI},
{"amu", "*=", DMGL_ANSI},
{"aml", "*=", DMGL_ANSI},
{"convert", "+", 0},
{"negate", "-", 0},
{"trunc_mod", "%", 0},
{"md", "%", DMGL_ANSI},
{"amd", "%=", DMGL_ANSI},
{"trunc_div", "/", 0},
{"dv", "/", DMGL_ANSI},
{"adv", "/=", DMGL_ANSI},
{"truth_andif", "&&", 0},
{"aa", "&&", DMGL_ANSI},
{"truth_orif", "||", 0},
{"oo", "||", DMGL_ANSI},
{"truth_not", "!", 0},
{"nt", "!", DMGL_ANSI},
{"postincrement","++", 0},
{"pp", "++", DMGL_ANSI},
{"postdecrement","--", 0},
{"mm", "--", DMGL_ANSI},
{"bit_ior", "|", 0},
{"or", "|", DMGL_ANSI},
{"aor", "|=", DMGL_ANSI},
{"bit_xor", "^", 0},
{"er", "^", DMGL_ANSI},
{"aer", "^=", DMGL_ANSI},
{"bit_and", "&", 0},
{"ad", "&", DMGL_ANSI},
{"aad", "&=", DMGL_ANSI},
{"bit_not", "~", 0},
{"co", "~", DMGL_ANSI},
{"call", "()", 0},
{"cl", "()", DMGL_ANSI},
{"alshift", "<<", 0},
{"ls", "<<", DMGL_ANSI},
{"als", "<<=", DMGL_ANSI},
{"arshift", ">>", 0},
{"rs", ">>", DMGL_ANSI},
{"ars", ">>=", DMGL_ANSI},
{"component", "->", 0},
{"pt", "->", DMGL_ANSI},
{"rf", "->", DMGL_ANSI},
{"indirect", "*", 0},
{"method_call", "->()", 0},
{"addr", "&", 0},
{"array", "[]", 0},
{"vc", "[]", DMGL_ANSI},
{"compound", ", ", 0},
{"cm", ", ", DMGL_ANSI},
{"cond", "?:", 0},
{"cn", "?:", DMGL_ANSI},
{"max", ">?", 0},
{"mx", ">?", DMGL_ANSI},
{"min", "<?", 0},
{"mn", "<?", DMGL_ANSI},
{"nop", "", 0},
{"rm", "->*", DMGL_ANSI}
};
typedef struct string
{
char *b;
char *p;
char *e;
} string;
#define STRING_EMPTY(str) ((str) -> b == (str) -> p)
#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
string_prepend(str, " ");}
#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
string_append(str, " ");}
#define ARM_VTABLE_STRING "__vtbl__"
#define ARM_VTABLE_STRLEN 8
static char *
mop_up PARAMS ((struct work_stuff *, string *, int));
#if 0
static int
demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *));
#endif
static int
demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
string *));
static int
demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
int, int));
static int
demangle_class PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_signature PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
static int
gnu_special PARAMS ((struct work_stuff *, const char **, string *));
static int
arm_special PARAMS ((struct work_stuff *, const char **, string *));
static void
string_need PARAMS ((string *, int));
static void
string_delete PARAMS ((string *));
static void
string_init PARAMS ((string *));
static void
string_clear PARAMS ((string *));
#if 0
static int
string_empty PARAMS ((string *));
#endif
static void
string_append PARAMS ((string *, const char *));
static void
string_appends PARAMS ((string *, string *));
static void
string_appendn PARAMS ((string *, const char *, int));
static void
string_prepend PARAMS ((string *, const char *));
static void
string_prependn PARAMS ((string *, const char *, int));
static int
get_count PARAMS ((const char **, int *));
static int
consume_count PARAMS ((const char **));
static int
demangle_args PARAMS ((struct work_stuff *, const char **, string *));
static int
do_type PARAMS ((struct work_stuff *, const char **, string *));
static int
do_arg PARAMS ((struct work_stuff *, const char **, string *));
static void
demangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
const char *));
static void
remember_type PARAMS ((struct work_stuff *, const char *, int));
static void
forget_types PARAMS ((struct work_stuff *));
static void
string_prepends PARAMS ((string *, string *));
static int
consume_count (type)
const char **type;
{
int count = 0;
while (isdigit (**type))
{
count *= 10;
count += **type - '0';
(*type)++;
}
return (count);
}
int
cplus_demangle_opname (opname, result, options)
char *opname;
char *result;
int options;
{
int len, i, len1, ret;
string type;
struct work_stuff work[1];
const char *tem;
len = strlen(opname);
result[0] = '\0';
ret = 0;
work->options = options;
if (opname[0] == '_' && opname[1] == '_'
&& opname[2] == 'o' && opname[3] == 'p')
{
tem = opname + 4;
if (do_type (work, &tem, &type))
{
strcat (result, "operator ");
strncat (result, type.b, type.p - type.b);
string_delete (&type);
ret = 1;
}
}
else if (opname[0] == '_' && opname[1] == '_'
&& opname[2] >= 'a' && opname[2] <= 'z'
&& opname[3] >= 'a' && opname[3] <= 'z')
{
if (opname[4] == '\0')
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 2
&& memcmp (optable[i].in, opname + 2, 2) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
ret = 1;
break;
}
}
}
else
{
if (opname[2] == 'a' && opname[5] == '\0')
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 3
&& memcmp (optable[i].in, opname + 2, 3) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
ret = 1;
break;
}
}
}
}
}
else if (len >= 3
&& opname[0] == 'o'
&& opname[1] == 'p'
&& strchr (cplus_markers, opname[2]) != NULL)
{
if (len >= 10
&& memcmp (opname + 3, "assign_", 7) == 0)
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 10;
if (strlen (optable[i].in) == len1
&& memcmp (optable[i].in, opname + 10, len1) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
strcat (result, "=");
ret = 1;
break;
}
}
}
else
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 3;
if (strlen (optable[i].in) == len1
&& memcmp (optable[i].in, opname + 3, len1) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
ret = 1;
break;
}
}
}
}
else if (len >= 5 && memcmp (opname, "type", 4) == 0
&& strchr (cplus_markers, opname[4]) != NULL)
{
tem = opname + 5;
if (do_type (work, &tem, &type))
{
strcat (result, "operator ");
strncat (result, type.b, type.p - type.b);
string_delete (&type);
ret = 1;
}
}
return ret;
}
char *
cplus_mangle_opname (opname, options)
char *opname;
int options;
{
int i;
int len;
len = strlen (opname);
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].out) == len
&& (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
&& memcmp (optable[i].out, opname, len) == 0)
return ((char *)optable[i].in);
}
return (0);
}
int cplus_match (mangled, text, text_len)
const char *mangled;
char *text;
int text_len;
{
if (strncmp (mangled, text, text_len) != 0) {
return(0);
} else {
return(1);
}
}
char *
cplus_demangle (mangled, options)
const char *mangled;
int options;
{
string decl;
int success = 0;
struct work_stuff work[1];
char *demangled = NULL;
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);
if ((AUTO_DEMANGLING || GNU_DEMANGLING))
{
success = gnu_special (work, &mangled, &decl);
}
if (!success)
{
success = demangle_prefix (work, &mangled, &decl);
}
if (success && (*mangled != '\0'))
{
success = demangle_signature (work, &mangled, &decl);
}
if (work->constructor == 2)
{
string_prepend(&decl, "global constructors keyed to ");
work->constructor = 0;
}
else if (work->destructor == 2)
{
string_prepend(&decl, "global destructors keyed to ");
work->destructor = 0;
}
demangled = mop_up (work, &decl, success);
}
return (demangled);
}
static char *
mop_up (work, declp, success)
struct work_stuff *work;
string *declp;
int success;
{
char *demangled = NULL;
forget_types (work);
if (work -> typevec != NULL)
{
free ((char *) work -> typevec);
}
if (!success)
{
string_delete (declp);
}
else
{
string_appendn (declp, "", 1);
demangled = declp -> b;
}
return (demangled);
}
static int
demangle_signature (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int success = 1;
int func_done = 0;
int expect_func = 0;
const char *oldmangled = NULL;
string trawname;
string tname;
while (success && (**mangled != '\0'))
{
switch (**mangled)
{
case 'Q':
oldmangled = *mangled;
success = demangle_qualified (work, mangled, declp, 1, 0);
if (success)
{
remember_type (work, oldmangled, *mangled - oldmangled);
}
if (AUTO_DEMANGLING || GNU_DEMANGLING)
{
expect_func = 1;
}
oldmangled = NULL;
break;
case 'S':
if (oldmangled == NULL)
{
oldmangled = *mangled;
}
(*mangled)++;
work -> static_type = 1;
break;
case 'C':
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 'F':
oldmangled = NULL;
func_done = 1;
(*mangled)++;
if (LUCID_DEMANGLING || ARM_DEMANGLING)
{
forget_types (work);
}
success = demangle_args (work, mangled, declp);
break;
case 't':
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 '_':
success = 0;
break;
default:
if (AUTO_DEMANGLING || GNU_DEMANGLING)
{
func_done = 1;
success = demangle_args (work, mangled, declp);
}
else
{
success = 0;
}
break;
}
{
if (success && expect_func)
{
func_done = 1;
success = demangle_args (work, mangled, declp);
}
}
}
if (success && !func_done)
{
if (AUTO_DEMANGLING || GNU_DEMANGLING)
{
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 (work, mangled, tname, trawname)
struct work_stuff *work;
const char **mangled;
string *tname;
string *trawname;
{
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;
string temp;
(*mangled)++;
start = *mangled;
if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
{
return (0);
}
if (trawname)
string_appendn (trawname, *mangled, r);
string_appendn (tname, *mangled, r);
*mangled += r;
string_append (tname, "<");
if (!get_count (mangled, &r))
{
return (0);
}
for (i = 0; i < r; i++)
{
if (need_comma)
{
string_append (tname, ", ");
}
if (**mangled == 'Z')
{
(*mangled)++;
success = do_type (work, mangled, &temp);
if (success)
{
string_appends (tname, &temp);
}
string_delete(&temp);
if (!success)
{
break;
}
}
else
{
old_p = *mangled;
is_pointer = 0;
is_real = 0;
is_integral = 0;
is_char = 0;
done = 0;
success = do_type (work, mangled, &temp);
string_delete(&temp);
if (!success)
{
break;
}
while (*old_p && !done)
{
switch (*old_p)
{
case 'P':
case 'p':
case 'R':
done = is_pointer = 1;
break;
case 'C':
case 'S':
case 'U':
case 'V':
case 'F':
case 'M':
case 'O':
old_p++;
continue;
case 'Q':
done = is_integral = 1;
break;
case 'T':
abort ();
break;
case 'v':
abort ();
break;
case 'x':
case 'l':
case 'i':
case 's':
case 'w':
done = is_integral = 1;
break;
case 'b':
done = is_bool = 1;
break;
case 'c':
done = is_char = 1;
break;
case 'r':
case 'd':
case 'f':
done = is_real = 1;
break;
default:
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)
{
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;
}
else if (is_real)
{
if (**mangled == 'm')
{
string_appendn (tname, "-", 1);
(*mangled)++;
}
while (isdigit (**mangled))
{
string_appendn (tname, *mangled, 1);
(*mangled)++;
}
if (**mangled == '.')
{
string_appendn (tname, ".", 1);
(*mangled)++;
while (isdigit (**mangled))
{
string_appendn (tname, *mangled, 1);
(*mangled)++;
}
}
if (**mangled == 'e')
{
string_appendn (tname, "e", 1);
(*mangled)++;
while (isdigit (**mangled))
{
string_appendn (tname, *mangled, 1);
(*mangled)++;
}
}
}
else if (is_pointer)
{
if (!get_count (mangled, &symbol_len))
{
success = 0;
break;
}
string_appendn (tname, *mangled, symbol_len);
*mangled += symbol_len;
}
}
need_comma = 1;
}
if (tname->p[-1] == '>')
string_append (tname, " ");
string_append (tname, ">");
return (success);
}
static int
arm_pt (work, mangled, n, anchor, args)
struct work_stuff *work;
const char *mangled;
int n;
const char **anchor, **args;
{
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;
}
}
return 0;
}
static void
demangle_arm_pt (work, mangled, n, declp)
struct work_stuff *work;
const char **mangled;
int n;
string *declp;
{
const char *p;
const char *args;
const char *e = *mangled + n;
if (arm_pt (work, *mangled, n, &p, &args))
{
string arg;
string_init (&arg);
string_appendn (declp, *mangled, p - *mangled);
string_append (declp, "<");
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);
}
*mangled += n;
}
static int
demangle_class_name (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int n;
int success = 0;
n = consume_count (mangled);
if (strlen (*mangled) >= n)
{
demangle_arm_pt (work, mangled, n, declp);
success = 1;
}
return (success);
}
static int
demangle_class (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int success = 0;
string class_name;
string_init (&class_name);
if (demangle_class_name (work, mangled, &class_name))
{
if ((work->constructor & 1) || (work->destructor & 1))
{
string_prepends (declp, &class_name);
if (work -> destructor & 1)
{
string_prepend (declp, "~");
work -> destructor -= 1;
}
else
{
work -> constructor -= 1;
}
}
string_prepend (declp, "::");
string_prepends (declp, &class_name);
success = 1;
}
string_delete (&class_name);
return (success);
}
static int
demangle_prefix (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int success = 1;
const char *scan;
int i;
if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
{
char *marker = strchr (cplus_markers, (*mangled)[8]);
if (marker != NULL && *marker == (*mangled)[10])
{
if ((*mangled)[9] == 'D')
{
(*mangled) += 11;
work->destructor = 2;
if (gnu_special (work, mangled, declp))
return success;
}
else if ((*mangled)[9] == 'I')
{
(*mangled) += 11;
work->constructor = 2;
if (gnu_special (work, mangled, declp))
return success;
}
}
}
else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0)
{
(*mangled) += 7;
work->destructor = 2;
}
else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0)
{
(*mangled) += 7;
work->constructor = 2;
}
{
scan = *mangled;
do {
scan = strchr (scan, '_');
} while (scan != NULL && *++scan != '_');
if (scan != NULL) --scan;
}
if (scan != NULL)
{
i = strspn (scan, "_");
if (i > 2)
{
scan += (i - 2);
}
}
if (scan == NULL)
{
success = 0;
}
else if (work -> static_type)
{
if (!isdigit (scan[0]) && (scan[0] != 't'))
{
success = 0;
}
}
else if ((scan == *mangled) &&
(isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
{
if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2]))
{
*mangled = scan + 2;
consume_count (mangled);
string_append (declp, *mangled);
*mangled += strlen (*mangled);
success = 1;
}
else
{
if (!(LUCID_DEMANGLING || ARM_DEMANGLING))
work -> constructor += 1;
*mangled = scan + 2;
}
}
else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't'))
{
if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
|| (arm_special (work, mangled, declp) == 0))
{
while (*scan == '_')
{
scan++;
}
if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
{
success = 0;
}
else
{
demangle_function_name (work, mangled, declp, scan);
}
}
}
else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
{
success = 1;
demangle_arm_pt (work, mangled, strlen (*mangled), declp);
}
else if (*(scan + 2) != '\0')
{
demangle_function_name (work, mangled, declp, scan);
}
else
{
success = 0;
}
if (!success && (work->constructor == 2 || work->destructor == 2))
{
string_append (declp, *mangled);
*mangled += strlen (*mangled);
success = 1;
}
return (success);
}
static int
gnu_special (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int n;
int success = 1;
const char *p;
if ((*mangled)[0] == '_'
&& strchr (cplus_markers, (*mangled)[1]) != NULL
&& (*mangled)[2] == '_')
{
(*mangled) += 3;
work -> destructor += 1;
}
else if ((*mangled)[0] == '_'
&& (((*mangled)[1] == '_'
&& (*mangled)[2] == 'v'
&& (*mangled)[3] == 't'
&& (*mangled)[4] == '_')
|| ((*mangled)[1] == 'v'
&& (*mangled)[2] == 't'
&& strchr (cplus_markers, (*mangled)[3]) != NULL)))
{
if ((*mangled)[2] == 'v')
(*mangled) += 5;
else
(*mangled) += 4;
while (**mangled != '\0')
{
p = strpbrk (*mangled, cplus_markers);
switch (**mangled)
{
case 'Q':
success = demangle_qualified (work, mangled, declp, 0, 1);
break;
case 't':
success = demangle_template (work, mangled, declp, 0);
break;
default:
if (isdigit(*mangled[0]))
{
n = consume_count(mangled);
}
else
{
n = strcspn (*mangled, cplus_markers);
}
string_appendn (declp, *mangled, n);
(*mangled) += n;
}
if (success && ((p == NULL) || (p == *mangled)))
{
if (p != NULL)
{
string_append (declp, "::");
(*mangled)++;
}
}
else
{
success = 0;
break;
}
}
if (success)
string_append (declp, " virtual table");
}
else if ((*mangled)[0] == '_'
&& (strchr("0123456789Qt", (*mangled)[1]) != NULL)
&& (p = strpbrk (*mangled, cplus_markers)) != NULL)
{
(*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;
}
if (success && (p == *mangled))
{
(*mangled)++;
string_append (declp, "::");
n = strlen (*mangled);
string_appendn (declp, *mangled, n);
(*mangled) += n;
}
else
{
success = 0;
}
}
else if (strncmp (*mangled, "__thunk_", 8) == 0)
{
int delta = ((*mangled) += 8, consume_count (mangled));
char *method = cplus_demangle (++*mangled, work->options);
if (method)
{
char buf[50];
sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
string_append (declp, buf);
string_append (declp, method);
free (method);
n = strlen (*mangled);
(*mangled) += n;
}
else
{
success = 0;
}
}
else
{
success = 0;
}
return (success);
}
static int
arm_special (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int n;
int success = 1;
const char *scan;
if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
{
scan = *mangled + ARM_VTABLE_STRLEN;
while (*scan != '\0')
{
n = consume_count (&scan);
if (n==0)
{
return (0);
}
scan += n;
if (scan[0] == '_' && scan[1] == '_')
{
scan += 2;
}
}
(*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);
}
static int
demangle_qualified (work, mangled, result, isfuncname, append)
struct work_stuff *work;
const char **mangled;
string *result;
int isfuncname;
int append;
{
int qualifiers;
int namelength;
int success = 1;
const char *p;
char num[2];
string temp;
string_init (&temp);
switch ((*mangled)[1])
{
case '_':
p = *mangled + 2;
qualifiers = atoi (p);
if (!isdigit (*p) || *p == '0')
success = 0;
while (isdigit (*p))
++p;
if (*p != '_')
success = 0;
*mangled = p + 1;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
num[0] = (*mangled)[1];
num[1] = '\0';
qualifiers = atoi (num);
if ((*mangled)[2] == '_')
{
(*mangled)++;
}
(*mangled) += 2;
break;
case '0':
default:
success = 0;
}
if (!success)
return success;
while (qualifiers-- > 0)
{
if (*mangled[0] == '_')
*mangled = *mangled + 1;
if (*mangled[0] == 't')
{
success = demangle_template(work, mangled, &temp, 0);
if (!success) break;
}
else
{
namelength = consume_count (mangled);
if (strlen (*mangled) < namelength)
{
success = 0;
break;
}
string_appendn (&temp, *mangled, namelength);
*mangled += namelength;
}
if (qualifiers > 0)
{
string_appendn (&temp, "::", 2);
}
}
if (isfuncname && (work->constructor & 1 || work->destructor & 1))
{
string_appendn (&temp, "::", 2);
if (work -> destructor & 1)
{
string_append (&temp, "~");
}
string_appendn (&temp, (*mangled) - namelength, namelength);
}
if (append)
{
string_appends (result, &temp);
}
else
{
if (!STRING_EMPTY (result))
{
string_appendn (&temp, "::", 2);
}
string_prepends (result, &temp);
}
string_delete (&temp);
return (success);
}
static int
get_count (type, count)
const char **type;
int *count;
{
const char *p;
int n;
if (!isdigit (**type))
{
return (0);
}
else
{
*count = **type - '0';
(*type)++;
if (isdigit (**type))
{
p = *type;
n = *count;
do
{
n *= 10;
n += *p - '0';
p++;
}
while (isdigit (*p));
if (*p == '_')
{
*type = p + 1;
*count = n;
}
}
}
return (1);
}
static int
do_type (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int n;
int done;
int success;
string decl;
const char *remembered_type;
int constp;
int volatilep;
string_init (&decl);
string_init (result);
done = 0;
success = 1;
while (success && !done)
{
int member;
switch (**mangled)
{
case 'P':
case 'p':
(*mangled)++;
string_prepend (&decl, "*");
break;
case 'R':
(*mangled)++;
string_prepend (&decl, "&");
break;
case 'A':
{
const char *p = ++(*mangled);
string_prepend (&decl, "(");
string_append (&decl, ")[");
while (**mangled && **mangled != '_')
++(*mangled);
if (**mangled == '_')
{
string_appendn (&decl, p, *mangled - p);
string_append (&decl, "]");
*mangled += 1;
}
else
success = 0;
break;
}
case 'T':
(*mangled)++;
if (!get_count (mangled, &n) || n >= work -> ntypes)
{
success = 0;
}
else
{
remembered_type = work -> typevec[n];
mangled = &remembered_type;
}
break;
case 'F':
(*mangled)++;
if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
{
string_prepend (&decl, "(");
string_append (&decl, ")");
}
if (!demangle_args (work, mangled, &decl)
|| (**mangled != '_' && **mangled != '\0'))
{
success = 0;
}
if (success && (**mangled == '_'))
{
(*mangled)++;
}
break;
case 'M':
case 'O':
{
constp = 0;
volatilep = 0;
member = **mangled == 'M';
(*mangled)++;
if (!isdigit (**mangled))
{
success = 0;
break;
}
n = consume_count (mangled);
if (strlen (*mangled) < n)
{
success = 0;
break;
}
string_append (&decl, ")");
string_prepend (&decl, "::");
string_prependn (&decl, *mangled, n);
string_prepend (&decl, "(");
*mangled += n;
if (member)
{
if (**mangled == 'C')
{
(*mangled)++;
constp = 1;
}
if (**mangled == 'V')
{
(*mangled)++;
volatilep = 1;
}
if (*(*mangled)++ != 'F')
{
success = 0;
break;
}
}
if ((member && !demangle_args (work, mangled, &decl))
|| **mangled != '_')
{
success = 0;
break;
}
(*mangled)++;
if (! PRINT_ANSI_QUALIFIERS)
{
break;
}
if (constp)
{
APPEND_BLANK (&decl);
string_append (&decl, "const");
}
if (volatilep)
{
APPEND_BLANK (&decl);
string_append (&decl, "volatile");
}
break;
}
case 'G':
(*mangled)++;
break;
case 'C':
(*mangled)++;
if (PRINT_ANSI_QUALIFIERS)
{
if (!STRING_EMPTY (&decl))
{
string_prepend (&decl, " ");
}
string_prepend (&decl, "const");
}
break;
default:
done = 1;
break;
}
}
switch (**mangled)
{
case 'Q':
success = demangle_qualified (work, mangled, result, 0, 1);
break;
default:
success = demangle_fund_type (work, mangled, result);
break;
}
if (success)
{
if (!STRING_EMPTY (&decl))
{
string_append (result, " ");
string_appends (result, &decl);
}
}
else
{
string_delete (result);
}
string_delete (&decl);
return (success);
}
static int
demangle_fund_type (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int done = 0;
int success = 1;
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':
(*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;
}
}
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;
}
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;
success = 0;
}
break;
case 't':
success = demangle_template(work,mangled, result, 0);
break;
default:
success = 0;
break;
}
return (success);
}
static int
do_arg (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
const char *start = *mangled;
if (!do_type (work, mangled, result))
{
return (0);
}
else
{
remember_type (work, start, *mangled - start);
return (1);
}
}
static void
remember_type (work, start, len)
struct work_stuff *work;
const char *start;
int len;
{
char *tem;
if (work -> ntypes >= work -> typevec_size)
{
if (work -> typevec_size == 0)
{
work -> typevec_size = 3;
work -> typevec =
(char **) xmalloc (sizeof (char *) * work -> typevec_size);
}
else
{
work -> typevec_size *= 2;
work -> typevec =
(char **) xrealloc ((char *)work -> typevec,
sizeof (char *) * work -> typevec_size);
}
}
tem = xmalloc (len + 1);
memcpy (tem, start, len);
tem[len] = '\0';
work -> typevec[work -> ntypes++] = tem;
}
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;
}
}
}
static int
demangle_args (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
string arg;
int need_comma = 0;
int r;
int t;
const char *tem;
char temptype;
if (PRINT_ARG_TYPES)
{
string_append (declp, "(");
if (**mangled == '\0')
{
string_append (declp, "void");
}
}
while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
{
if ((**mangled == 'N') || (**mangled == 'T'))
{
temptype = *(*mangled)++;
if (temptype == 'N')
{
if (!get_count (mangled, &r))
{
return (0);
}
}
else
{
r = 1;
}
if (ARM_DEMANGLING && work -> ntypes >= 10)
{
if ((t = consume_count(mangled)) == 0)
{
return (0);
}
}
else
{
if (!get_count (mangled, &t))
{
return (0);
}
}
if (LUCID_DEMANGLING || ARM_DEMANGLING)
{
t--;
}
if ((t < 0) || (t >= work -> ntypes))
{
return (0);
}
while (--r >= 0)
{
tem = work -> typevec[t];
if (need_comma && PRINT_ARG_TYPES)
{
string_append (declp, ", ");
}
if (!do_arg (work, &tem, &arg))
{
return (0);
}
if (PRINT_ARG_TYPES)
{
string_appends (declp, &arg);
}
string_delete (&arg);
need_comma = 1;
}
}
else
{
if (need_comma & PRINT_ARG_TYPES)
{
string_append (declp, ", ");
}
if (!do_arg (work, mangled, &arg))
{
return (0);
}
if (PRINT_ARG_TYPES)
{
string_appends (declp, &arg);
}
string_delete (&arg);
need_comma = 1;
}
}
if (**mangled == 'e')
{
(*mangled)++;
if (PRINT_ARG_TYPES)
{
if (need_comma)
{
string_append (declp, ",");
}
string_append (declp, "...");
}
}
if (PRINT_ARG_TYPES)
{
string_append (declp, ")");
}
return (1);
}
static void
demangle_function_name (work, mangled, declp, scan)
struct work_stuff *work;
const char **mangled;
string *declp;
const char *scan;
{
int i;
int len;
string type;
const char *tem;
string_appendn (declp, (*mangled), scan - (*mangled));
string_need (declp, 1);
*(declp -> p) = '\0';
(*mangled) = scan + 2;
if (LUCID_DEMANGLING || ARM_DEMANGLING)
{
if (strcmp (declp -> b, "__ct") == 0)
{
work -> constructor += 1;
string_clear (declp);
return;
}
else if (strcmp (declp -> b, "__dt") == 0)
{
work -> destructor += 1;
string_clear (declp);
return;
}
}
if (declp->p - declp->b >= 3
&& declp->b[0] == 'o'
&& declp->b[1] == 'p'
&& strchr (cplus_markers, declp->b[2]) != NULL)
{
if (declp->p - declp->b >= 10
&& memcmp (declp->b + 3, "assign_", 7) == 0)
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len = declp->p - declp->b - 10;
if (strlen (optable[i].in) == len
&& memcmp (optable[i].in, declp->b + 10, len) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
string_append (declp, "=");
break;
}
}
}
else
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
int len = declp->p - declp->b - 3;
if (strlen (optable[i].in) == len
&& memcmp (optable[i].in, declp->b + 3, len) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
break;
}
}
}
}
else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
&& strchr (cplus_markers, declp->b[4]) != NULL)
{
tem = declp->b + 5;
if (do_type (work, &tem, &type))
{
string_clear (declp);
string_append (declp, "operator ");
string_appends (declp, &type);
string_delete (&type);
}
}
else if (declp->b[0] == '_' && declp->b[1] == '_'
&& declp->b[2] == 'o' && declp->b[3] == 'p')
{
tem = declp->b + 4;
if (do_type (work, &tem, &type))
{
string_clear (declp);
string_append (declp, "operator ");
string_appends (declp, &type);
string_delete (&type);
}
}
else if (declp->b[0] == '_' && declp->b[1] == '_'
&& declp->b[2] >= 'a' && declp->b[2] <= 'z'
&& declp->b[3] >= 'a' && declp->b[3] <= 'z')
{
if (declp->b[4] == '\0')
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 2
&& memcmp (optable[i].in, declp->b + 2, 2) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
break;
}
}
}
else
{
if (declp->b[2] == 'a' && declp->b[5] == '\0')
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 3
&& memcmp (optable[i].in, declp->b + 2, 3) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
break;
}
}
}
}
}
}
static void
string_need (s, n)
string *s;
int n;
{
int tem;
if (s->b == NULL)
{
if (n < 32)
{
n = 32;
}
s->p = s->b = xmalloc (n);
s->e = s->b + n;
}
else if (s->e - s->p < n)
{
tem = s->p - s->b;
n += tem;
n *= 2;
s->b = xrealloc (s->b, n);
s->p = s->b + tem;
s->e = s->b + n;
}
}
static void
string_delete (s)
string *s;
{
if (s->b != NULL)
{
free (s->b);
s->b = s->e = s->p = NULL;
}
}
static void
string_init (s)
string *s;
{
s->b = s->p = s->e = NULL;
}
static void
string_clear (s)
string *s;
{
s->p = s->b;
}
#if 0
static int
string_empty (s)
string *s;
{
return (s->b == s->p);
}
#endif
static void
string_append (p, s)
string *p;
const char *s;
{
int n;
if (s == NULL || *s == '\0')
return;
n = strlen (s);
string_need (p, n);
memcpy (p->p, s, n);
p->p += n;
}
static void
string_appends (p, s)
string *p, *s;
{
int n;
if (s->b != s->p)
{
n = s->p - s->b;
string_need (p, n);
memcpy (p->p, s->b, n);
p->p += n;
}
}
static void
string_appendn (p, s, n)
string *p;
const char *s;
int n;
{
if (n != 0)
{
string_need (p, n);
memcpy (p->p, s, n);
p->p += n;
}
}
static void
string_prepend (p, s)
string *p;
const char *s;
{
if (s != NULL && *s != '\0')
{
string_prependn (p, s, strlen (s));
}
}
static void
string_prepends (p, s)
string *p, *s;
{
if (s->b != s->p)
{
string_prependn (p, s->b, s->p - s->b);
}
}
static void
string_prependn (p, s, n)
string *p;
const char *s;
int n;
{
char *q;
if (n != 0)
{
string_need (p, n);
for (q = p->p - 1; q >= p->b; q--)
{
q[n] = q[0];
}
memcpy (p->b, s, n);
p->p += n;
}
}
#ifdef MAIN
static void
demangle_it (mangled_name)
char *mangled_name;
{
char *result;
result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
if (result == NULL)
{
printf ("%s\n", mangled_name);
}
else
{
printf ("%s\n", result);
free (result);
}
}
#include "getopt.h"
static char *program_name;
static char *program_version = VERSION;
static void
usage (stream, status)
FILE *stream;
int 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",
program_name);
exit (status);
}
#define MBUF_SIZE 512
char mbuffer[MBUF_SIZE];
extern int prepends_underscore;
int strip_underscore = 0;
static struct option long_options[] = {
{"strip-underscores", no_argument, 0, '_'},
{"format", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{"no-strip-underscores", no_argument, 0, 'n'},
{"version", no_argument, 0, 'v'},
{0, no_argument, 0, 0}
};
int
main (argc, argv)
int argc;
char **argv;
{
char *result;
int c;
program_name = argv[0];
strip_underscore = prepends_underscore;
while ((c = getopt_long (argc, argv, "_ns:", 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;
}
}
if (optind < argc)
{
for ( ; optind < argc; optind++)
{
demangle_it (argv[optind]);
}
}
else
{
for (;;)
{
int i = 0;
c = getchar ();
while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
{
if (i >= MBUF_SIZE-1)
break;
mbuffer[i++] = c;
c = getchar ();
}
if (i > 0)
{
int skip_first = 0;
if (mbuffer[0] == '.')
++skip_first;
if (strip_underscore && mbuffer[skip_first] == '_')
++skip_first;
if (skip_first > i)
skip_first = i;
mbuffer[i] = 0;
result = cplus_demangle (mbuffer + skip_first,
DMGL_PARAMS | DMGL_ANSI);
if (result)
{
if (mbuffer[0] == '.')
putc ('.', stdout);
fputs (result, stdout);
free (result);
}
else
fputs (mbuffer, stdout);
fflush (stdout);
}
if (c == EOF)
break;
putchar (c);
}
}
exit (0);
}
static void
fatal (str)
char *str;
{
fprintf (stderr, "%s: %s\n", program_name, str);
exit (1);
}
char * malloc ();
char * realloc ();
char *
xmalloc (size)
unsigned size;
{
register char *value = (char *) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
char *
xrealloc (ptr, size)
char *ptr;
unsigned size;
{
register char *value = (char *) realloc (ptr, size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
#endif
Generated by GNU enscript 1.6.4.