#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
char * malloc ();
char * realloc ();
#endif
#include <demangle.h>
#undef CURRENT_DEMANGLING_STYLE
#define CURRENT_DEMANGLING_STYLE work->options
#include "libiberty.h"
#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
static const char *mystrstr PARAMS ((const char *, const char *));
static const char *
mystrstr (s1, s2)
const char *s1, *s2;
{
register const 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' };
static char char_str[2] = { '\000', '\000' };
void
set_cplus_marker_for_demangling (ch)
int ch;
{
cplus_markers[0] = ch;
}
typedef struct string
{
char *b;
char *p;
char *e;
} string;
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;
int temp_start;
int type_quals;
int dllimported;
char **tmpl_argvec;
int ntmpl_args;
int forgetting_types;
string* previous_argument;
int nrepeats;
};
#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},
{"sz", "sizeof ", DMGL_ANSI}
};
typedef enum type_kind_t
{
tk_none,
tk_pointer,
tk_reference,
tk_integral,
tk_bool,
tk_char,
tk_real
} type_kind_t;
#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 LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
#define ARM_VTABLE_STRING "__vtbl__"
#define ARM_VTABLE_STRLEN 8
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 *, const char **, string *));
#endif
static char *
internal_cplus_demangle PARAMS ((struct work_stuff *, const char *));
static int
demangle_template_template_parm PARAMS ((struct work_stuff *work,
const char **, string *));
static int
demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
string *, int, int));
static int
arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
const char **));
static int
demangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
int, int));
static int
demangle_class PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_signature PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
static int
gnu_special PARAMS ((struct work_stuff *, const char **, string *));
static int
arm_special PARAMS ((const char **, string *));
static void
string_need PARAMS ((string *, int));
static void
string_delete PARAMS ((string *));
static void
string_init PARAMS ((string *));
static void
string_clear PARAMS ((string *));
#if 0
static int
string_empty PARAMS ((string *));
#endif
static void
string_append PARAMS ((string *, const char *));
static void
string_appends PARAMS ((string *, string *));
static void
string_appendn PARAMS ((string *, const char *, int));
static void
string_prepend PARAMS ((string *, const char *));
static void
string_prependn PARAMS ((string *, const char *, int));
static int
get_count PARAMS ((const char **, int *));
static int
consume_count PARAMS ((const char **));
static int
consume_count_with_underscores PARAMS ((const char**));
static int
demangle_args PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
static int
do_type PARAMS ((struct work_stuff *, const char **, string *));
static int
do_arg PARAMS ((struct work_stuff *, const char **, string *));
static void
demangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
const char *));
static void
remember_type PARAMS ((struct work_stuff *, const char *, int));
static void
remember_Btype PARAMS ((struct work_stuff *, const char *, int, int));
static int
register_Btype PARAMS ((struct work_stuff *));
static void
remember_Ktype PARAMS ((struct work_stuff *, const char *, int));
static void
forget_types PARAMS ((struct work_stuff *));
static void
forget_B_and_K_types PARAMS ((struct work_stuff *));
static void
string_prepends PARAMS ((string *, string *));
static int
demangle_template_value_parm PARAMS ((struct work_stuff*, const char**,
string*, type_kind_t));
static int
do_hpacc_template_const_value PARAMS ((struct work_stuff *, const char **, string *));
static int
do_hpacc_template_literal PARAMS ((struct work_stuff *, const char **, string *));
static int
snarf_numeric_literal PARAMS ((const char **, string *));
#define TYPE_UNQUALIFIED 0x0
#define TYPE_QUAL_CONST 0x1
#define TYPE_QUAL_VOLATILE 0x2
#define TYPE_QUAL_RESTRICT 0x4
static int
code_for_qualifier PARAMS ((int));
static const char*
qualifier_string PARAMS ((int));
static const char*
demangle_qualifier PARAMS ((int));
static int
consume_count (type)
const char **type;
{
int count = 0;
if (! isdigit ((unsigned char)**type))
return -1;
while (isdigit ((unsigned char)**type))
{
count *= 10;
if ((count % 10) != 0)
{
while (isdigit ((unsigned char) **type))
(*type)++;
return -1;
}
count += **type - '0';
(*type)++;
}
return (count);
}
static int
consume_count_with_underscores (mangled)
const char **mangled;
{
int idx;
if (**mangled == '_')
{
(*mangled)++;
if (!isdigit ((unsigned char)**mangled))
return -1;
idx = consume_count (mangled);
if (**mangled != '_')
return -1;
(*mangled)++;
}
else
{
if (**mangled < '0' || **mangled > '9')
return -1;
idx = **mangled - '0';
(*mangled)++;
}
return idx;
}
static int
code_for_qualifier (c)
int c;
{
switch (c)
{
case 'C':
return TYPE_QUAL_CONST;
case 'V':
return TYPE_QUAL_VOLATILE;
case 'u':
return TYPE_QUAL_RESTRICT;
default:
break;
}
abort ();
}
static const char*
qualifier_string (type_quals)
int type_quals;
{
switch (type_quals)
{
case TYPE_UNQUALIFIED:
return "";
case TYPE_QUAL_CONST:
return "const";
case TYPE_QUAL_VOLATILE:
return "volatile";
case TYPE_QUAL_RESTRICT:
return "__restrict";
case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
return "const volatile";
case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
return "const __restrict";
case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
return "volatile __restrict";
case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
return "const volatile __restrict";
default:
break;
}
abort ();
}
static const char*
demangle_qualifier (c)
int c;
{
return qualifier_string (code_for_qualifier (c));
}
int
cplus_demangle_opname (opname, result, options)
const char *opname;
char *result;
int options;
{
int len, len1, ret;
string type;
struct work_stuff work[1];
const char *tem;
len = strlen(opname);
result[0] = '\0';
ret = 0;
memset ((char *) work, 0, sizeof (work));
work->options = options;
if (opname[0] == '_' && opname[1] == '_'
&& opname[2] == 'o' && opname[3] == 'p')
{
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')
{
size_t i;
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')
{
size_t i;
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)
{
size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 10;
if ((int) strlen (optable[i].in) == len1
&& memcmp (optable[i].in, opname + 10, len1) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
strcat (result, "=");
ret = 1;
break;
}
}
}
else
{
size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 3;
if ((int) strlen (optable[i].in) == len1
&& memcmp (optable[i].in, opname + 3, len1) == 0)
{
strcat (result, "operator");
strcat (result, optable[i].out);
ret = 1;
break;
}
}
}
}
else if (len >= 5 && memcmp (opname, "type", 4) == 0
&& strchr (cplus_markers, opname[4]) != NULL)
{
tem = opname + 5;
if (do_type (work, &tem, &type))
{
strcat (result, "operator ");
strncat (result, type.b, type.p - type.b);
string_delete (&type);
ret = 1;
}
}
squangle_mop_up (work);
return ret;
}
const char *
cplus_mangle_opname (opname, options)
const char *opname;
int options;
{
size_t i;
int len;
len = strlen (opname);
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if ((int) strlen (optable[i].out) == len
&& (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
&& memcmp (optable[i].out, opname, len) == 0)
return optable[i].in;
}
return (0);
}
char *
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);
}
static char *
internal_cplus_demangle (work, mangled)
struct work_stuff *work;
const char *mangled;
{
string decl;
int success = 0;
char *demangled = NULL;
int s1,s2,s3,s4;
s1 = work->constructor;
s2 = work->destructor;
s3 = work->static_type;
s4 = work->type_quals;
work->constructor = work->destructor = 0;
work->type_quals = TYPE_UNQUALIFIED;
work->dllimported = 0;
if ((mangled != NULL) && (*mangled != '\0'))
{
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;
}
else if (work->dllimported == 1)
{
string_prepend (&decl, "import stub for ");
work->dllimported = 0;
}
demangled = mop_up (work, &decl, success);
}
work->constructor = s1;
work->destructor = s2;
work->static_type = s3;
work->type_quals = s4;
return (demangled);
}
static void
squangle_mop_up (work)
struct work_stuff *work;
{
forget_B_and_K_types (work);
if (work -> btypevec != NULL)
{
free ((char *) work -> btypevec);
}
if (work -> ktypevec != NULL)
{
free ((char *) work -> ktypevec);
}
}
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);
work -> typevec = NULL;
work -> typevec_size = 0;
}
if (work->tmpl_argvec)
{
int i;
for (i = 0; i < work->ntmpl_args; i++)
if (work->tmpl_argvec[i])
free ((char*) work->tmpl_argvec[i]);
free ((char*) work->tmpl_argvec);
work->tmpl_argvec = NULL;
}
if (work->previous_argument)
{
string_delete (work->previous_argument);
free ((char*) work->previous_argument);
work->previous_argument = NULL;
}
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;
int expect_return_type = 0;
const char *oldmangled = NULL;
string trawname;
string tname;
while (success && (**mangled != '\0'))
{
switch (**mangled)
{
case 'Q':
oldmangled = *mangled;
success = demangle_qualified (work, mangled, declp, 1, 0);
if (success)
remember_type (work, oldmangled, *mangled - oldmangled);
if (AUTO_DEMANGLING || GNU_DEMANGLING)
expect_func = 1;
oldmangled = NULL;
break;
case 'K':
oldmangled = *mangled;
success = demangle_qualified (work, mangled, declp, 1, 0);
if (AUTO_DEMANGLING || GNU_DEMANGLING)
{
expect_func = 1;
}
oldmangled = NULL;
break;
case 'S':
if (oldmangled == NULL)
{
oldmangled = *mangled;
}
(*mangled)++;
work -> static_type = 1;
break;
case 'C':
case 'V':
case 'u':
work->type_quals |= code_for_qualifier (**mangled);
if (oldmangled == NULL)
oldmangled = *mangled;
(*mangled)++;
break;
case 'L':
if (HP_DEMANGLING)
{
while (**mangled && (**mangled != '_'))
(*mangled)++;
if (!**mangled)
success = 0;
else
(*mangled)++;
}
else
success = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (oldmangled == NULL)
{
oldmangled = *mangled;
}
work->temp_start = -1;
success = demangle_class (work, mangled, declp);
if (success)
{
remember_type (work, oldmangled, *mangled - oldmangled);
}
if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
{
if (**mangled != 'F')
expect_func = 1;
}
oldmangled = NULL;
break;
case 'B':
{
string s;
success = do_type (work, mangled, &s);
if (success)
{
string_append (&s, SCOPE_STRING (work));
string_prepends (declp, &s);
}
oldmangled = NULL;
expect_func = 1;
}
break;
case 'F':
oldmangled = NULL;
func_done = 1;
(*mangled)++;
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
{
forget_types (work);
}
success = demangle_args (work, mangled, declp);
if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
{
++(*mangled);
success = do_type (work, mangled, &tname);
string_delete (&tname);
}
break;
case 't':
string_init(&trawname);
string_init(&tname);
if (oldmangled == NULL)
{
oldmangled = *mangled;
}
success = demangle_template (work, mangled, &tname,
&trawname, 1, 1);
if (success)
{
remember_type (work, oldmangled, *mangled - oldmangled);
}
string_append (&tname, SCOPE_STRING (work));
string_prepends(declp, &tname);
if (work -> destructor & 1)
{
string_prepend (&trawname, "~");
string_appends (declp, &trawname);
work->destructor -= 1;
}
if ((work->constructor & 1) || (work->destructor & 1))
{
string_appends (declp, &trawname);
work->constructor -= 1;
}
string_delete(&trawname);
string_delete(&tname);
oldmangled = NULL;
expect_func = 1;
break;
case '_':
if (GNU_DEMANGLING && expect_return_type)
{
string return_type;
string_init (&return_type);
(*mangled)++;
success = do_type (work, mangled, &return_type);
APPEND_BLANK (&return_type);
string_prepends (declp, &return_type);
string_delete (&return_type);
break;
}
else
if (HP_DEMANGLING)
{
(*mangled)++;
while (**mangled && isdigit ((unsigned char)**mangled))
(*mangled)++;
}
else
success = 0;
break;
case 'H':
if (GNU_DEMANGLING)
{
success = demangle_template (work, mangled, declp, 0, 0,
0);
if (!(work->constructor & 1))
expect_return_type = 1;
(*mangled)++;
break;
}
else
{;}
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;
if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
{
forget_types (work);
}
success = demangle_args (work, mangled, declp);
expect_func = 0;
}
}
}
if (success && !func_done)
{
if (AUTO_DEMANGLING || GNU_DEMANGLING)
{
success = demangle_args (work, mangled, declp);
}
}
if (success && PRINT_ARG_TYPES)
{
if (work->static_type)
string_append (declp, " static");
if (work->type_quals != TYPE_UNQUALIFIED)
{
APPEND_BLANK (declp);
string_append (declp, qualifier_string (work->type_quals));
}
}
return (success);
}
#if 0
static int
demangle_method_args (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int success = 0;
if (work -> static_type)
{
string_append (declp, *mangled + 1);
*mangled += strlen (*mangled);
success = 1;
}
else
{
success = demangle_args (work, mangled, declp);
}
return (success);
}
#endif
static int
demangle_template_template_parm (work, mangled, tname)
struct work_stuff *work;
const char **mangled;
string *tname;
{
int i;
int r;
int need_comma = 0;
int success = 1;
string temp;
string_append (tname, "template <");
if (get_count (mangled, &r))
{
for (i = 0; i < r; i++)
{
if (need_comma)
{
string_append (tname, ", ");
}
if (**mangled == 'Z')
{
(*mangled)++;
string_append (tname, "class");
}
else if (**mangled == 'z')
{
(*mangled)++;
success =
demangle_template_template_parm (work, mangled, tname);
if (!success)
{
break;
}
}
else
{
success = do_type (work, mangled, &temp);
if (success)
{
string_appends (tname, &temp);
}
string_delete(&temp);
if (!success)
{
break;
}
}
need_comma = 1;
}
}
if (tname->p[-1] == '>')
string_append (tname, " ");
string_append (tname, "> class");
return (success);
}
static int
demangle_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,
tk_integral);
}
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 ((unsigned char)**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
success = 1;
}
}
return success;
}
static int
demangle_template_value_parm (work, mangled, s, tk)
struct work_stuff *work;
const char **mangled;
string* s;
type_kind_t tk;
{
int success = 1;
if (**mangled == 'Y')
{
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 (tk == tk_integral)
success = demangle_integral_value (work, mangled, s);
else if (tk == tk_char)
{
char tmp[2];
int val;
if (**mangled == 'm')
{
string_appendn (s, "-", 1);
(*mangled)++;
}
string_appendn (s, "'", 1);
val = consume_count(mangled);
if (val <= 0)
success = 0;
else
{
tmp[0] = (char)val;
tmp[1] = '\0';
string_appendn (s, &tmp[0], 1);
string_appendn (s, "'", 1);
}
}
else if (tk == tk_bool)
{
int val = consume_count (mangled);
if (val == 0)
string_appendn (s, "false", 5);
else if (val == 1)
string_appendn (s, "true", 4);
else
success = 0;
}
else if (tk == tk_real)
{
if (**mangled == 'm')
{
string_appendn (s, "-", 1);
(*mangled)++;
}
while (isdigit ((unsigned char)**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
if (**mangled == '.')
{
string_appendn (s, ".", 1);
(*mangled)++;
while (isdigit ((unsigned char)**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
}
if (**mangled == 'e')
{
string_appendn (s, "e", 1);
(*mangled)++;
while (isdigit ((unsigned char)**mangled))
{
string_appendn (s, *mangled, 1);
(*mangled)++;
}
}
}
else if (tk == tk_pointer || tk == tk_reference)
{
if (**mangled == 'Q')
success = demangle_qualified (work, mangled, s,
0,
1);
else
{
int symbol_len = consume_count (mangled);
if (symbol_len == -1)
return -1;
if (symbol_len == 0)
string_appendn (s, "0", 1);
else
{
char *p = xmalloc (symbol_len + 1), *q;
strncpy (p, *mangled, symbol_len);
p [symbol_len] = '\0';
q = cplus_demangle (p, work->options);
if (tk == tk_pointer)
string_appendn (s, "&", 1);
if (q)
{
string_append (s, q);
free (q);
}
else
string_append (s, p);
free (p);
}
*mangled += symbol_len;
}
}
return success;
}
static int
demangle_template (work, mangled, tname, trawname, is_type, remember)
struct work_stuff *work;
const char **mangled;
string *tname;
string *trawname;
int is_type;
int remember;
{
int i;
int r;
int need_comma = 0;
int success = 0;
const char *start;
int is_java_array = 0;
string temp;
int bindex = 0;
(*mangled)++;
if (is_type)
{
if (remember)
bindex = register_Btype (work);
start = *mangled;
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, buf);
}
}
else
{
if ((r = consume_count (mangled)) <= 0
|| (int) strlen (*mangled) < r)
{
return (0);
}
is_java_array = (work -> options & DMGL_JAVA)
&& strncmp (*mangled, "JArray1Z", 8) == 0;
if (! is_java_array)
{
string_appendn (tname, *mangled, r);
}
if (trawname)
string_appendn (trawname, *mangled, r);
*mangled += r;
}
}
if (!is_java_array)
string_append (tname, "<");
if (!get_count (mangled, &r))
{
return (0);
}
if (!is_type)
{
work->tmpl_argvec = (char**) xmalloc (r * sizeof (char *));
work->ntmpl_args = r;
for (i = 0; i < r; i++)
work->tmpl_argvec[i] = 0;
}
for (i = 0; i < r; i++)
{
if (need_comma)
{
string_append (tname, ", ");
}
if (**mangled == 'Z')
{
(*mangled)++;
success = do_type (work, mangled, &temp);
if (success)
{
string_appends (tname, &temp);
if (!is_type)
{
int len = temp.p - temp.b;
work->tmpl_argvec[i] = xmalloc (len + 1);
memcpy (work->tmpl_argvec[i], temp.b, len);
work->tmpl_argvec[i][len] = '\0';
}
}
string_delete(&temp);
if (!success)
{
break;
}
}
else if (**mangled == 'z')
{
int r2;
(*mangled)++;
success = demangle_template_template_parm (work, mangled, tname);
if (success
&& (r2 = consume_count (mangled)) > 0
&& (int) strlen (*mangled) >= r2)
{
string_append (tname, " ");
string_appendn (tname, *mangled, r2);
if (!is_type)
{
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;
success = do_type (work, mangled, &temp);
string_delete(&temp);
if (!success)
break;
if (!is_type)
{
s = ¶m;
string_init (s);
}
else
s = tname;
success = demangle_template_value_parm (work, mangled, s,
(type_kind_t) success);
if (!success)
{
if (!is_type)
string_delete (s);
success = 0;
break;
}
if (!is_type)
{
int len = s->p - s->b;
work->tmpl_argvec[i] = xmalloc (len + 1);
memcpy (work->tmpl_argvec[i], s->b, len);
work->tmpl_argvec[i][len] = '\0';
string_appends (tname, s);
string_delete (s);
}
}
need_comma = 1;
}
if (is_java_array)
{
string_append (tname, "[]");
}
else
{
if (tname->p[-1] == '>')
string_append (tname, " ");
string_append (tname, ">");
}
if (is_type && remember)
remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
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 || HP_DEMANGLING) && (*anchor = mystrstr (mangled, "__pt__")))
{
int len;
*args = *anchor + 6;
len = consume_count (args);
if (len == -1)
return 0;
if (*args + len == mangled + n && **args == '_')
{
++*args;
return 1;
}
}
if (AUTO_DEMANGLING || EDG_DEMANGLING)
{
if ((*anchor = mystrstr (mangled, "__tm__"))
|| (*anchor = mystrstr (mangled, "__ps__"))
|| (*anchor = mystrstr (mangled, "__pt__")))
{
int len;
*args = *anchor + 6;
len = consume_count (args);
if (len == -1)
return 0;
if (*args + len == mangled + n && **args == '_')
{
++*args;
return 1;
}
}
else if ((*anchor = mystrstr (mangled, "__S")))
{
int len;
*args = *anchor + 3;
len = consume_count (args);
if (len == -1)
return 0;
if (*args + len == mangled + n && **args == '_')
{
++*args;
return 1;
}
}
}
return 0;
}
static void
demangle_arm_hp_template (work, mangled, n, declp)
struct work_stuff *work;
const char **mangled;
int n;
string *declp;
{
const char *p;
const char *args;
const char *e = *mangled + n;
string arg;
if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
{
char *start_spec_args = NULL;
start_spec_args = strchr (*mangled, '<');
if (start_spec_args && (start_spec_args - *mangled < n))
string_appendn (declp, *mangled, start_spec_args - *mangled);
else
string_appendn (declp, *mangled, n);
(*mangled) += n + 1;
string_init (&arg);
if (work->temp_start == -1)
work->temp_start = declp->p - declp->b;
string_append (declp, "<");
while (1)
{
string_clear (&arg);
switch (**mangled)
{
case 'T':
(*mangled)++;
if (!do_type (work, mangled, &arg))
goto hpacc_template_args_done;
break;
case 'U':
case 'S':
if (!do_hpacc_template_const_value (work, mangled, &arg))
goto hpacc_template_args_done;
break;
case 'A':
if (!do_hpacc_template_literal (work, mangled, &arg))
goto hpacc_template_args_done;
break;
default:
goto hpacc_template_args_done;
}
string_appends (declp, &arg);
if ((**mangled == '\000') || (**mangled == '_'))
break;
else
string_append (declp, ",");
}
hpacc_template_args_done:
string_append (declp, ">");
string_delete (&arg);
if (**mangled == '_')
(*mangled)++;
return;
}
else if (arm_pt (work, *mangled, n, &p, &args))
{
string type_str;
string_init (&arg);
string_appendn (declp, *mangled, p - *mangled);
if (work->temp_start == -1)
work->temp_start = declp->p - declp->b;
string_append (declp, "<");
while (args < e) {
string_clear (&arg);
switch (*args)
{
case 'X':
args++;
if (!do_type (work, &args, &type_str))
goto cfront_template_args_done;
string_append (&arg, "(");
string_appends (&arg, &type_str);
string_append (&arg, ")");
if (*args != 'L')
goto cfront_template_args_done;
args++;
if (!snarf_numeric_literal (&args, &arg))
goto cfront_template_args_done;
break;
case 'L':
args++;
if (!snarf_numeric_literal (&args, &arg))
goto cfront_template_args_done;
break;
default:
if (!do_type (work, &args, &arg))
goto cfront_template_args_done;
}
string_appends (declp, &arg);
string_append (declp, ",");
}
cfront_template_args_done:
string_delete (&arg);
if (args >= e)
--declp->p;
string_append (declp, ">");
}
else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
&& (*mangled)[9] == 'N'
&& (*mangled)[8] == (*mangled)[10]
&& strchr (cplus_markers, (*mangled)[8]))
{
string_append (declp, "{anonymous}");
}
else
{
if (work->temp_start == -1)
work->temp_start = 0;
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 (n == -1)
return 0;
if ((int) strlen (*mangled) >= n)
{
demangle_arm_hp_template (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;
int btype;
string class_name;
char *save_class_name_end = 0;
string_init (&class_name);
btype = register_Btype (work);
if (demangle_class_name (work, mangled, &class_name))
{
save_class_name_end = class_name.p;
if ((work->constructor & 1) || (work->destructor & 1))
{
if (work->temp_start && (work->temp_start != -1))
{
class_name.p = class_name.b + work->temp_start;
}
string_prepends (declp, &class_name);
if (work -> destructor & 1)
{
string_prepend (declp, "~");
work -> destructor -= 1;
}
else
{
work -> constructor -= 1;
}
}
class_name.p = save_class_name_end;
remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
string_prepend (declp, SCOPE_STRING (work));
string_prepends (declp, &class_name);
success = 1;
}
string_delete (&class_name);
return (success);
}
static int
demangle_prefix (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
int success = 1;
const char *scan;
int i;
if (strlen(*mangled) > 6
&& (strncmp(*mangled, "_imp__", 6) == 0
|| strncmp(*mangled, "__imp_", 6) == 0))
{
(*mangled) += 6;
work->dllimported = 1;
}
else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
{
char *marker = strchr (cplus_markers, (*mangled)[8]);
if (marker != NULL && *marker == (*mangled)[10])
{
if ((*mangled)[9] == 'D')
{
(*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 || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
{
(*mangled) += 7;
work->destructor = 2;
}
else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_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 ((unsigned char)scan[0]) && (scan[0] != 't'))
{
success = 0;
}
}
else if ((scan == *mangled)
&& (isdigit ((unsigned char)scan[2]) || (scan[2] == 'Q')
|| (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
{
if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
&& isdigit ((unsigned char)scan[2]))
{
*mangled = scan + 2;
consume_count (mangled);
string_append (declp, *mangled);
*mangled += strlen (*mangled);
success = 1;
}
else
{
if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
work -> constructor += 1;
*mangled = scan + 2;
}
}
else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
{
success = 1;
demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
}
else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
|| (scan[2] == 'p' && scan[3] == 's')
|| (scan[2] == 'p' && scan[3] == 't')))
{
success = 1;
demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
}
else if ((scan == *mangled) && !isdigit ((unsigned char)scan[2])
&& (scan[2] != 't'))
{
if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
|| (arm_special (mangled, declp) == 0))
{
while (*scan == '_')
{
scan++;
}
if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
{
success = 0;
}
else
{
const char *tmp;
if (!(ARM_DEMANGLING || HP_DEMANGLING))
{
while ((tmp = mystrstr (scan + 2, "__")) != NULL)
scan = tmp;
}
if (*(scan + 2) == '\0')
success = 0;
else
demangle_function_name (work, mangled, declp, scan);
}
}
}
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')
{
switch (**mangled)
{
case 'Q':
case 'K':
success = demangle_qualified (work, mangled, declp, 0, 1);
break;
case 't':
success = demangle_template (work, mangled, declp, 0, 1,
1);
break;
default:
if (isdigit((unsigned char)*mangled[0]))
{
n = consume_count(mangled);
if (n > (int) strlen (*mangled))
{
success = 1;
break;
}
}
else
{
n = strcspn (*mangled, cplus_markers);
}
string_appendn (declp, *mangled, n);
(*mangled) += n;
}
p = strpbrk (*mangled, cplus_markers);
if (success && ((p == NULL) || (p == *mangled)))
{
if (p != NULL)
{
string_append (declp, SCOPE_STRING (work));
(*mangled)++;
}
}
else
{
success = 0;
break;
}
}
if (success)
string_append (declp, " virtual table");
}
else if ((*mangled)[0] == '_'
&& (strchr("0123456789Qt", (*mangled)[1]) != NULL)
&& (p = strpbrk (*mangled, cplus_markers)) != NULL)
{
(*mangled)++;
switch (**mangled)
{
case 'Q':
case 'K':
success = demangle_qualified (work, mangled, declp, 0, 1);
break;
case 't':
success = demangle_template (work, mangled, declp, 0, 1, 1);
break;
default:
n = consume_count (mangled);
if (n < 0 || n > strlen (*mangled))
{
success = 0;
break;
}
string_appendn (declp, *mangled, n);
(*mangled) += n;
}
if (success && (p == *mangled))
{
(*mangled)++;
string_append (declp, SCOPE_STRING (work));
n = strlen (*mangled);
string_appendn (declp, *mangled, n);
(*mangled) += n;
}
else
{
success = 0;
}
}
else if (strncmp (*mangled, "__thunk_", 8) == 0)
{
int delta;
(*mangled) += 8;
delta = consume_count (mangled);
if (delta == -1)
success = 0;
else
{
char *method = internal_cplus_demangle (work, ++*mangled);
if (method)
{
char buf[50];
sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
string_append (declp, buf);
string_append (declp, method);
free (method);
n = strlen (*mangled);
(*mangled) += n;
}
else
{
success = 0;
}
}
}
else if (strncmp (*mangled, "__t", 3) == 0
&& ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
{
p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
(*mangled) += 4;
switch (**mangled)
{
case 'Q':
case 'K':
success = demangle_qualified (work, mangled, declp, 0, 1);
break;
case 't':
success = demangle_template (work, mangled, declp, 0, 1, 1);
break;
default:
success = demangle_fund_type (work, mangled, declp);
break;
}
if (success && **mangled != '\0')
success = 0;
if (success)
string_append (declp, p);
}
else
{
success = 0;
}
return (success);
}
static void
recursively_demangle(work, mangled, result, namelength)
struct work_stuff *work;
const char **mangled;
string *result;
int namelength;
{
char * recurse = (char *)NULL;
char * recurse_dem = (char *)NULL;
recurse = (char *) xmalloc (namelength + 1);
memcpy (recurse, *mangled, namelength);
recurse[namelength] = '\000';
recurse_dem = cplus_demangle (recurse, work->options);
if (recurse_dem)
{
string_append (result, recurse_dem);
free (recurse_dem);
}
else
{
string_appendn (result, *mangled, namelength);
}
free (recurse);
*mangled += namelength;
}
static int
arm_special (mangled, declp)
const char **mangled;
string *declp;
{
int n;
int success = 1;
const char *scan;
if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
{
scan = *mangled + ARM_VTABLE_STRLEN;
while (*scan != '\0')
{
n = consume_count (&scan);
if (n == -1)
{
return (0);
}
scan += n;
if (scan[0] == '_' && scan[1] == '_')
{
scan += 2;
}
}
(*mangled) += ARM_VTABLE_STRLEN;
while (**mangled != '\0')
{
n = consume_count (mangled);
if (n == -1
|| n > strlen (*mangled))
return 0;
string_prependn (declp, *mangled, n);
(*mangled) += n;
if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
{
string_prepend (declp, "::");
(*mangled) += 2;
}
}
string_append (declp, " virtual table");
}
else
{
success = 0;
}
return (success);
}
static int
demangle_qualified (work, mangled, result, isfuncname, append)
struct work_stuff *work;
const char **mangled;
string *result;
int isfuncname;
int append;
{
int qualifiers = 0;
int success = 1;
const char *p;
char num[2];
string temp;
string last_name;
int bindex = register_Btype (work);
isfuncname = (isfuncname
&& ((work->constructor & 1) || (work->destructor & 1)));
string_init (&temp);
string_init (&last_name);
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]);
}
else
switch ((*mangled)[1])
{
case '_':
p = *mangled + 2;
qualifiers = atoi (p);
if (!isdigit ((unsigned char)*p) || *p == '0')
success = 0;
while (isdigit ((unsigned char)*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)
{
int remember_K = 1;
string_clear (&last_name);
if (*mangled[0] == '_')
(*mangled)++;
if (*mangled[0] == 't')
{
success = demangle_template(work, mangled, &temp,
&last_name, 1, 0);
if (!success)
break;
}
else if (*mangled[0] == 'K')
{
int idx;
(*mangled)++;
idx = consume_count_with_underscores (mangled);
if (idx == -1 || idx >= work->numk)
success = 0;
else
string_append (&temp, work->ktypevec[idx]);
remember_K = 0;
if (!success) break;
}
else
{
if (EDG_DEMANGLING)
{
int namelength;
namelength = consume_count (mangled);
if (namelength == -1)
{
success = 0;
break;
}
recursively_demangle(work, mangled, &temp, namelength);
}
else
{
success = do_type (work, mangled, &last_name);
if (!success)
break;
string_appends (&temp, &last_name);
}
}
if (remember_K)
remember_Ktype (work, temp.b, LEN_STRING (&temp));
if (qualifiers > 0)
string_append (&temp, SCOPE_STRING (work));
}
remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
if (isfuncname)
{
string_append (&temp, SCOPE_STRING (work));
if (work -> destructor & 1)
string_append (&temp, "~");
string_appends (&temp, &last_name);
}
if (append)
string_appends (result, &temp);
else
{
if (!STRING_EMPTY (result))
string_append (&temp, SCOPE_STRING (work));
string_prepends (result, &temp);
}
string_delete (&last_name);
string_delete (&temp);
return (success);
}
static int
get_count (type, count)
const char **type;
int *count;
{
const char *p;
int n;
if (!isdigit ((unsigned char)**type))
{
return (0);
}
else
{
*count = **type - '0';
(*type)++;
if (isdigit ((unsigned char)**type))
{
p = *type;
n = *count;
do
{
n *= 10;
n += *p - '0';
p++;
}
while (isdigit ((unsigned char)*p));
if (*p == '_')
{
*type = p + 1;
*count = n;
}
}
}
return (1);
}
static int
do_type (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int n;
int done;
int success;
string decl;
const char *remembered_type;
int type_quals;
string btype;
type_kind_t tk = tk_none;
string_init (&btype);
string_init (&decl);
string_init (result);
done = 0;
success = 1;
while (success && !done)
{
int member;
switch (**mangled)
{
case 'P':
case 'p':
(*mangled)++;
if (! (work -> options & DMGL_JAVA))
string_prepend (&decl, "*");
if (tk == tk_none)
tk = tk_pointer;
break;
case 'R':
(*mangled)++;
string_prepend (&decl, "&");
if (tk == tk_none)
tk = tk_reference;
break;
case 'A':
{
++(*mangled);
if (!STRING_EMPTY (&decl)
&& (decl.b[0] == '*' || decl.b[0] == '&'))
{
string_prepend (&decl, "(");
string_append (&decl, ")");
}
string_append (&decl, "[");
if (**mangled != '_')
success = demangle_template_value_parm (work, mangled, &decl,
tk_integral);
if (**mangled == '_')
++(*mangled);
string_append (&decl, "]");
break;
}
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] == '*' || decl.b[0] == '&'))
{
string_prepend (&decl, "(");
string_append (&decl, ")");
}
if (!demangle_nested_args (work, mangled, &decl)
|| (**mangled != '_' && **mangled != '\0'))
{
success = 0;
break;
}
if (success && (**mangled == '_'))
(*mangled)++;
break;
case 'M':
case 'O':
{
type_quals = TYPE_UNQUALIFIED;
member = **mangled == 'M';
(*mangled)++;
string_append (&decl, ")");
string_prepend (&decl, SCOPE_STRING (work));
if (isdigit ((unsigned char)**mangled))
{
n = consume_count (mangled);
if (n == -1
|| (int) strlen (*mangled) < n)
{
success = 0;
break;
}
string_prependn (&decl, *mangled, n);
*mangled += n;
}
else if (**mangled == 'X' || **mangled == 'Y')
{
string temp;
do_type (work, mangled, &temp);
string_prepends (&decl, &temp);
}
else if (**mangled == 't')
{
string temp;
string_init (&temp);
success = demangle_template (work, mangled, &temp,
NULL, 1, 1);
if (success)
{
string_prependn (&decl, temp.b, temp.p - temp.b);
string_clear (&temp);
}
else
break;
}
else
{
success = 0;
break;
}
string_prepend (&decl, "(");
if (member)
{
switch (**mangled)
{
case 'C':
case 'V':
case 'u':
type_quals |= code_for_qualifier (**mangled);
(*mangled)++;
break;
default:
break;
}
if (*(*mangled)++ != 'F')
{
success = 0;
break;
}
}
if ((member && !demangle_nested_args (work, mangled, &decl))
|| **mangled != '_')
{
success = 0;
break;
}
(*mangled)++;
if (! PRINT_ANSI_QUALIFIERS)
{
break;
}
if (type_quals != TYPE_UNQUALIFIED)
{
APPEND_BLANK (&decl);
string_append (&decl, qualifier_string (type_quals));
}
break;
}
case 'G':
(*mangled)++;
break;
case 'C':
case 'V':
case 'u':
if (PRINT_ANSI_QUALIFIERS)
{
if (!STRING_EMPTY (&decl))
string_prepend (&decl, " ");
string_prepend (&decl, demangle_qualifier (**mangled));
}
(*mangled)++;
break;
default:
done = 1;
break;
}
}
if (success) switch (**mangled)
{
case 'Q':
case 'K':
{
success = demangle_qualified (work, mangled, result, 0, 1);
break;
}
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':
{
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);
if (tk == tk_none)
tk = (type_kind_t) success;
break;
}
if (success)
{
if (!STRING_EMPTY (&decl))
{
string_append (result, " ");
string_appends (result, &decl);
}
}
else
string_delete (result);
string_delete (&decl);
if (success)
return (int) ((tk == tk_none) ? tk_integral : tk);
else
return 0;
}
static int
demangle_fund_type (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int done = 0;
int success = 1;
char buf[10];
int dec = 0;
string btype;
type_kind_t tk = tk_integral;
string_init (&btype);
while (!done)
{
switch (**mangled)
{
case 'C':
case 'V':
case 'u':
if (PRINT_ANSI_QUALIFIERS)
{
if (!STRING_EMPTY (result))
string_prepend (result, " ");
string_prepend (result, demangle_qualifier (**mangled));
}
(*mangled)++;
break;
case 'U':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "unsigned");
break;
case 'S':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "signed");
break;
case 'J':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "__complex");
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");
tk = tk_bool;
break;
case 'c':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "char");
tk = tk_char;
break;
case 'w':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "wchar_t");
tk = tk_char;
break;
case 'r':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "long double");
tk = tk_real;
break;
case 'd':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "double");
tk = tk_real;
break;
case 'f':
(*mangled)++;
APPEND_BLANK (result);
string_append (result, "float");
tk = tk_real;
break;
case 'G':
(*mangled)++;
if (!isdigit ((unsigned char)**mangled))
{
success = 0;
break;
}
case 'I':
(*mangled)++;
if (**mangled == '_')
{
int i;
(*mangled)++;
for (i = 0;
i < sizeof (buf) - 1 && **mangled && **mangled != '_';
(*mangled)++, i++)
buf[i] = **mangled;
if (**mangled != '_')
{
success = 0;
break;
}
buf[i] = '\0';
(*mangled)++;
}
else
{
strncpy (buf, *mangled, 2);
buf[2] = '\0';
*mangled += min (strlen (*mangled), 2);
}
sscanf (buf, "%x", &dec);
sprintf (buf, "int%i_t", dec);
APPEND_BLANK (result);
string_append (result, buf);
break;
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':
{
success = demangle_template (work, mangled, &btype, 0, 1, 1);
string_appends (result, &btype);
break;
}
default:
success = 0;
break;
}
return success ? ((int) tk) : 0;
}
static int
do_hpacc_template_const_value (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int unsigned_const;
if (**mangled != 'U' && **mangled != 'S')
return 0;
unsigned_const = (**mangled == 'U');
(*mangled)++;
switch (**mangled)
{
case 'N':
string_append (result, "-");
case 'P':
(*mangled)++;
break;
case 'M':
string_append (result, "-2147483648");
(*mangled)++;
return 1;
default:
return 0;
}
if (!(isdigit ((unsigned char)**mangled)))
return 0;
while (isdigit ((unsigned char)**mangled))
{
char_str[0] = **mangled;
string_append (result, char_str);
(*mangled)++;
}
if (unsigned_const)
string_append (result, "U");
return 1;
}
static int
do_hpacc_template_literal (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
int literal_len = 0;
char * recurse;
char * recurse_dem;
if (**mangled != 'A')
return 0;
(*mangled)++;
literal_len = consume_count (mangled);
if (literal_len <= 0)
return 0;
string_append (result, "&");
recurse = (char *) xmalloc (literal_len + 1);
memcpy (recurse, *mangled, literal_len);
recurse[literal_len] = '\000';
recurse_dem = cplus_demangle (recurse, work->options);
if (recurse_dem)
{
string_append (result, recurse_dem);
free (recurse_dem);
}
else
{
string_appendn (result, *mangled, literal_len);
}
(*mangled) += literal_len;
free (recurse);
return 1;
}
static int
snarf_numeric_literal (args, arg)
const char ** args;
string * arg;
{
if (**args == '-')
{
char_str[0] = '-';
string_append (arg, char_str);
(*args)++;
}
else if (**args == '+')
(*args)++;
if (!isdigit ((unsigned char)**args))
return 0;
while (isdigit ((unsigned char)**args))
{
char_str[0] = **args;
string_append (arg, char_str);
(*args)++;
}
return 1;
}
static int
do_arg (work, mangled, result)
struct work_stuff *work;
const char **mangled;
string *result;
{
const char *start = *mangled;
string_init (result);
if (work->nrepeats > 0)
{
--work->nrepeats;
if (work->previous_argument == 0)
return 0;
string_appends (result, work->previous_argument);
return 1;
}
if (**mangled == 'n')
{
(*mangled)++;
work->nrepeats = consume_count(mangled);
if (work->nrepeats <= 0)
return 0;
if (work->nrepeats > 9)
{
if (**mangled != '_')
return 0;
else
(*mangled)++;
}
return do_arg (work, mangled, result);
}
if (work->previous_argument)
string_clear (work->previous_argument);
else
{
work->previous_argument = (string*) xmalloc (sizeof (string));
string_init (work->previous_argument);
}
if (!do_type (work, mangled, work->previous_argument))
return 0;
string_appends (result, work->previous_argument);
remember_type (work, start, *mangled - start);
return 1;
}
static void
remember_type (work, start, len)
struct work_stuff *work;
const char *start;
int len;
{
char *tem;
if (work->forgetting_types)
return;
if (work -> ntypes >= work -> typevec_size)
{
if (work -> typevec_size == 0)
{
work -> typevec_size = 3;
work -> typevec
= (char **) xmalloc (sizeof (char *) * work -> typevec_size);
}
else
{
work -> typevec_size *= 2;
work -> typevec
= (char **) xrealloc ((char *)work -> typevec,
sizeof (char *) * work -> typevec_size);
}
}
tem = xmalloc (len + 1);
memcpy (tem, start, len);
tem[len] = '\0';
work -> typevec[work -> ntypes++] = tem;
}
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;
}
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);
}
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;
}
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;
}
}
}
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')
|| work->nrepeats > 0)
{
if ((**mangled == 'N') || (**mangled == 'T'))
{
temptype = *(*mangled)++;
if (temptype == 'N')
{
if (!get_count (mangled, &r))
{
return (0);
}
}
else
{
r = 1;
}
if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
{
if ((t = consume_count(mangled)) <= 0)
{
return (0);
}
}
else
{
if (!get_count (mangled, &t))
{
return (0);
}
}
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
{
t--;
}
if ((t < 0) || (t >= work -> ntypes))
{
return (0);
}
while (work->nrepeats > 0 || --r >= 0)
{
tem = work -> typevec[t];
if (need_comma && PRINT_ARG_TYPES)
{
string_append (declp, ", ");
}
if (!do_arg (work, &tem, &arg))
{
return (0);
}
if (PRINT_ARG_TYPES)
{
string_appends (declp, &arg);
}
string_delete (&arg);
need_comma = 1;
}
}
else
{
if (need_comma && PRINT_ARG_TYPES)
string_append (declp, ", ");
if (!do_arg (work, mangled, &arg))
return (0);
if (PRINT_ARG_TYPES)
string_appends (declp, &arg);
string_delete (&arg);
need_comma = 1;
}
}
if (**mangled == 'e')
{
(*mangled)++;
if (PRINT_ARG_TYPES)
{
if (need_comma)
{
string_append (declp, ",");
}
string_append (declp, "...");
}
}
if (PRINT_ARG_TYPES)
{
string_append (declp, ")");
}
return (1);
}
static int
demangle_nested_args (work, mangled, declp)
struct work_stuff *work;
const char **mangled;
string *declp;
{
string* saved_previous_argument;
int result;
int saved_nrepeats;
++work->forgetting_types;
saved_previous_argument = work->previous_argument;
saved_nrepeats = work->nrepeats;
work->previous_argument = 0;
work->nrepeats = 0;
result = demangle_args (work, mangled, declp);
if (work->previous_argument)
string_delete (work->previous_argument);
work->previous_argument = saved_previous_argument;
--work->forgetting_types;
work->nrepeats = saved_nrepeats;
return result;
}
static void
demangle_function_name (work, mangled, declp, scan)
struct work_stuff *work;
const char **mangled;
string *declp;
const char *scan;
{
size_t i;
string type;
const char *tem;
string_appendn (declp, (*mangled), scan - (*mangled));
string_need (declp, 1);
*(declp -> p) = '\0';
(*mangled) = scan + 2;
if (HP_DEMANGLING && (**mangled == 'X'))
{
demangle_arm_hp_template (work, mangled, 0, declp);
}
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_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++)
{
int len = declp->p - declp->b - 10;
if ((int) strlen (optable[i].in) == len
&& memcmp (optable[i].in, declp->b + 10, len) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
string_append (declp, "=");
break;
}
}
}
else
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
int len = declp->p - declp->b - 3;
if ((int) strlen (optable[i].in) == len
&& memcmp (optable[i].in, declp->b + 3, len) == 0)
{
string_clear (declp);
string_append (declp, "operator");
string_append (declp, optable[i].out);
break;
}
}
}
}
else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
&& strchr (cplus_markers, declp->b[4]) != NULL)
{
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
#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 *result;
result = cplus_demangle (mangled_name, flags);
if (result == NULL)
{
printf ("%s\n", mangled_name);
}
else
{
printf ("%s\n", result);
free (result);
}
}
static void
usage (stream, status)
FILE *stream;
int status;
{
fprintf (stream, "\
Usage: %s [-_] [-n] [-s {gnu,lucid,arm,hp,edg}] [--strip-underscores]\n\
[--no-strip-underscores] [--format={gnu,lucid,arm,hp,edg}]\n\
[--help] [--version] [arg...]\n",
program_name);
exit (status);
}
#define MBUF_SIZE 32767
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'},
{"java", no_argument, 0, 'j'},
{"no-strip-underscores", no_argument, 0, 'n'},
{"version", no_argument, 0, 'v'},
{0, no_argument, 0, 0}
};
void
fancy_abort ()
{
fatal ("Internal gcc abort.");
}
static const char *
standard_symbol_characters ()
{
return "_$.";
}
static const char *
hp_symbol_characters ()
{
return "_$.<>#,*&[]:(){}";
}
int
main (argc, argv)
int argc;
char **argv;
{
char *result;
int c;
char *valid_symbols;
program_name = argv[0];
strip_underscore = prepends_underscore;
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 (C++ demangler), 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 if (strcmp (optarg, "hp") == 0)
{
current_demangling_style = hp_demangling;
}
else if (strcmp (optarg, "edg") == 0)
{
current_demangling_style = edg_demangling;
}
else
{
fprintf (stderr, "%s: unknown demangling style `%s'\n",
program_name, optarg);
exit (1);
}
break;
}
}
if (optind < argc)
{
for ( ; optind < argc; optind++)
{
demangle_it (argv[optind]);
}
}
else
{
switch (current_demangling_style)
{
case gnu_demangling:
case lucid_demangling:
case arm_demangling:
case edg_demangling:
valid_symbols = standard_symbol_characters ();
break;
case hp_demangling:
valid_symbols = hp_symbol_characters ();
break;
default:
abort ();
}
for (;;)
{
int i = 0;
c = getchar ();
while (c != EOF && (isalnum (c) || strchr (valid_symbols, 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, flags);
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);
}
PTR
xmalloc (size)
size_t size;
{
register PTR value = (PTR) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
PTR
xrealloc (ptr, size)
PTR ptr;
size_t size;
{
register PTR value = (PTR) realloc (ptr, size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
#endif