cplus-dem.c revision 33965
133965Sjdp/* Demangler for GNU C++
233965Sjdp   Copyright 1989, 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
333965Sjdp   Written by James Clark (jjc@jclark.uucp)
433965Sjdp   Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
533965Sjdp
633965SjdpThis file is part of the libiberty library.
733965SjdpLibiberty is free software; you can redistribute it and/or
833965Sjdpmodify it under the terms of the GNU Library General Public
933965SjdpLicense as published by the Free Software Foundation; either
1033965Sjdpversion 2 of the License, or (at your option) any later version.
1133965Sjdp
1233965SjdpLibiberty is distributed in the hope that it will be useful,
1333965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1433965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1533965SjdpLibrary General Public License for more details.
1633965Sjdp
1733965SjdpYou should have received a copy of the GNU Library General Public
1833965SjdpLicense along with libiberty; see the file COPYING.LIB.  If
1933965Sjdpnot, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2033965SjdpBoston, MA 02111-1307, USA.  */
2133965Sjdp
2233965Sjdp/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
2333965Sjdp
2433965Sjdp   This file imports xmalloc and xrealloc, which are like malloc and
2533965Sjdp   realloc except that they generate a fatal error if there is no
2633965Sjdp   available memory.  */
2733965Sjdp
2833965Sjdp/* This file lives in both GCC and libiberty.  When making changes, please
2933965Sjdp   try not to break either.  */
3033965Sjdp
3133965Sjdp#include <ctype.h>
3233965Sjdp#include <string.h>
3333965Sjdp#include <stdio.h>
3433965Sjdp
3533965Sjdp#include <demangle.h>
3633965Sjdp#undef CURRENT_DEMANGLING_STYLE
3733965Sjdp#define CURRENT_DEMANGLING_STYLE work->options
3833965Sjdp
3933965Sjdpextern char *xmalloc PARAMS((unsigned));
4033965Sjdpextern char *xrealloc PARAMS((char *, unsigned));
4133965Sjdp
4233965Sjdpstatic const char *mystrstr PARAMS ((const char *, const char *));
4333965Sjdp
4433965Sjdpstatic const char *
4533965Sjdpmystrstr (s1, s2)
4633965Sjdp     const char *s1, *s2;
4733965Sjdp{
4833965Sjdp  register const char *p = s1;
4933965Sjdp  register int len = strlen (s2);
5033965Sjdp
5133965Sjdp  for (; (p = strchr (p, *s2)) != 0; p++)
5233965Sjdp    {
5333965Sjdp      if (strncmp (p, s2, len) == 0)
5433965Sjdp	{
5533965Sjdp	  return (p);
5633965Sjdp	}
5733965Sjdp    }
5833965Sjdp  return (0);
5933965Sjdp}
6033965Sjdp
6133965Sjdp/* In order to allow a single demangler executable to demangle strings
6233965Sjdp   using various common values of CPLUS_MARKER, as well as any specific
6333965Sjdp   one set at compile time, we maintain a string containing all the
6433965Sjdp   commonly used ones, and check to see if the marker we are looking for
6533965Sjdp   is in that string.  CPLUS_MARKER is usually '$' on systems where the
6633965Sjdp   assembler can deal with that.  Where the assembler can't, it's usually
6733965Sjdp   '.' (but on many systems '.' is used for other things).  We put the
6833965Sjdp   current defined CPLUS_MARKER first (which defaults to '$'), followed
6933965Sjdp   by the next most common value, followed by an explicit '$' in case
7033965Sjdp   the value of CPLUS_MARKER is not '$'.
7133965Sjdp
7233965Sjdp   We could avoid this if we could just get g++ to tell us what the actual
7333965Sjdp   cplus marker character is as part of the debug information, perhaps by
7433965Sjdp   ensuring that it is the character that terminates the gcc<n>_compiled
7533965Sjdp   marker symbol (FIXME).  */
7633965Sjdp
7733965Sjdp#if !defined (CPLUS_MARKER)
7833965Sjdp#define CPLUS_MARKER '$'
7933965Sjdp#endif
8033965Sjdp
8133965Sjdpenum demangling_styles current_demangling_style = gnu_demangling;
8233965Sjdp
8333965Sjdpstatic char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
8433965Sjdp
8533965Sjdpvoid
8633965Sjdpset_cplus_marker_for_demangling (ch)
8733965Sjdp     int ch;
8833965Sjdp{
8933965Sjdp  cplus_markers[0] = ch;
9033965Sjdp}
9133965Sjdp
9233965Sjdp/* Stuff that is shared between sub-routines.
9333965Sjdp   Using a shared structure allows cplus_demangle to be reentrant.  */
9433965Sjdp
9533965Sjdpstruct work_stuff
9633965Sjdp{
9733965Sjdp  int options;
9833965Sjdp  char **typevec;
9933965Sjdp  int ntypes;
10033965Sjdp  int typevec_size;
10133965Sjdp  int constructor;
10233965Sjdp  int destructor;
10333965Sjdp  int static_type;	/* A static member function */
10433965Sjdp  int const_type;	/* A const member function */
10533965Sjdp};
10633965Sjdp
10733965Sjdp#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
10833965Sjdp#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
10933965Sjdp
11033965Sjdpstatic const struct optable
11133965Sjdp{
11233965Sjdp  const char *in;
11333965Sjdp  const char *out;
11433965Sjdp  int flags;
11533965Sjdp} optable[] = {
11633965Sjdp  {"nw",	  " new",	DMGL_ANSI},	/* new (1.92,	 ansi) */
11733965Sjdp  {"dl",	  " delete",	DMGL_ANSI},	/* new (1.92,	 ansi) */
11833965Sjdp  {"new",	  " new",	0},		/* old (1.91,	 and 1.x) */
11933965Sjdp  {"delete",	  " delete",	0},		/* old (1.91,	 and 1.x) */
12033965Sjdp  {"vn",	  " new []",	DMGL_ANSI},	/* GNU, pending ansi */
12133965Sjdp  {"vd",	  " delete []",	DMGL_ANSI},	/* GNU, pending ansi */
12233965Sjdp  {"as",	  "=",		DMGL_ANSI},	/* ansi */
12333965Sjdp  {"ne",	  "!=",		DMGL_ANSI},	/* old, ansi */
12433965Sjdp  {"eq",	  "==",		DMGL_ANSI},	/* old,	ansi */
12533965Sjdp  {"ge",	  ">=",		DMGL_ANSI},	/* old,	ansi */
12633965Sjdp  {"gt",	  ">",		DMGL_ANSI},	/* old,	ansi */
12733965Sjdp  {"le",	  "<=",		DMGL_ANSI},	/* old,	ansi */
12833965Sjdp  {"lt",	  "<",		DMGL_ANSI},	/* old,	ansi */
12933965Sjdp  {"plus",	  "+",		0},		/* old */
13033965Sjdp  {"pl",	  "+",		DMGL_ANSI},	/* ansi */
13133965Sjdp  {"apl",	  "+=",		DMGL_ANSI},	/* ansi */
13233965Sjdp  {"minus",	  "-",		0},		/* old */
13333965Sjdp  {"mi",	  "-",		DMGL_ANSI},	/* ansi */
13433965Sjdp  {"ami",	  "-=",		DMGL_ANSI},	/* ansi */
13533965Sjdp  {"mult",	  "*",		0},		/* old */
13633965Sjdp  {"ml",	  "*",		DMGL_ANSI},	/* ansi */
13733965Sjdp  {"amu",	  "*=",		DMGL_ANSI},	/* ansi (ARM/Lucid) */
13833965Sjdp  {"aml",	  "*=",		DMGL_ANSI},	/* ansi (GNU/g++) */
13933965Sjdp  {"convert",	  "+",		0},		/* old (unary +) */
14033965Sjdp  {"negate",	  "-",		0},		/* old (unary -) */
14133965Sjdp  {"trunc_mod",	  "%",		0},		/* old */
14233965Sjdp  {"md",	  "%",		DMGL_ANSI},	/* ansi */
14333965Sjdp  {"amd",	  "%=",		DMGL_ANSI},	/* ansi */
14433965Sjdp  {"trunc_div",	  "/",		0},		/* old */
14533965Sjdp  {"dv",	  "/",		DMGL_ANSI},	/* ansi */
14633965Sjdp  {"adv",	  "/=",		DMGL_ANSI},	/* ansi */
14733965Sjdp  {"truth_andif", "&&",		0},		/* old */
14833965Sjdp  {"aa",	  "&&",		DMGL_ANSI},	/* ansi */
14933965Sjdp  {"truth_orif",  "||",		0},		/* old */
15033965Sjdp  {"oo",	  "||",		DMGL_ANSI},	/* ansi */
15133965Sjdp  {"truth_not",	  "!",		0},		/* old */
15233965Sjdp  {"nt",	  "!",		DMGL_ANSI},	/* ansi */
15333965Sjdp  {"postincrement","++",	0},		/* old */
15433965Sjdp  {"pp",	  "++",		DMGL_ANSI},	/* ansi */
15533965Sjdp  {"postdecrement","--",	0},		/* old */
15633965Sjdp  {"mm",	  "--",		DMGL_ANSI},	/* ansi */
15733965Sjdp  {"bit_ior",	  "|",		0},		/* old */
15833965Sjdp  {"or",	  "|",		DMGL_ANSI},	/* ansi */
15933965Sjdp  {"aor",	  "|=",		DMGL_ANSI},	/* ansi */
16033965Sjdp  {"bit_xor",	  "^",		0},		/* old */
16133965Sjdp  {"er",	  "^",		DMGL_ANSI},	/* ansi */
16233965Sjdp  {"aer",	  "^=",		DMGL_ANSI},	/* ansi */
16333965Sjdp  {"bit_and",	  "&",		0},		/* old */
16433965Sjdp  {"ad",	  "&",		DMGL_ANSI},	/* ansi */
16533965Sjdp  {"aad",	  "&=",		DMGL_ANSI},	/* ansi */
16633965Sjdp  {"bit_not",	  "~",		0},		/* old */
16733965Sjdp  {"co",	  "~",		DMGL_ANSI},	/* ansi */
16833965Sjdp  {"call",	  "()",		0},		/* old */
16933965Sjdp  {"cl",	  "()",		DMGL_ANSI},	/* ansi */
17033965Sjdp  {"alshift",	  "<<",		0},		/* old */
17133965Sjdp  {"ls",	  "<<",		DMGL_ANSI},	/* ansi */
17233965Sjdp  {"als",	  "<<=",	DMGL_ANSI},	/* ansi */
17333965Sjdp  {"arshift",	  ">>",		0},		/* old */
17433965Sjdp  {"rs",	  ">>",		DMGL_ANSI},	/* ansi */
17533965Sjdp  {"ars",	  ">>=",	DMGL_ANSI},	/* ansi */
17633965Sjdp  {"component",	  "->",		0},		/* old */
17733965Sjdp  {"pt",	  "->",		DMGL_ANSI},	/* ansi; Lucid C++ form */
17833965Sjdp  {"rf",	  "->",		DMGL_ANSI},	/* ansi; ARM/GNU form */
17933965Sjdp  {"indirect",	  "*",		0},		/* old */
18033965Sjdp  {"method_call",  "->()",	0},		/* old */
18133965Sjdp  {"addr",	  "&",		0},		/* old (unary &) */
18233965Sjdp  {"array",	  "[]",		0},		/* old */
18333965Sjdp  {"vc",	  "[]",		DMGL_ANSI},	/* ansi */
18433965Sjdp  {"compound",	  ", ",		0},		/* old */
18533965Sjdp  {"cm",	  ", ",		DMGL_ANSI},	/* ansi */
18633965Sjdp  {"cond",	  "?:",		0},		/* old */
18733965Sjdp  {"cn",	  "?:",		DMGL_ANSI},	/* pseudo-ansi */
18833965Sjdp  {"max",	  ">?",		0},		/* old */
18933965Sjdp  {"mx",	  ">?",		DMGL_ANSI},	/* pseudo-ansi */
19033965Sjdp  {"min",	  "<?",		0},		/* old */
19133965Sjdp  {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
19233965Sjdp  {"nop",	  "",		0},		/* old (for operator=) */
19333965Sjdp  {"rm",	  "->*",	DMGL_ANSI}	/* ansi */
19433965Sjdp};
19533965Sjdp
19633965Sjdp
19733965Sjdptypedef struct string		/* Beware: these aren't required to be */
19833965Sjdp{				/*  '\0' terminated.  */
19933965Sjdp  char *b;			/* pointer to start of string */
20033965Sjdp  char *p;			/* pointer after last character */
20133965Sjdp  char *e;			/* pointer after end of allocated space */
20233965Sjdp} string;
20333965Sjdp
20433965Sjdp#define STRING_EMPTY(str)	((str) -> b == (str) -> p)
20533965Sjdp#define PREPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
20633965Sjdp    string_prepend(str, " ");}
20733965Sjdp#define APPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
20833965Sjdp    string_append(str, " ");}
20933965Sjdp
21033965Sjdp#define ARM_VTABLE_STRING "__vtbl__"	/* Lucid/ARM virtual table prefix */
21133965Sjdp#define ARM_VTABLE_STRLEN 8		/* strlen (ARM_VTABLE_STRING) */
21233965Sjdp
21333965Sjdp/* Prototypes for local functions */
21433965Sjdp
21533965Sjdpstatic char *
21633965Sjdpmop_up PARAMS ((struct work_stuff *, string *, int));
21733965Sjdp
21833965Sjdp#if 0
21933965Sjdpstatic int
22033965Sjdpdemangle_method_args PARAMS ((struct work_stuff *work, const char **, string *));
22133965Sjdp#endif
22233965Sjdp
22333965Sjdpstatic int
22433965Sjdpdemangle_template PARAMS ((struct work_stuff *work, const char **, string *,
22533965Sjdp			   string *));
22633965Sjdp
22733965Sjdpstatic int
22833965Sjdparm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
22933965Sjdp		const char **));
23033965Sjdp
23133965Sjdpstatic void
23233965Sjdpdemangle_arm_pt PARAMS ((struct work_stuff *, const char **, int, string *));
23333965Sjdp
23433965Sjdpstatic int
23533965Sjdpdemangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
23633965Sjdp
23733965Sjdpstatic int
23833965Sjdpdemangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
23933965Sjdp			    int, int));
24033965Sjdp
24133965Sjdpstatic int
24233965Sjdpdemangle_class PARAMS ((struct work_stuff *, const char **, string *));
24333965Sjdp
24433965Sjdpstatic int
24533965Sjdpdemangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
24633965Sjdp
24733965Sjdpstatic int
24833965Sjdpdemangle_signature PARAMS ((struct work_stuff *, const char **, string *));
24933965Sjdp
25033965Sjdpstatic int
25133965Sjdpdemangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
25233965Sjdp
25333965Sjdpstatic int
25433965Sjdpgnu_special PARAMS ((struct work_stuff *, const char **, string *));
25533965Sjdp
25633965Sjdpstatic int
25733965Sjdparm_special PARAMS ((struct work_stuff *, const char **, string *));
25833965Sjdp
25933965Sjdpstatic void
26033965Sjdpstring_need PARAMS ((string *, int));
26133965Sjdp
26233965Sjdpstatic void
26333965Sjdpstring_delete PARAMS ((string *));
26433965Sjdp
26533965Sjdpstatic void
26633965Sjdpstring_init PARAMS ((string *));
26733965Sjdp
26833965Sjdpstatic void
26933965Sjdpstring_clear PARAMS ((string *));
27033965Sjdp
27133965Sjdp#if 0
27233965Sjdpstatic int
27333965Sjdpstring_empty PARAMS ((string *));
27433965Sjdp#endif
27533965Sjdp
27633965Sjdpstatic void
27733965Sjdpstring_append PARAMS ((string *, const char *));
27833965Sjdp
27933965Sjdpstatic void
28033965Sjdpstring_appends PARAMS ((string *, string *));
28133965Sjdp
28233965Sjdpstatic void
28333965Sjdpstring_appendn PARAMS ((string *, const char *, int));
28433965Sjdp
28533965Sjdpstatic void
28633965Sjdpstring_prepend PARAMS ((string *, const char *));
28733965Sjdp
28833965Sjdpstatic void
28933965Sjdpstring_prependn PARAMS ((string *, const char *, int));
29033965Sjdp
29133965Sjdpstatic int
29233965Sjdpget_count PARAMS ((const char **, int *));
29333965Sjdp
29433965Sjdpstatic int
29533965Sjdpconsume_count PARAMS ((const char **));
29633965Sjdp
29733965Sjdpstatic int
29833965Sjdpdemangle_args PARAMS ((struct work_stuff *, const char **, string *));
29933965Sjdp
30033965Sjdpstatic int
30133965Sjdpdo_type PARAMS ((struct work_stuff *, const char **, string *));
30233965Sjdp
30333965Sjdpstatic int
30433965Sjdpdo_arg PARAMS ((struct work_stuff *, const char **, string *));
30533965Sjdp
30633965Sjdpstatic void
30733965Sjdpdemangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
30833965Sjdp				const char *));
30933965Sjdp
31033965Sjdpstatic void
31133965Sjdpremember_type PARAMS ((struct work_stuff *, const char *, int));
31233965Sjdp
31333965Sjdpstatic void
31433965Sjdpforget_types PARAMS ((struct work_stuff *));
31533965Sjdp
31633965Sjdpstatic void
31733965Sjdpstring_prepends PARAMS ((string *, string *));
31833965Sjdp
31933965Sjdp/*  Translate count to integer, consuming tokens in the process.
32033965Sjdp    Conversion terminates on the first non-digit character.
32133965Sjdp    Trying to consume something that isn't a count results in
32233965Sjdp    no consumption of input and a return of 0.  */
32333965Sjdp
32433965Sjdpstatic int
32533965Sjdpconsume_count (type)
32633965Sjdp     const char **type;
32733965Sjdp{
32833965Sjdp  int count = 0;
32933965Sjdp
33033965Sjdp  while (isdigit (**type))
33133965Sjdp    {
33233965Sjdp      count *= 10;
33333965Sjdp      count += **type - '0';
33433965Sjdp      (*type)++;
33533965Sjdp    }
33633965Sjdp  return (count);
33733965Sjdp}
33833965Sjdp
33933965Sjdpint
34033965Sjdpcplus_demangle_opname (opname, result, options)
34133965Sjdp     const char *opname;
34233965Sjdp     char *result;
34333965Sjdp     int options;
34433965Sjdp{
34533965Sjdp  int len, i, len1, ret;
34633965Sjdp  string type;
34733965Sjdp  struct work_stuff work[1];
34833965Sjdp  const char *tem;
34933965Sjdp
35033965Sjdp  len = strlen(opname);
35133965Sjdp  result[0] = '\0';
35233965Sjdp  ret = 0;
35333965Sjdp  work->options = options;
35433965Sjdp
35533965Sjdp  if (opname[0] == '_' && opname[1] == '_'
35633965Sjdp      && opname[2] == 'o' && opname[3] == 'p')
35733965Sjdp    {
35833965Sjdp      /* ANSI.  */
35933965Sjdp      /* type conversion operator.  */
36033965Sjdp      tem = opname + 4;
36133965Sjdp      if (do_type (work, &tem, &type))
36233965Sjdp	{
36333965Sjdp	  strcat (result, "operator ");
36433965Sjdp	  strncat (result, type.b, type.p - type.b);
36533965Sjdp	  string_delete (&type);
36633965Sjdp	  ret = 1;
36733965Sjdp	}
36833965Sjdp    }
36933965Sjdp  else if (opname[0] == '_' && opname[1] == '_'
37033965Sjdp	   && opname[2] >= 'a' && opname[2] <= 'z'
37133965Sjdp	   && opname[3] >= 'a' && opname[3] <= 'z')
37233965Sjdp    {
37333965Sjdp      if (opname[4] == '\0')
37433965Sjdp	{
37533965Sjdp	  /* Operator.  */
37633965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
37733965Sjdp	    {
37833965Sjdp	      if (strlen (optable[i].in) == 2
37933965Sjdp		  && memcmp (optable[i].in, opname + 2, 2) == 0)
38033965Sjdp		{
38133965Sjdp		  strcat (result, "operator");
38233965Sjdp		  strcat (result, optable[i].out);
38333965Sjdp		  ret = 1;
38433965Sjdp		  break;
38533965Sjdp		}
38633965Sjdp	    }
38733965Sjdp	}
38833965Sjdp      else
38933965Sjdp	{
39033965Sjdp	  if (opname[2] == 'a' && opname[5] == '\0')
39133965Sjdp	    {
39233965Sjdp	      /* Assignment.  */
39333965Sjdp	      for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
39433965Sjdp		{
39533965Sjdp		  if (strlen (optable[i].in) == 3
39633965Sjdp		      && memcmp (optable[i].in, opname + 2, 3) == 0)
39733965Sjdp		    {
39833965Sjdp		      strcat (result, "operator");
39933965Sjdp		      strcat (result, optable[i].out);
40033965Sjdp		      ret = 1;
40133965Sjdp		      break;
40233965Sjdp		    }
40333965Sjdp		}
40433965Sjdp	    }
40533965Sjdp	}
40633965Sjdp    }
40733965Sjdp  else if (len >= 3
40833965Sjdp	   && opname[0] == 'o'
40933965Sjdp	   && opname[1] == 'p'
41033965Sjdp	   && strchr (cplus_markers, opname[2]) != NULL)
41133965Sjdp    {
41233965Sjdp      /* see if it's an assignment expression */
41333965Sjdp      if (len >= 10 /* op$assign_ */
41433965Sjdp	  && memcmp (opname + 3, "assign_", 7) == 0)
41533965Sjdp	{
41633965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
41733965Sjdp	    {
41833965Sjdp	      len1 = len - 10;
41933965Sjdp	      if (strlen (optable[i].in) == len1
42033965Sjdp		  && memcmp (optable[i].in, opname + 10, len1) == 0)
42133965Sjdp		{
42233965Sjdp		  strcat (result, "operator");
42333965Sjdp		  strcat (result, optable[i].out);
42433965Sjdp		  strcat (result, "=");
42533965Sjdp		  ret = 1;
42633965Sjdp		  break;
42733965Sjdp		}
42833965Sjdp	    }
42933965Sjdp	}
43033965Sjdp      else
43133965Sjdp	{
43233965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
43333965Sjdp	    {
43433965Sjdp	      len1 = len - 3;
43533965Sjdp	      if (strlen (optable[i].in) == len1
43633965Sjdp		  && memcmp (optable[i].in, opname + 3, len1) == 0)
43733965Sjdp		{
43833965Sjdp		  strcat (result, "operator");
43933965Sjdp		  strcat (result, optable[i].out);
44033965Sjdp		  ret = 1;
44133965Sjdp		  break;
44233965Sjdp		}
44333965Sjdp	    }
44433965Sjdp	}
44533965Sjdp    }
44633965Sjdp  else if (len >= 5 && memcmp (opname, "type", 4) == 0
44733965Sjdp	   && strchr (cplus_markers, opname[4]) != NULL)
44833965Sjdp    {
44933965Sjdp      /* type conversion operator */
45033965Sjdp      tem = opname + 5;
45133965Sjdp      if (do_type (work, &tem, &type))
45233965Sjdp	{
45333965Sjdp	  strcat (result, "operator ");
45433965Sjdp	  strncat (result, type.b, type.p - type.b);
45533965Sjdp	  string_delete (&type);
45633965Sjdp	  ret = 1;
45733965Sjdp	}
45833965Sjdp    }
45933965Sjdp  return ret;
46033965Sjdp
46133965Sjdp}
46233965Sjdp/* Takes operator name as e.g. "++" and returns mangled
46333965Sjdp   operator name (e.g. "postincrement_expr"), or NULL if not found.
46433965Sjdp
46533965Sjdp   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
46633965Sjdp   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
46733965Sjdp
46833965Sjdpconst char *
46933965Sjdpcplus_mangle_opname (opname, options)
47033965Sjdp     const char *opname;
47133965Sjdp     int options;
47233965Sjdp{
47333965Sjdp  int i;
47433965Sjdp  int len;
47533965Sjdp
47633965Sjdp  len = strlen (opname);
47733965Sjdp  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
47833965Sjdp    {
47933965Sjdp      if (strlen (optable[i].out) == len
48033965Sjdp	  && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
48133965Sjdp	  && memcmp (optable[i].out, opname, len) == 0)
48233965Sjdp	return optable[i].in;
48333965Sjdp    }
48433965Sjdp  return (0);
48533965Sjdp}
48633965Sjdp
48733965Sjdp/* char *cplus_demangle (const char *mangled, int options)
48833965Sjdp
48933965Sjdp   If MANGLED is a mangled function name produced by GNU C++, then
49033965Sjdp   a pointer to a malloced string giving a C++ representation
49133965Sjdp   of the name will be returned; otherwise NULL will be returned.
49233965Sjdp   It is the caller's responsibility to free the string which
49333965Sjdp   is returned.
49433965Sjdp
49533965Sjdp   The OPTIONS arg may contain one or more of the following bits:
49633965Sjdp
49733965Sjdp   	DMGL_ANSI	ANSI qualifiers such as `const' and `void' are
49833965Sjdp			included.
49933965Sjdp	DMGL_PARAMS	Function parameters are included.
50033965Sjdp
50133965Sjdp   For example,
50233965Sjdp
50333965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS)		=> "A::foo(int)"
50433965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)	=> "A::foo(int)"
50533965Sjdp   cplus_demangle ("foo__1Ai", 0)			=> "A::foo"
50633965Sjdp
50733965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS)		=> "A::foo(float,...)"
50833965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
50933965Sjdp   cplus_demangle ("foo__1Afe", 0)			=> "A::foo"
51033965Sjdp
51133965Sjdp   Note that any leading underscores, or other such characters prepended by
51233965Sjdp   the compilation system, are presumed to have already been stripped from
51333965Sjdp   MANGLED.  */
51433965Sjdp
51533965Sjdpchar *
51633965Sjdpcplus_demangle (mangled, options)
51733965Sjdp     const char *mangled;
51833965Sjdp     int options;
51933965Sjdp{
52033965Sjdp  string decl;
52133965Sjdp  int success = 0;
52233965Sjdp  struct work_stuff work[1];
52333965Sjdp  char *demangled = NULL;
52433965Sjdp
52533965Sjdp  if ((mangled != NULL) && (*mangled != '\0'))
52633965Sjdp    {
52733965Sjdp      memset ((char *) work, 0, sizeof (work));
52833965Sjdp      work -> options = options;
52933965Sjdp      if ((work->options & DMGL_STYLE_MASK) == 0)
53033965Sjdp	work->options |= (int)current_demangling_style & DMGL_STYLE_MASK;
53133965Sjdp
53233965Sjdp      string_init (&decl);
53333965Sjdp
53433965Sjdp      /* First check to see if gnu style demangling is active and if the
53533965Sjdp	 string to be demangled contains a CPLUS_MARKER.  If so, attempt to
53633965Sjdp	 recognize one of the gnu special forms rather than looking for a
53733965Sjdp	 standard prefix.  In particular, don't worry about whether there
53833965Sjdp	 is a "__" string in the mangled string.  Consider "_$_5__foo" for
53933965Sjdp	 example.  */
54033965Sjdp
54133965Sjdp      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
54233965Sjdp	{
54333965Sjdp	  success = gnu_special (work, &mangled, &decl);
54433965Sjdp	}
54533965Sjdp      if (!success)
54633965Sjdp	{
54733965Sjdp	  success = demangle_prefix (work, &mangled, &decl);
54833965Sjdp	}
54933965Sjdp      if (success && (*mangled != '\0'))
55033965Sjdp	{
55133965Sjdp	  success = demangle_signature (work, &mangled, &decl);
55233965Sjdp	}
55333965Sjdp      if (work->constructor == 2)
55433965Sjdp        {
55533965Sjdp          string_prepend(&decl, "global constructors keyed to ");
55633965Sjdp          work->constructor = 0;
55733965Sjdp        }
55833965Sjdp      else if (work->destructor == 2)
55933965Sjdp        {
56033965Sjdp          string_prepend(&decl, "global destructors keyed to ");
56133965Sjdp          work->destructor = 0;
56233965Sjdp        }
56333965Sjdp      demangled = mop_up (work, &decl, success);
56433965Sjdp    }
56533965Sjdp  return (demangled);
56633965Sjdp}
56733965Sjdp
56833965Sjdpstatic char *
56933965Sjdpmop_up (work, declp, success)
57033965Sjdp     struct work_stuff *work;
57133965Sjdp     string *declp;
57233965Sjdp     int success;
57333965Sjdp{
57433965Sjdp  char *demangled = NULL;
57533965Sjdp
57633965Sjdp  /* Discard the remembered types, if any.  */
57733965Sjdp
57833965Sjdp  forget_types (work);
57933965Sjdp  if (work -> typevec != NULL)
58033965Sjdp    {
58133965Sjdp      free ((char *) work -> typevec);
58233965Sjdp    }
58333965Sjdp
58433965Sjdp  /* If demangling was successful, ensure that the demangled string is null
58533965Sjdp     terminated and return it.  Otherwise, free the demangling decl.  */
58633965Sjdp
58733965Sjdp  if (!success)
58833965Sjdp    {
58933965Sjdp      string_delete (declp);
59033965Sjdp    }
59133965Sjdp  else
59233965Sjdp    {
59333965Sjdp      string_appendn (declp, "", 1);
59433965Sjdp      demangled = declp -> b;
59533965Sjdp    }
59633965Sjdp  return (demangled);
59733965Sjdp}
59833965Sjdp
59933965Sjdp/*
60033965Sjdp
60133965SjdpLOCAL FUNCTION
60233965Sjdp
60333965Sjdp	demangle_signature -- demangle the signature part of a mangled name
60433965Sjdp
60533965SjdpSYNOPSIS
60633965Sjdp
60733965Sjdp	static int
60833965Sjdp	demangle_signature (struct work_stuff *work, const char **mangled,
60933965Sjdp			    string *declp);
61033965Sjdp
61133965SjdpDESCRIPTION
61233965Sjdp
61333965Sjdp	Consume and demangle the signature portion of the mangled name.
61433965Sjdp
61533965Sjdp	DECLP is the string where demangled output is being built.  At
61633965Sjdp	entry it contains the demangled root name from the mangled name
61733965Sjdp	prefix.  I.E. either a demangled operator name or the root function
61833965Sjdp	name.  In some special cases, it may contain nothing.
61933965Sjdp
62033965Sjdp	*MANGLED points to the current unconsumed location in the mangled
62133965Sjdp	name.  As tokens are consumed and demangling is performed, the
62233965Sjdp	pointer is updated to continuously point at the next token to
62333965Sjdp	be consumed.
62433965Sjdp
62533965Sjdp	Demangling GNU style mangled names is nasty because there is no
62633965Sjdp	explicit token that marks the start of the outermost function
62733965Sjdp	argument list.  */
62833965Sjdp
62933965Sjdpstatic int
63033965Sjdpdemangle_signature (work, mangled, declp)
63133965Sjdp     struct work_stuff *work;
63233965Sjdp     const char **mangled;
63333965Sjdp     string *declp;
63433965Sjdp{
63533965Sjdp  int success = 1;
63633965Sjdp  int func_done = 0;
63733965Sjdp  int expect_func = 0;
63833965Sjdp  const char *oldmangled = NULL;
63933965Sjdp  string trawname;
64033965Sjdp  string tname;
64133965Sjdp
64233965Sjdp  while (success && (**mangled != '\0'))
64333965Sjdp    {
64433965Sjdp      switch (**mangled)
64533965Sjdp	{
64633965Sjdp	case 'Q':
64733965Sjdp	  oldmangled = *mangled;
64833965Sjdp	  success = demangle_qualified (work, mangled, declp, 1, 0);
64933965Sjdp	  if (success)
65033965Sjdp	    {
65133965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
65233965Sjdp	    }
65333965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
65433965Sjdp	    {
65533965Sjdp	      expect_func = 1;
65633965Sjdp	    }
65733965Sjdp	  oldmangled = NULL;
65833965Sjdp	  break;
65933965Sjdp
66033965Sjdp	case 'S':
66133965Sjdp	  /* Static member function */
66233965Sjdp	  if (oldmangled == NULL)
66333965Sjdp	    {
66433965Sjdp	      oldmangled = *mangled;
66533965Sjdp	    }
66633965Sjdp	  (*mangled)++;
66733965Sjdp	  work -> static_type = 1;
66833965Sjdp	  break;
66933965Sjdp
67033965Sjdp	case 'C':
67133965Sjdp	  /* a const member function */
67233965Sjdp	  if (oldmangled == NULL)
67333965Sjdp	    {
67433965Sjdp	      oldmangled = *mangled;
67533965Sjdp	    }
67633965Sjdp	  (*mangled)++;
67733965Sjdp	  work -> const_type = 1;
67833965Sjdp	  break;
67933965Sjdp
68033965Sjdp	case '0': case '1': case '2': case '3': case '4':
68133965Sjdp	case '5': case '6': case '7': case '8': case '9':
68233965Sjdp	  if (oldmangled == NULL)
68333965Sjdp	    {
68433965Sjdp	      oldmangled = *mangled;
68533965Sjdp	    }
68633965Sjdp	  success = demangle_class (work, mangled, declp);
68733965Sjdp	  if (success)
68833965Sjdp	    {
68933965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
69033965Sjdp	    }
69133965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
69233965Sjdp	    {
69333965Sjdp	      expect_func = 1;
69433965Sjdp	    }
69533965Sjdp	  oldmangled = NULL;
69633965Sjdp	  break;
69733965Sjdp
69833965Sjdp	case 'F':
69933965Sjdp	  /* Function */
70033965Sjdp	  /* ARM style demangling includes a specific 'F' character after
70133965Sjdp	     the class name.  For GNU style, it is just implied.  So we can
70233965Sjdp	     safely just consume any 'F' at this point and be compatible
70333965Sjdp	     with either style.  */
70433965Sjdp
70533965Sjdp	  oldmangled = NULL;
70633965Sjdp	  func_done = 1;
70733965Sjdp	  (*mangled)++;
70833965Sjdp
70933965Sjdp	  /* For lucid/ARM style we have to forget any types we might
71033965Sjdp	     have remembered up to this point, since they were not argument
71133965Sjdp	     types.  GNU style considers all types seen as available for
71233965Sjdp	     back references.  See comment in demangle_args() */
71333965Sjdp
71433965Sjdp	  if (LUCID_DEMANGLING || ARM_DEMANGLING)
71533965Sjdp	    {
71633965Sjdp	      forget_types (work);
71733965Sjdp	    }
71833965Sjdp	  success = demangle_args (work, mangled, declp);
71933965Sjdp	  break;
72033965Sjdp
72133965Sjdp	case 't':
72233965Sjdp	  /* G++ Template */
72333965Sjdp	  string_init(&trawname);
72433965Sjdp	  string_init(&tname);
72533965Sjdp	  if (oldmangled == NULL)
72633965Sjdp	    {
72733965Sjdp	      oldmangled = *mangled;
72833965Sjdp	    }
72933965Sjdp	  success = demangle_template (work, mangled, &tname, &trawname);
73033965Sjdp	  if (success)
73133965Sjdp	    {
73233965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
73333965Sjdp	    }
73433965Sjdp	  string_append(&tname, "::");
73533965Sjdp	  string_prepends(declp, &tname);
73633965Sjdp	  if (work -> destructor & 1)
73733965Sjdp	    {
73833965Sjdp	      string_prepend (&trawname, "~");
73933965Sjdp	      string_appends (declp, &trawname);
74033965Sjdp	      work->destructor -= 1;
74133965Sjdp	    }
74233965Sjdp	  if ((work->constructor & 1) || (work->destructor & 1))
74333965Sjdp	    {
74433965Sjdp	      string_appends (declp, &trawname);
74533965Sjdp	      work->constructor -= 1;
74633965Sjdp	    }
74733965Sjdp	  string_delete(&trawname);
74833965Sjdp	  string_delete(&tname);
74933965Sjdp	  oldmangled = NULL;
75033965Sjdp	  expect_func = 1;
75133965Sjdp	  break;
75233965Sjdp
75333965Sjdp	case '_':
75433965Sjdp	  /* At the outermost level, we cannot have a return type specified,
75533965Sjdp	     so if we run into another '_' at this point we are dealing with
75633965Sjdp	     a mangled name that is either bogus, or has been mangled by
75733965Sjdp	     some algorithm we don't know how to deal with.  So just
75833965Sjdp	     reject the entire demangling.  */
75933965Sjdp	  success = 0;
76033965Sjdp	  break;
76133965Sjdp
76233965Sjdp	default:
76333965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
76433965Sjdp	    {
76533965Sjdp	      /* Assume we have stumbled onto the first outermost function
76633965Sjdp		 argument token, and start processing args.  */
76733965Sjdp	      func_done = 1;
76833965Sjdp	      success = demangle_args (work, mangled, declp);
76933965Sjdp	    }
77033965Sjdp	  else
77133965Sjdp	    {
77233965Sjdp	      /* Non-GNU demanglers use a specific token to mark the start
77333965Sjdp		 of the outermost function argument tokens.  Typically 'F',
77433965Sjdp		 for ARM-demangling, for example.  So if we find something
77533965Sjdp		 we are not prepared for, it must be an error.  */
77633965Sjdp	      success = 0;
77733965Sjdp	    }
77833965Sjdp	  break;
77933965Sjdp	}
78033965Sjdp      /*
78133965Sjdp	if (AUTO_DEMANGLING || GNU_DEMANGLING)
78233965Sjdp	*/
78333965Sjdp      {
78433965Sjdp	if (success && expect_func)
78533965Sjdp	  {
78633965Sjdp	    func_done = 1;
78733965Sjdp	    success = demangle_args (work, mangled, declp);
78833965Sjdp	  }
78933965Sjdp      }
79033965Sjdp    }
79133965Sjdp  if (success && !func_done)
79233965Sjdp    {
79333965Sjdp      if (AUTO_DEMANGLING || GNU_DEMANGLING)
79433965Sjdp	{
79533965Sjdp	  /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
79633965Sjdp	     bar__3fooi is 'foo::bar(int)'.  We get here when we find the
79733965Sjdp	     first case, and need to ensure that the '(void)' gets added to
79833965Sjdp	     the current declp.  Note that with ARM, the first case
79933965Sjdp	     represents the name of a static data member 'foo::bar',
80033965Sjdp	     which is in the current declp, so we leave it alone.  */
80133965Sjdp	  success = demangle_args (work, mangled, declp);
80233965Sjdp	}
80333965Sjdp    }
80433965Sjdp  if (success && work -> static_type && PRINT_ARG_TYPES)
80533965Sjdp    {
80633965Sjdp      string_append (declp, " static");
80733965Sjdp    }
80833965Sjdp  if (success && work -> const_type && PRINT_ARG_TYPES)
80933965Sjdp    {
81033965Sjdp      string_append (declp, " const");
81133965Sjdp    }
81233965Sjdp  return (success);
81333965Sjdp}
81433965Sjdp
81533965Sjdp#if 0
81633965Sjdp
81733965Sjdpstatic int
81833965Sjdpdemangle_method_args (work, mangled, declp)
81933965Sjdp     struct work_stuff *work;
82033965Sjdp     const char **mangled;
82133965Sjdp     string *declp;
82233965Sjdp{
82333965Sjdp  int success = 0;
82433965Sjdp
82533965Sjdp  if (work -> static_type)
82633965Sjdp    {
82733965Sjdp      string_append (declp, *mangled + 1);
82833965Sjdp      *mangled += strlen (*mangled);
82933965Sjdp      success = 1;
83033965Sjdp    }
83133965Sjdp  else
83233965Sjdp    {
83333965Sjdp      success = demangle_args (work, mangled, declp);
83433965Sjdp    }
83533965Sjdp  return (success);
83633965Sjdp}
83733965Sjdp
83833965Sjdp#endif
83933965Sjdp
84033965Sjdpstatic int
84133965Sjdpdemangle_template (work, mangled, tname, trawname)
84233965Sjdp     struct work_stuff *work;
84333965Sjdp     const char **mangled;
84433965Sjdp     string *tname;
84533965Sjdp     string *trawname;
84633965Sjdp{
84733965Sjdp  int i;
84833965Sjdp  int is_pointer;
84933965Sjdp  int is_real;
85033965Sjdp  int is_integral;
85133965Sjdp  int is_char;
85233965Sjdp  int is_bool;
85333965Sjdp  int r;
85433965Sjdp  int need_comma = 0;
85533965Sjdp  int success = 0;
85633965Sjdp  int done;
85733965Sjdp  const char *old_p;
85833965Sjdp  const char *start;
85933965Sjdp  int symbol_len;
86033965Sjdp  string temp;
86133965Sjdp
86233965Sjdp  (*mangled)++;
86333965Sjdp  start = *mangled;
86433965Sjdp  /* get template name */
86533965Sjdp  if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
86633965Sjdp    {
86733965Sjdp      return (0);
86833965Sjdp    }
86933965Sjdp  if (trawname)
87033965Sjdp    string_appendn (trawname, *mangled, r);
87133965Sjdp  string_appendn (tname, *mangled, r);
87233965Sjdp  *mangled += r;
87333965Sjdp  string_append (tname, "<");
87433965Sjdp  /* get size of template parameter list */
87533965Sjdp  if (!get_count (mangled, &r))
87633965Sjdp    {
87733965Sjdp      return (0);
87833965Sjdp    }
87933965Sjdp  for (i = 0; i < r; i++)
88033965Sjdp    {
88133965Sjdp      if (need_comma)
88233965Sjdp	{
88333965Sjdp	  string_append (tname, ", ");
88433965Sjdp	}
88533965Sjdp      /* Z for type parameters */
88633965Sjdp      if (**mangled == 'Z')
88733965Sjdp	{
88833965Sjdp	  (*mangled)++;
88933965Sjdp	  /* temp is initialized in do_type */
89033965Sjdp	  success = do_type (work, mangled, &temp);
89133965Sjdp	  if (success)
89233965Sjdp	    {
89333965Sjdp	      string_appends (tname, &temp);
89433965Sjdp	    }
89533965Sjdp	  string_delete(&temp);
89633965Sjdp	  if (!success)
89733965Sjdp	    {
89833965Sjdp	      break;
89933965Sjdp	    }
90033965Sjdp	}
90133965Sjdp      else
90233965Sjdp	{
90333965Sjdp	  /* otherwise, value parameter */
90433965Sjdp	  old_p  = *mangled;
90533965Sjdp	  is_pointer = 0;
90633965Sjdp	  is_real = 0;
90733965Sjdp	  is_integral = 0;
90833965Sjdp          is_char = 0;
90933965Sjdp	  is_bool = 0;
91033965Sjdp	  done = 0;
91133965Sjdp	  /* temp is initialized in do_type */
91233965Sjdp	  success = do_type (work, mangled, &temp);
91333965Sjdp	  /*
91433965Sjdp	    if (success)
91533965Sjdp	    {
91633965Sjdp	    string_appends (tname, &temp);
91733965Sjdp	    }
91833965Sjdp	    */
91933965Sjdp	  string_delete(&temp);
92033965Sjdp	  if (!success)
92133965Sjdp	    {
92233965Sjdp	      break;
92333965Sjdp	    }
92433965Sjdp	  /*
92533965Sjdp	    string_append (tname, "=");
92633965Sjdp	    */
92733965Sjdp	  while (*old_p && !done)
92833965Sjdp	    {
92933965Sjdp	      switch (*old_p)
93033965Sjdp		{
93133965Sjdp		case 'P':
93233965Sjdp		case 'p':
93333965Sjdp		case 'R':
93433965Sjdp		  done = is_pointer = 1;
93533965Sjdp		  break;
93633965Sjdp		case 'C':	/* const */
93733965Sjdp		case 'S':	/* explicitly signed [char] */
93833965Sjdp		case 'U':	/* unsigned */
93933965Sjdp		case 'V':	/* volatile */
94033965Sjdp		case 'F':	/* function */
94133965Sjdp		case 'M':	/* member function */
94233965Sjdp		case 'O':	/* ??? */
94333965Sjdp		  old_p++;
94433965Sjdp		  continue;
94533965Sjdp		case 'Q':	/* qualified name */
94633965Sjdp		  done = is_integral = 1;
94733965Sjdp		  break;
94833965Sjdp		case 'T':	/* remembered type */
94933965Sjdp		  abort ();
95033965Sjdp		  break;
95133965Sjdp		case 'v':	/* void */
95233965Sjdp		  abort ();
95333965Sjdp		  break;
95433965Sjdp		case 'x':	/* long long */
95533965Sjdp		case 'l':	/* long */
95633965Sjdp		case 'i':	/* int */
95733965Sjdp		case 's':	/* short */
95833965Sjdp		case 'w':	/* wchar_t */
95933965Sjdp		  done = is_integral = 1;
96033965Sjdp		  break;
96133965Sjdp		case 'b':	/* bool */
96233965Sjdp		  done = is_bool = 1;
96333965Sjdp		  break;
96433965Sjdp		case 'c':	/* char */
96533965Sjdp		  done = is_char = 1;
96633965Sjdp		  break;
96733965Sjdp		case 'r':	/* long double */
96833965Sjdp		case 'd':	/* double */
96933965Sjdp		case 'f':	/* float */
97033965Sjdp		  done = is_real = 1;
97133965Sjdp		  break;
97233965Sjdp		default:
97333965Sjdp		  /* it's probably user defined type, let's assume
97433965Sjdp		     it's integral, it seems hard to figure out
97533965Sjdp		     what it really is */
97633965Sjdp		  done = is_integral = 1;
97733965Sjdp		}
97833965Sjdp	    }
97933965Sjdp	  if (is_integral)
98033965Sjdp	    {
98133965Sjdp	      if (**mangled == 'm')
98233965Sjdp		{
98333965Sjdp		  string_appendn (tname, "-", 1);
98433965Sjdp		  (*mangled)++;
98533965Sjdp		}
98633965Sjdp	      while (isdigit (**mangled))
98733965Sjdp		{
98833965Sjdp		  string_appendn (tname, *mangled, 1);
98933965Sjdp		  (*mangled)++;
99033965Sjdp		}
99133965Sjdp	    }
99233965Sjdp	  else if (is_char)
99333965Sjdp	    {
99433965Sjdp	      char tmp[2];
99533965Sjdp	      int val;
99633965Sjdp              if (**mangled == 'm')
99733965Sjdp                {
99833965Sjdp                  string_appendn (tname, "-", 1);
99933965Sjdp                  (*mangled)++;
100033965Sjdp                }
100133965Sjdp	      string_appendn (tname, "'", 1);
100233965Sjdp              val = consume_count(mangled);
100333965Sjdp	      if (val == 0)
100433965Sjdp		{
100533965Sjdp		  success = 0;
100633965Sjdp		  break;
100733965Sjdp                }
100833965Sjdp              tmp[0] = (char)val;
100933965Sjdp              tmp[1] = '\0';
101033965Sjdp              string_appendn (tname, &tmp[0], 1);
101133965Sjdp	      string_appendn (tname, "'", 1);
101233965Sjdp	    }
101333965Sjdp	  else if (is_bool)
101433965Sjdp	    {
101533965Sjdp	      int val = consume_count (mangled);
101633965Sjdp	      if (val == 0)
101733965Sjdp		string_appendn (tname, "false", 5);
101833965Sjdp	      else if (val == 1)
101933965Sjdp		string_appendn (tname, "true", 4);
102033965Sjdp	      else
102133965Sjdp		success = 0;
102233965Sjdp	    }
102333965Sjdp	  else if (is_real)
102433965Sjdp	    {
102533965Sjdp	      if (**mangled == 'm')
102633965Sjdp		{
102733965Sjdp		  string_appendn (tname, "-", 1);
102833965Sjdp		  (*mangled)++;
102933965Sjdp		}
103033965Sjdp	      while (isdigit (**mangled))
103133965Sjdp		{
103233965Sjdp		  string_appendn (tname, *mangled, 1);
103333965Sjdp		  (*mangled)++;
103433965Sjdp		}
103533965Sjdp	      if (**mangled == '.') /* fraction */
103633965Sjdp		{
103733965Sjdp		  string_appendn (tname, ".", 1);
103833965Sjdp		  (*mangled)++;
103933965Sjdp		  while (isdigit (**mangled))
104033965Sjdp		    {
104133965Sjdp		      string_appendn (tname, *mangled, 1);
104233965Sjdp		      (*mangled)++;
104333965Sjdp		    }
104433965Sjdp		}
104533965Sjdp	      if (**mangled == 'e') /* exponent */
104633965Sjdp		{
104733965Sjdp		  string_appendn (tname, "e", 1);
104833965Sjdp		  (*mangled)++;
104933965Sjdp		  while (isdigit (**mangled))
105033965Sjdp		    {
105133965Sjdp		      string_appendn (tname, *mangled, 1);
105233965Sjdp		      (*mangled)++;
105333965Sjdp		    }
105433965Sjdp		}
105533965Sjdp	    }
105633965Sjdp	  else if (is_pointer)
105733965Sjdp	    {
105833965Sjdp	      symbol_len = consume_count (mangled);
105933965Sjdp	      if (symbol_len == 0)
106033965Sjdp		{
106133965Sjdp		  success = 0;
106233965Sjdp		  break;
106333965Sjdp		}
106433965Sjdp	      if (symbol_len == 0)
106533965Sjdp		string_appendn (tname, "0", 1);
106633965Sjdp	      else
106733965Sjdp		{
106833965Sjdp		  char *p = xmalloc (symbol_len + 1), *q;
106933965Sjdp		  strncpy (p, *mangled, symbol_len);
107033965Sjdp		  p [symbol_len] = '\0';
107133965Sjdp		  q = cplus_demangle (p, work->options);
107233965Sjdp		  string_appendn (tname, "&", 1);
107333965Sjdp		  if (q)
107433965Sjdp		    {
107533965Sjdp		      string_append (tname, q);
107633965Sjdp		      free (q);
107733965Sjdp		    }
107833965Sjdp		  else
107933965Sjdp		    string_append (tname, p);
108033965Sjdp		  free (p);
108133965Sjdp		}
108233965Sjdp	      *mangled += symbol_len;
108333965Sjdp	    }
108433965Sjdp	}
108533965Sjdp      need_comma = 1;
108633965Sjdp    }
108733965Sjdp  if (tname->p[-1] == '>')
108833965Sjdp    string_append (tname, " ");
108933965Sjdp  string_append (tname, ">");
109033965Sjdp
109133965Sjdp  /*
109233965Sjdp    if (work -> static_type)
109333965Sjdp    {
109433965Sjdp    string_append (declp, *mangled + 1);
109533965Sjdp    *mangled += strlen (*mangled);
109633965Sjdp    success = 1;
109733965Sjdp    }
109833965Sjdp    else
109933965Sjdp    {
110033965Sjdp    success = demangle_args (work, mangled, declp);
110133965Sjdp    }
110233965Sjdp    }
110333965Sjdp    */
110433965Sjdp  return (success);
110533965Sjdp}
110633965Sjdp
110733965Sjdpstatic int
110833965Sjdparm_pt (work, mangled, n, anchor, args)
110933965Sjdp     struct work_stuff *work;
111033965Sjdp     const char *mangled;
111133965Sjdp     int n;
111233965Sjdp     const char **anchor, **args;
111333965Sjdp{
111433965Sjdp  /* ARM template? */
111533965Sjdp  if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__")))
111633965Sjdp    {
111733965Sjdp      int len;
111833965Sjdp      *args = *anchor + 6;
111933965Sjdp      len = consume_count (args);
112033965Sjdp      if (*args + len == mangled + n && **args == '_')
112133965Sjdp	{
112233965Sjdp	  ++*args;
112333965Sjdp	  return 1;
112433965Sjdp	}
112533965Sjdp    }
112633965Sjdp  return 0;
112733965Sjdp}
112833965Sjdp
112933965Sjdpstatic void
113033965Sjdpdemangle_arm_pt (work, mangled, n, declp)
113133965Sjdp     struct work_stuff *work;
113233965Sjdp     const char **mangled;
113333965Sjdp     int n;
113433965Sjdp     string *declp;
113533965Sjdp{
113633965Sjdp  const char *p;
113733965Sjdp  const char *args;
113833965Sjdp  const char *e = *mangled + n;
113933965Sjdp
114033965Sjdp  /* ARM template? */
114133965Sjdp  if (arm_pt (work, *mangled, n, &p, &args))
114233965Sjdp    {
114333965Sjdp      string arg;
114433965Sjdp      string_init (&arg);
114533965Sjdp      string_appendn (declp, *mangled, p - *mangled);
114633965Sjdp      string_append (declp, "<");
114733965Sjdp      /* should do error checking here */
114833965Sjdp      while (args < e) {
114933965Sjdp	string_clear (&arg);
115033965Sjdp	do_type (work, &args, &arg);
115133965Sjdp	string_appends (declp, &arg);
115233965Sjdp	string_append (declp, ",");
115333965Sjdp      }
115433965Sjdp      string_delete (&arg);
115533965Sjdp      --declp->p;
115633965Sjdp      string_append (declp, ">");
115733965Sjdp    }
115833965Sjdp  else
115933965Sjdp    {
116033965Sjdp      string_appendn (declp, *mangled, n);
116133965Sjdp    }
116233965Sjdp  *mangled += n;
116333965Sjdp}
116433965Sjdp
116533965Sjdpstatic int
116633965Sjdpdemangle_class_name (work, mangled, declp)
116733965Sjdp     struct work_stuff *work;
116833965Sjdp     const char **mangled;
116933965Sjdp     string *declp;
117033965Sjdp{
117133965Sjdp  int n;
117233965Sjdp  int success = 0;
117333965Sjdp
117433965Sjdp  n = consume_count (mangled);
117533965Sjdp  if (strlen (*mangled) >= n)
117633965Sjdp    {
117733965Sjdp      demangle_arm_pt (work, mangled, n, declp);
117833965Sjdp      success = 1;
117933965Sjdp    }
118033965Sjdp
118133965Sjdp  return (success);
118233965Sjdp}
118333965Sjdp
118433965Sjdp/*
118533965Sjdp
118633965SjdpLOCAL FUNCTION
118733965Sjdp
118833965Sjdp	demangle_class -- demangle a mangled class sequence
118933965Sjdp
119033965SjdpSYNOPSIS
119133965Sjdp
119233965Sjdp	static int
119333965Sjdp	demangle_class (struct work_stuff *work, const char **mangled,
119433965Sjdp			strint *declp)
119533965Sjdp
119633965SjdpDESCRIPTION
119733965Sjdp
119833965Sjdp	DECLP points to the buffer into which demangling is being done.
119933965Sjdp
120033965Sjdp	*MANGLED points to the current token to be demangled.  On input,
120133965Sjdp	it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
120233965Sjdp	On exit, it points to the next token after the mangled class on
120333965Sjdp	success, or the first unconsumed token on failure.
120433965Sjdp
120533965Sjdp	If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
120633965Sjdp	we are demangling a constructor or destructor.  In this case
120733965Sjdp	we prepend "class::class" or "class::~class" to DECLP.
120833965Sjdp
120933965Sjdp	Otherwise, we prepend "class::" to the current DECLP.
121033965Sjdp
121133965Sjdp	Reset the constructor/destructor flags once they have been
121233965Sjdp	"consumed".  This allows demangle_class to be called later during
121333965Sjdp	the same demangling, to do normal class demangling.
121433965Sjdp
121533965Sjdp	Returns 1 if demangling is successful, 0 otherwise.
121633965Sjdp
121733965Sjdp*/
121833965Sjdp
121933965Sjdpstatic int
122033965Sjdpdemangle_class (work, mangled, declp)
122133965Sjdp     struct work_stuff *work;
122233965Sjdp     const char **mangled;
122333965Sjdp     string *declp;
122433965Sjdp{
122533965Sjdp  int success = 0;
122633965Sjdp  string class_name;
122733965Sjdp
122833965Sjdp  string_init (&class_name);
122933965Sjdp  if (demangle_class_name (work, mangled, &class_name))
123033965Sjdp    {
123133965Sjdp      if ((work->constructor & 1) || (work->destructor & 1))
123233965Sjdp	{
123333965Sjdp	  string_prepends (declp, &class_name);
123433965Sjdp	  if (work -> destructor & 1)
123533965Sjdp	    {
123633965Sjdp	      string_prepend (declp, "~");
123733965Sjdp              work -> destructor -= 1;
123833965Sjdp	    }
123933965Sjdp	  else
124033965Sjdp	    {
124133965Sjdp	      work -> constructor -= 1;
124233965Sjdp	    }
124333965Sjdp	}
124433965Sjdp      string_prepend (declp, "::");
124533965Sjdp      string_prepends (declp, &class_name);
124633965Sjdp      success = 1;
124733965Sjdp    }
124833965Sjdp  string_delete (&class_name);
124933965Sjdp  return (success);
125033965Sjdp}
125133965Sjdp
125233965Sjdp/*
125333965Sjdp
125433965SjdpLOCAL FUNCTION
125533965Sjdp
125633965Sjdp	demangle_prefix -- consume the mangled name prefix and find signature
125733965Sjdp
125833965SjdpSYNOPSIS
125933965Sjdp
126033965Sjdp	static int
126133965Sjdp	demangle_prefix (struct work_stuff *work, const char **mangled,
126233965Sjdp			 string *declp);
126333965Sjdp
126433965SjdpDESCRIPTION
126533965Sjdp
126633965Sjdp	Consume and demangle the prefix of the mangled name.
126733965Sjdp
126833965Sjdp	DECLP points to the string buffer into which demangled output is
126933965Sjdp	placed.  On entry, the buffer is empty.  On exit it contains
127033965Sjdp	the root function name, the demangled operator name, or in some
127133965Sjdp	special cases either nothing or the completely demangled result.
127233965Sjdp
127333965Sjdp	MANGLED points to the current pointer into the mangled name.  As each
127433965Sjdp	token of the mangled name is consumed, it is updated.  Upon entry
127533965Sjdp	the current mangled name pointer points to the first character of
127633965Sjdp	the mangled name.  Upon exit, it should point to the first character
127733965Sjdp	of the signature if demangling was successful, or to the first
127833965Sjdp	unconsumed character if demangling of the prefix was unsuccessful.
127933965Sjdp
128033965Sjdp	Returns 1 on success, 0 otherwise.
128133965Sjdp */
128233965Sjdp
128333965Sjdpstatic int
128433965Sjdpdemangle_prefix (work, mangled, declp)
128533965Sjdp     struct work_stuff *work;
128633965Sjdp     const char **mangled;
128733965Sjdp     string *declp;
128833965Sjdp{
128933965Sjdp  int success = 1;
129033965Sjdp  const char *scan;
129133965Sjdp  int i;
129233965Sjdp
129333965Sjdp  if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
129433965Sjdp    {
129533965Sjdp      char *marker = strchr (cplus_markers, (*mangled)[8]);
129633965Sjdp      if (marker != NULL && *marker == (*mangled)[10])
129733965Sjdp	{
129833965Sjdp	  if ((*mangled)[9] == 'D')
129933965Sjdp	    {
130033965Sjdp	      /* it's a GNU global destructor to be executed at program exit */
130133965Sjdp	      (*mangled) += 11;
130233965Sjdp	      work->destructor = 2;
130333965Sjdp	      if (gnu_special (work, mangled, declp))
130433965Sjdp		return success;
130533965Sjdp	    }
130633965Sjdp	  else if ((*mangled)[9] == 'I')
130733965Sjdp	    {
130833965Sjdp	      /* it's a GNU global constructor to be executed at program init */
130933965Sjdp	      (*mangled) += 11;
131033965Sjdp	      work->constructor = 2;
131133965Sjdp	      if (gnu_special (work, mangled, declp))
131233965Sjdp		return success;
131333965Sjdp	    }
131433965Sjdp	}
131533965Sjdp    }
131633965Sjdp  else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0)
131733965Sjdp    {
131833965Sjdp      /* it's a ARM global destructor to be executed at program exit */
131933965Sjdp      (*mangled) += 7;
132033965Sjdp      work->destructor = 2;
132133965Sjdp    }
132233965Sjdp  else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0)
132333965Sjdp    {
132433965Sjdp      /* it's a ARM global constructor to be executed at program initial */
132533965Sjdp      (*mangled) += 7;
132633965Sjdp      work->constructor = 2;
132733965Sjdp    }
132833965Sjdp
132933965Sjdp  /*  This block of code is a reduction in strength time optimization
133033965Sjdp      of:
133133965Sjdp      scan = mystrstr (*mangled, "__"); */
133233965Sjdp
133333965Sjdp  {
133433965Sjdp    scan = *mangled;
133533965Sjdp
133633965Sjdp    do {
133733965Sjdp      scan = strchr (scan, '_');
133833965Sjdp    } while (scan != NULL && *++scan != '_');
133933965Sjdp
134033965Sjdp    if (scan != NULL) --scan;
134133965Sjdp  }
134233965Sjdp
134333965Sjdp  if (scan != NULL)
134433965Sjdp    {
134533965Sjdp      /* We found a sequence of two or more '_', ensure that we start at
134633965Sjdp	 the last pair in the sequence.  */
134733965Sjdp      i = strspn (scan, "_");
134833965Sjdp      if (i > 2)
134933965Sjdp	{
135033965Sjdp	  scan += (i - 2);
135133965Sjdp	}
135233965Sjdp    }
135333965Sjdp
135433965Sjdp  if (scan == NULL)
135533965Sjdp    {
135633965Sjdp      success = 0;
135733965Sjdp    }
135833965Sjdp  else if (work -> static_type)
135933965Sjdp    {
136033965Sjdp      if (!isdigit (scan[0]) && (scan[0] != 't'))
136133965Sjdp	{
136233965Sjdp	  success = 0;
136333965Sjdp	}
136433965Sjdp    }
136533965Sjdp  else if ((scan == *mangled) &&
136633965Sjdp	   (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
136733965Sjdp    {
136833965Sjdp      /* The ARM says nothing about the mangling of local variables.
136933965Sjdp	 But cfront mangles local variables by prepending __<nesting_level>
137033965Sjdp	 to them. As an extension to ARM demangling we handle this case.  */
137133965Sjdp      if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2]))
137233965Sjdp	{
137333965Sjdp	  *mangled = scan + 2;
137433965Sjdp	  consume_count (mangled);
137533965Sjdp	  string_append (declp, *mangled);
137633965Sjdp	  *mangled += strlen (*mangled);
137733965Sjdp	  success = 1;
137833965Sjdp	}
137933965Sjdp      else
138033965Sjdp	{
138133965Sjdp	  /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
138233965Sjdp	     names like __Q2_3foo3bar for nested type names.  So don't accept
138333965Sjdp	     this style of constructor for cfront demangling.  */
138433965Sjdp	  if (!(LUCID_DEMANGLING || ARM_DEMANGLING))
138533965Sjdp	    work -> constructor += 1;
138633965Sjdp	  *mangled = scan + 2;
138733965Sjdp	}
138833965Sjdp    }
138933965Sjdp  else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't'))
139033965Sjdp    {
139133965Sjdp      /* Mangled name starts with "__".  Skip over any leading '_' characters,
139233965Sjdp	 then find the next "__" that separates the prefix from the signature.
139333965Sjdp	 */
139433965Sjdp      if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
139533965Sjdp	  || (arm_special (work, mangled, declp) == 0))
139633965Sjdp	{
139733965Sjdp	  while (*scan == '_')
139833965Sjdp	    {
139933965Sjdp	      scan++;
140033965Sjdp	    }
140133965Sjdp	  if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
140233965Sjdp	    {
140333965Sjdp	      /* No separator (I.E. "__not_mangled"), or empty signature
140433965Sjdp		 (I.E. "__not_mangled_either__") */
140533965Sjdp	      success = 0;
140633965Sjdp	    }
140733965Sjdp	  else
140833965Sjdp	    {
140933965Sjdp	      demangle_function_name (work, mangled, declp, scan);
141033965Sjdp	    }
141133965Sjdp	}
141233965Sjdp    }
141333965Sjdp  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
141433965Sjdp    {
141533965Sjdp      /* Cfront-style parameterized type.  Handled later as a signature.  */
141633965Sjdp      success = 1;
141733965Sjdp
141833965Sjdp      /* ARM template? */
141933965Sjdp      demangle_arm_pt (work, mangled, strlen (*mangled), declp);
142033965Sjdp    }
142133965Sjdp  else if (*(scan + 2) != '\0')
142233965Sjdp    {
142333965Sjdp      /* Mangled name does not start with "__" but does have one somewhere
142433965Sjdp	 in there with non empty stuff after it.  Looks like a global
142533965Sjdp	 function name.  */
142633965Sjdp      demangle_function_name (work, mangled, declp, scan);
142733965Sjdp    }
142833965Sjdp  else
142933965Sjdp    {
143033965Sjdp      /* Doesn't look like a mangled name */
143133965Sjdp      success = 0;
143233965Sjdp    }
143333965Sjdp
143433965Sjdp  if (!success && (work->constructor == 2 || work->destructor == 2))
143533965Sjdp    {
143633965Sjdp      string_append (declp, *mangled);
143733965Sjdp      *mangled += strlen (*mangled);
143833965Sjdp      success = 1;
143933965Sjdp    }
144033965Sjdp  return (success);
144133965Sjdp}
144233965Sjdp
144333965Sjdp/*
144433965Sjdp
144533965SjdpLOCAL FUNCTION
144633965Sjdp
144733965Sjdp	gnu_special -- special handling of gnu mangled strings
144833965Sjdp
144933965SjdpSYNOPSIS
145033965Sjdp
145133965Sjdp	static int
145233965Sjdp	gnu_special (struct work_stuff *work, const char **mangled,
145333965Sjdp		     string *declp);
145433965Sjdp
145533965Sjdp
145633965SjdpDESCRIPTION
145733965Sjdp
145833965Sjdp	Process some special GNU style mangling forms that don't fit
145933965Sjdp	the normal pattern.  For example:
146033965Sjdp
146133965Sjdp		_$_3foo		(destructor for class foo)
146233965Sjdp		_vt$foo		(foo virtual table)
146333965Sjdp		_vt$foo$bar	(foo::bar virtual table)
146433965Sjdp		__vt_foo	(foo virtual table, new style with thunks)
146533965Sjdp		_3foo$varname	(static data member)
146633965Sjdp		_Q22rs2tu$vw	(static data member)
146733965Sjdp		__t6vector1Zii	(constructor with template)
146833965Sjdp		__thunk_4__$_7ostream (virtual function thunk)
146933965Sjdp */
147033965Sjdp
147133965Sjdpstatic int
147233965Sjdpgnu_special (work, mangled, declp)
147333965Sjdp     struct work_stuff *work;
147433965Sjdp     const char **mangled;
147533965Sjdp     string *declp;
147633965Sjdp{
147733965Sjdp  int n;
147833965Sjdp  int success = 1;
147933965Sjdp  const char *p;
148033965Sjdp
148133965Sjdp  if ((*mangled)[0] == '_'
148233965Sjdp      && strchr (cplus_markers, (*mangled)[1]) != NULL
148333965Sjdp      && (*mangled)[2] == '_')
148433965Sjdp    {
148533965Sjdp      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
148633965Sjdp      (*mangled) += 3;
148733965Sjdp      work -> destructor += 1;
148833965Sjdp    }
148933965Sjdp  else if ((*mangled)[0] == '_'
149033965Sjdp	   && (((*mangled)[1] == '_'
149133965Sjdp		&& (*mangled)[2] == 'v'
149233965Sjdp		&& (*mangled)[3] == 't'
149333965Sjdp		&& (*mangled)[4] == '_')
149433965Sjdp	       || ((*mangled)[1] == 'v'
149533965Sjdp		   && (*mangled)[2] == 't'
149633965Sjdp		   && strchr (cplus_markers, (*mangled)[3]) != NULL)))
149733965Sjdp    {
149833965Sjdp      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
149933965Sjdp         and create the decl.  Note that we consume the entire mangled
150033965Sjdp	 input string, which means that demangle_signature has no work
150133965Sjdp	 to do.  */
150233965Sjdp      if ((*mangled)[2] == 'v')
150333965Sjdp	(*mangled) += 5; /* New style, with thunks: "__vt_" */
150433965Sjdp      else
150533965Sjdp	(*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
150633965Sjdp      while (**mangled != '\0')
150733965Sjdp	{
150833965Sjdp	  p = strpbrk (*mangled, cplus_markers);
150933965Sjdp	  switch (**mangled)
151033965Sjdp	    {
151133965Sjdp	    case 'Q':
151233965Sjdp	      success = demangle_qualified (work, mangled, declp, 0, 1);
151333965Sjdp	      break;
151433965Sjdp	    case 't':
151533965Sjdp	      success = demangle_template (work, mangled, declp, 0);
151633965Sjdp	      break;
151733965Sjdp	    default:
151833965Sjdp	      if (isdigit(*mangled[0]))
151933965Sjdp		{
152033965Sjdp		  n = consume_count(mangled);
152133965Sjdp		}
152233965Sjdp	      else
152333965Sjdp		{
152433965Sjdp		  n = strcspn (*mangled, cplus_markers);
152533965Sjdp		}
152633965Sjdp	      string_appendn (declp, *mangled, n);
152733965Sjdp	      (*mangled) += n;
152833965Sjdp	    }
152933965Sjdp
153033965Sjdp	  if (success && ((p == NULL) || (p == *mangled)))
153133965Sjdp	    {
153233965Sjdp	      if (p != NULL)
153333965Sjdp		{
153433965Sjdp		  string_append (declp, "::");
153533965Sjdp		  (*mangled)++;
153633965Sjdp		}
153733965Sjdp	    }
153833965Sjdp	  else
153933965Sjdp	    {
154033965Sjdp	      success = 0;
154133965Sjdp	      break;
154233965Sjdp	    }
154333965Sjdp	}
154433965Sjdp      if (success)
154533965Sjdp	string_append (declp, " virtual table");
154633965Sjdp    }
154733965Sjdp  else if ((*mangled)[0] == '_'
154833965Sjdp	   && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
154933965Sjdp	   && (p = strpbrk (*mangled, cplus_markers)) != NULL)
155033965Sjdp    {
155133965Sjdp      /* static data member, "_3foo$varname" for example */
155233965Sjdp      (*mangled)++;
155333965Sjdp      switch (**mangled)
155433965Sjdp	{
155533965Sjdp	case 'Q':
155633965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
155733965Sjdp	  break;
155833965Sjdp	case 't':
155933965Sjdp	  success = demangle_template (work, mangled, declp, 0);
156033965Sjdp	  break;
156133965Sjdp	default:
156233965Sjdp	  n = consume_count (mangled);
156333965Sjdp	  string_appendn (declp, *mangled, n);
156433965Sjdp	  (*mangled) += n;
156533965Sjdp	}
156633965Sjdp      if (success && (p == *mangled))
156733965Sjdp	{
156833965Sjdp	  /* Consumed everything up to the cplus_marker, append the
156933965Sjdp	     variable name.  */
157033965Sjdp	  (*mangled)++;
157133965Sjdp	  string_append (declp, "::");
157233965Sjdp	  n = strlen (*mangled);
157333965Sjdp	  string_appendn (declp, *mangled, n);
157433965Sjdp	  (*mangled) += n;
157533965Sjdp	}
157633965Sjdp      else
157733965Sjdp	{
157833965Sjdp	  success = 0;
157933965Sjdp	}
158033965Sjdp    }
158133965Sjdp  else if (strncmp (*mangled, "__thunk_", 8) == 0)
158233965Sjdp    {
158333965Sjdp      int delta = ((*mangled) += 8, consume_count (mangled));
158433965Sjdp      char *method = cplus_demangle (++*mangled, work->options);
158533965Sjdp      if (method)
158633965Sjdp	{
158733965Sjdp	  char buf[50];
158833965Sjdp	  sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
158933965Sjdp	  string_append (declp, buf);
159033965Sjdp	  string_append (declp, method);
159133965Sjdp	  free (method);
159233965Sjdp	  n = strlen (*mangled);
159333965Sjdp	  (*mangled) += n;
159433965Sjdp	}
159533965Sjdp      else
159633965Sjdp	{
159733965Sjdp	  success = 0;
159833965Sjdp	}
159933965Sjdp    }
160033965Sjdp  else if (strncmp (*mangled, "__t", 3) == 0
160133965Sjdp	   && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
160233965Sjdp    {
160333965Sjdp      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
160433965Sjdp      (*mangled) += 4;
160533965Sjdp      switch (**mangled)
160633965Sjdp	{
160733965Sjdp	case 'Q':
160833965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
160933965Sjdp	  break;
161033965Sjdp	case 't':
161133965Sjdp	  success = demangle_template (work, mangled, declp, 0);
161233965Sjdp	  break;
161333965Sjdp	default:
161433965Sjdp	  success = demangle_fund_type (work, mangled, declp);
161533965Sjdp	  break;
161633965Sjdp	}
161733965Sjdp      if (success && **mangled != '\0')
161833965Sjdp	success = 0;
161933965Sjdp      if (success)
162033965Sjdp	string_append (declp, p);
162133965Sjdp    }
162233965Sjdp  else
162333965Sjdp    {
162433965Sjdp      success = 0;
162533965Sjdp    }
162633965Sjdp  return (success);
162733965Sjdp}
162833965Sjdp
162933965Sjdp/*
163033965Sjdp
163133965SjdpLOCAL FUNCTION
163233965Sjdp
163333965Sjdp	arm_special -- special handling of ARM/lucid mangled strings
163433965Sjdp
163533965SjdpSYNOPSIS
163633965Sjdp
163733965Sjdp	static int
163833965Sjdp	arm_special (struct work_stuff *work, const char **mangled,
163933965Sjdp			string *declp);
164033965Sjdp
164133965Sjdp
164233965SjdpDESCRIPTION
164333965Sjdp
164433965Sjdp	Process some special ARM style mangling forms that don't fit
164533965Sjdp	the normal pattern.  For example:
164633965Sjdp
164733965Sjdp		__vtbl__3foo		(foo virtual table)
164833965Sjdp		__vtbl__3foo__3bar	(bar::foo virtual table)
164933965Sjdp
165033965Sjdp */
165133965Sjdp
165233965Sjdpstatic int
165333965Sjdparm_special (work, mangled, declp)
165433965Sjdp     struct work_stuff *work;
165533965Sjdp     const char **mangled;
165633965Sjdp     string *declp;
165733965Sjdp{
165833965Sjdp  int n;
165933965Sjdp  int success = 1;
166033965Sjdp  const char *scan;
166133965Sjdp
166233965Sjdp  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
166333965Sjdp    {
166433965Sjdp      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
166533965Sjdp         and create the decl.  Note that we consume the entire mangled
166633965Sjdp	 input string, which means that demangle_signature has no work
166733965Sjdp	 to do.  */
166833965Sjdp      scan = *mangled + ARM_VTABLE_STRLEN;
166933965Sjdp      while (*scan != '\0')        /* first check it can be demangled */
167033965Sjdp        {
167133965Sjdp          n = consume_count (&scan);
167233965Sjdp          if (n==0)
167333965Sjdp	    {
167433965Sjdp	      return (0);           /* no good */
167533965Sjdp	    }
167633965Sjdp          scan += n;
167733965Sjdp          if (scan[0] == '_' && scan[1] == '_')
167833965Sjdp	    {
167933965Sjdp	      scan += 2;
168033965Sjdp	    }
168133965Sjdp        }
168233965Sjdp      (*mangled) += ARM_VTABLE_STRLEN;
168333965Sjdp      while (**mangled != '\0')
168433965Sjdp	{
168533965Sjdp	  n = consume_count (mangled);
168633965Sjdp	  string_prependn (declp, *mangled, n);
168733965Sjdp	  (*mangled) += n;
168833965Sjdp	  if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
168933965Sjdp	    {
169033965Sjdp	      string_prepend (declp, "::");
169133965Sjdp	      (*mangled) += 2;
169233965Sjdp	    }
169333965Sjdp	}
169433965Sjdp      string_append (declp, " virtual table");
169533965Sjdp    }
169633965Sjdp  else
169733965Sjdp    {
169833965Sjdp      success = 0;
169933965Sjdp    }
170033965Sjdp  return (success);
170133965Sjdp}
170233965Sjdp
170333965Sjdp/*
170433965Sjdp
170533965SjdpLOCAL FUNCTION
170633965Sjdp
170733965Sjdp	demangle_qualified -- demangle 'Q' qualified name strings
170833965Sjdp
170933965SjdpSYNOPSIS
171033965Sjdp
171133965Sjdp	static int
171233965Sjdp	demangle_qualified (struct work_stuff *, const char *mangled,
171333965Sjdp			    string *result, int isfuncname, int append);
171433965Sjdp
171533965SjdpDESCRIPTION
171633965Sjdp
171733965Sjdp	Demangle a qualified name, such as "Q25Outer5Inner" which is
171833965Sjdp	the mangled form of "Outer::Inner".  The demangled output is
171933965Sjdp	prepended or appended to the result string according to the
172033965Sjdp	state of the append flag.
172133965Sjdp
172233965Sjdp	If isfuncname is nonzero, then the qualified name we are building
172333965Sjdp	is going to be used as a member function name, so if it is a
172433965Sjdp	constructor or destructor function, append an appropriate
172533965Sjdp	constructor or destructor name.  I.E. for the above example,
172633965Sjdp	the result for use as a constructor is "Outer::Inner::Inner"
172733965Sjdp	and the result for use as a destructor is "Outer::Inner::~Inner".
172833965Sjdp
172933965SjdpBUGS
173033965Sjdp
173133965Sjdp	Numeric conversion is ASCII dependent (FIXME).
173233965Sjdp
173333965Sjdp */
173433965Sjdp
173533965Sjdpstatic int
173633965Sjdpdemangle_qualified (work, mangled, result, isfuncname, append)
173733965Sjdp     struct work_stuff *work;
173833965Sjdp     const char **mangled;
173933965Sjdp     string *result;
174033965Sjdp     int isfuncname;
174133965Sjdp     int append;
174233965Sjdp{
174333965Sjdp  int qualifiers;
174433965Sjdp  int namelength;
174533965Sjdp  int success = 1;
174633965Sjdp  const char *p;
174733965Sjdp  char num[2];
174833965Sjdp  string temp;
174933965Sjdp
175033965Sjdp  string_init (&temp);
175133965Sjdp  switch ((*mangled)[1])
175233965Sjdp    {
175333965Sjdp    case '_':
175433965Sjdp      /* GNU mangled name with more than 9 classes.  The count is preceded
175533965Sjdp	 by an underscore (to distinguish it from the <= 9 case) and followed
175633965Sjdp	 by an underscore.  */
175733965Sjdp      p = *mangled + 2;
175833965Sjdp      qualifiers = atoi (p);
175933965Sjdp      if (!isdigit (*p) || *p == '0')
176033965Sjdp	success = 0;
176133965Sjdp
176233965Sjdp      /* Skip the digits.  */
176333965Sjdp      while (isdigit (*p))
176433965Sjdp	++p;
176533965Sjdp
176633965Sjdp      if (*p != '_')
176733965Sjdp	success = 0;
176833965Sjdp
176933965Sjdp      *mangled = p + 1;
177033965Sjdp      break;
177133965Sjdp
177233965Sjdp    case '1':
177333965Sjdp    case '2':
177433965Sjdp    case '3':
177533965Sjdp    case '4':
177633965Sjdp    case '5':
177733965Sjdp    case '6':
177833965Sjdp    case '7':
177933965Sjdp    case '8':
178033965Sjdp    case '9':
178133965Sjdp      /* The count is in a single digit.  */
178233965Sjdp      num[0] = (*mangled)[1];
178333965Sjdp      num[1] = '\0';
178433965Sjdp      qualifiers = atoi (num);
178533965Sjdp
178633965Sjdp      /* If there is an underscore after the digit, skip it.  This is
178733965Sjdp	 said to be for ARM-qualified names, but the ARM makes no
178833965Sjdp	 mention of such an underscore.  Perhaps cfront uses one.  */
178933965Sjdp      if ((*mangled)[2] == '_')
179033965Sjdp	{
179133965Sjdp	  (*mangled)++;
179233965Sjdp	}
179333965Sjdp      (*mangled) += 2;
179433965Sjdp      break;
179533965Sjdp
179633965Sjdp    case '0':
179733965Sjdp    default:
179833965Sjdp      success = 0;
179933965Sjdp    }
180033965Sjdp
180133965Sjdp  if (!success)
180233965Sjdp    return success;
180333965Sjdp
180433965Sjdp  /* Pick off the names and collect them in the temp buffer in the order
180533965Sjdp     in which they are found, separated by '::'.  */
180633965Sjdp
180733965Sjdp  while (qualifiers-- > 0)
180833965Sjdp    {
180933965Sjdp      if (*mangled[0] == '_')
181033965Sjdp	*mangled = *mangled + 1;
181133965Sjdp      if (*mangled[0] == 't')
181233965Sjdp	{
181333965Sjdp	  success = demangle_template(work, mangled, &temp, 0);
181433965Sjdp	  if (!success) break;
181533965Sjdp	}
181633965Sjdp      else
181733965Sjdp        {
181833965Sjdp	  namelength = consume_count (mangled);
181933965Sjdp      	  if (strlen (*mangled) < namelength)
182033965Sjdp	    {
182133965Sjdp	      /* Simple sanity check failed */
182233965Sjdp	      success = 0;
182333965Sjdp	      break;
182433965Sjdp	    }
182533965Sjdp      	  string_appendn (&temp, *mangled, namelength);
182633965Sjdp      	  *mangled += namelength;
182733965Sjdp	}
182833965Sjdp      if (qualifiers > 0)
182933965Sjdp        {
183033965Sjdp          string_appendn (&temp, "::", 2);
183133965Sjdp        }
183233965Sjdp    }
183333965Sjdp
183433965Sjdp  /* If we are using the result as a function name, we need to append
183533965Sjdp     the appropriate '::' separated constructor or destructor name.
183633965Sjdp     We do this here because this is the most convenient place, where
183733965Sjdp     we already have a pointer to the name and the length of the name.  */
183833965Sjdp
183933965Sjdp  if (isfuncname && (work->constructor & 1 || work->destructor & 1))
184033965Sjdp    {
184133965Sjdp      string_appendn (&temp, "::", 2);
184233965Sjdp      if (work -> destructor & 1)
184333965Sjdp	{
184433965Sjdp	  string_append (&temp, "~");
184533965Sjdp	}
184633965Sjdp      string_appendn (&temp, (*mangled) - namelength, namelength);
184733965Sjdp    }
184833965Sjdp
184933965Sjdp  /* Now either prepend the temp buffer to the result, or append it,
185033965Sjdp     depending upon the state of the append flag.  */
185133965Sjdp
185233965Sjdp  if (append)
185333965Sjdp    {
185433965Sjdp      string_appends (result, &temp);
185533965Sjdp    }
185633965Sjdp  else
185733965Sjdp    {
185833965Sjdp      if (!STRING_EMPTY (result))
185933965Sjdp	{
186033965Sjdp	  string_appendn (&temp, "::", 2);
186133965Sjdp	}
186233965Sjdp      string_prepends (result, &temp);
186333965Sjdp    }
186433965Sjdp
186533965Sjdp  string_delete (&temp);
186633965Sjdp  return (success);
186733965Sjdp}
186833965Sjdp
186933965Sjdp/*
187033965Sjdp
187133965SjdpLOCAL FUNCTION
187233965Sjdp
187333965Sjdp	get_count -- convert an ascii count to integer, consuming tokens
187433965Sjdp
187533965SjdpSYNOPSIS
187633965Sjdp
187733965Sjdp	static int
187833965Sjdp	get_count (const char **type, int *count)
187933965Sjdp
188033965SjdpDESCRIPTION
188133965Sjdp
188233965Sjdp	Return 0 if no conversion is performed, 1 if a string is converted.
188333965Sjdp*/
188433965Sjdp
188533965Sjdpstatic int
188633965Sjdpget_count (type, count)
188733965Sjdp     const char **type;
188833965Sjdp     int *count;
188933965Sjdp{
189033965Sjdp  const char *p;
189133965Sjdp  int n;
189233965Sjdp
189333965Sjdp  if (!isdigit (**type))
189433965Sjdp    {
189533965Sjdp      return (0);
189633965Sjdp    }
189733965Sjdp  else
189833965Sjdp    {
189933965Sjdp      *count = **type - '0';
190033965Sjdp      (*type)++;
190133965Sjdp      if (isdigit (**type))
190233965Sjdp	{
190333965Sjdp	  p = *type;
190433965Sjdp	  n = *count;
190533965Sjdp	  do
190633965Sjdp	    {
190733965Sjdp	      n *= 10;
190833965Sjdp	      n += *p - '0';
190933965Sjdp	      p++;
191033965Sjdp	    }
191133965Sjdp	  while (isdigit (*p));
191233965Sjdp	  if (*p == '_')
191333965Sjdp	    {
191433965Sjdp	      *type = p + 1;
191533965Sjdp	      *count = n;
191633965Sjdp	    }
191733965Sjdp	}
191833965Sjdp    }
191933965Sjdp  return (1);
192033965Sjdp}
192133965Sjdp
192233965Sjdp/* result will be initialised here; it will be freed on failure */
192333965Sjdp
192433965Sjdpstatic int
192533965Sjdpdo_type (work, mangled, result)
192633965Sjdp     struct work_stuff *work;
192733965Sjdp     const char **mangled;
192833965Sjdp     string *result;
192933965Sjdp{
193033965Sjdp  int n;
193133965Sjdp  int done;
193233965Sjdp  int success;
193333965Sjdp  string decl;
193433965Sjdp  const char *remembered_type;
193533965Sjdp  int constp;
193633965Sjdp  int volatilep;
193733965Sjdp
193833965Sjdp  string_init (&decl);
193933965Sjdp  string_init (result);
194033965Sjdp
194133965Sjdp  done = 0;
194233965Sjdp  success = 1;
194333965Sjdp  while (success && !done)
194433965Sjdp    {
194533965Sjdp      int member;
194633965Sjdp      switch (**mangled)
194733965Sjdp	{
194833965Sjdp
194933965Sjdp	  /* A pointer type */
195033965Sjdp	case 'P':
195133965Sjdp	case 'p':
195233965Sjdp	  (*mangled)++;
195333965Sjdp	  string_prepend (&decl, "*");
195433965Sjdp	  break;
195533965Sjdp
195633965Sjdp	  /* A reference type */
195733965Sjdp	case 'R':
195833965Sjdp	  (*mangled)++;
195933965Sjdp	  string_prepend (&decl, "&");
196033965Sjdp	  break;
196133965Sjdp
196233965Sjdp	  /* An array */
196333965Sjdp	case 'A':
196433965Sjdp	  {
196533965Sjdp	    const char *p = ++(*mangled);
196633965Sjdp
196733965Sjdp	    string_prepend (&decl, "(");
196833965Sjdp	    string_append (&decl, ")[");
196933965Sjdp	    /* Copy anything up until the next underscore (the size of the
197033965Sjdp	       array).  */
197133965Sjdp	    while (**mangled && **mangled != '_')
197233965Sjdp	      ++(*mangled);
197333965Sjdp	    if (**mangled == '_')
197433965Sjdp	      {
197533965Sjdp		string_appendn (&decl, p, *mangled - p);
197633965Sjdp		string_append (&decl, "]");
197733965Sjdp		*mangled += 1;
197833965Sjdp	      }
197933965Sjdp	    else
198033965Sjdp	      success = 0;
198133965Sjdp	    break;
198233965Sjdp	  }
198333965Sjdp
198433965Sjdp	/* A back reference to a previously seen type */
198533965Sjdp	case 'T':
198633965Sjdp	  (*mangled)++;
198733965Sjdp	  if (!get_count (mangled, &n) || n >= work -> ntypes)
198833965Sjdp	    {
198933965Sjdp	      success = 0;
199033965Sjdp	    }
199133965Sjdp	  else
199233965Sjdp	    {
199333965Sjdp	      remembered_type = work -> typevec[n];
199433965Sjdp	      mangled = &remembered_type;
199533965Sjdp	    }
199633965Sjdp	  break;
199733965Sjdp
199833965Sjdp	  /* A function */
199933965Sjdp	case 'F':
200033965Sjdp	  (*mangled)++;
200133965Sjdp	  if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
200233965Sjdp	    {
200333965Sjdp	      string_prepend (&decl, "(");
200433965Sjdp	      string_append (&decl, ")");
200533965Sjdp	    }
200633965Sjdp	  /* After picking off the function args, we expect to either find the
200733965Sjdp	     function return type (preceded by an '_') or the end of the
200833965Sjdp	     string.  */
200933965Sjdp	  if (!demangle_args (work, mangled, &decl)
201033965Sjdp	      || (**mangled != '_' && **mangled != '\0'))
201133965Sjdp	    {
201233965Sjdp	      success = 0;
201333965Sjdp	    }
201433965Sjdp	  if (success && (**mangled == '_'))
201533965Sjdp	    {
201633965Sjdp	      (*mangled)++;
201733965Sjdp	    }
201833965Sjdp	  break;
201933965Sjdp
202033965Sjdp	case 'M':
202133965Sjdp	case 'O':
202233965Sjdp	  {
202333965Sjdp	    constp = 0;
202433965Sjdp	    volatilep = 0;
202533965Sjdp
202633965Sjdp	    member = **mangled == 'M';
202733965Sjdp	    (*mangled)++;
202833965Sjdp	    if (!isdigit (**mangled) && **mangled != 't')
202933965Sjdp	      {
203033965Sjdp		success = 0;
203133965Sjdp		break;
203233965Sjdp	      }
203333965Sjdp
203433965Sjdp	    string_append (&decl, ")");
203533965Sjdp	    string_prepend (&decl, "::");
203633965Sjdp	    if (isdigit (**mangled))
203733965Sjdp	      {
203833965Sjdp		n = consume_count (mangled);
203933965Sjdp		if (strlen (*mangled) < n)
204033965Sjdp		  {
204133965Sjdp		    success = 0;
204233965Sjdp		    break;
204333965Sjdp		  }
204433965Sjdp		string_prependn (&decl, *mangled, n);
204533965Sjdp		*mangled += n;
204633965Sjdp	      }
204733965Sjdp	    else
204833965Sjdp	      {
204933965Sjdp		string temp;
205033965Sjdp		string_init (&temp);
205133965Sjdp		success = demangle_template (work, mangled, &temp, NULL);
205233965Sjdp		if (success)
205333965Sjdp		  {
205433965Sjdp		    string_prependn (&decl, temp.b, temp.p - temp.b);
205533965Sjdp		    string_clear (&temp);
205633965Sjdp		  }
205733965Sjdp		else
205833965Sjdp		  break;
205933965Sjdp	      }
206033965Sjdp	    string_prepend (&decl, "(");
206133965Sjdp	    if (member)
206233965Sjdp	      {
206333965Sjdp		if (**mangled == 'C')
206433965Sjdp		  {
206533965Sjdp		    (*mangled)++;
206633965Sjdp		    constp = 1;
206733965Sjdp		  }
206833965Sjdp		if (**mangled == 'V')
206933965Sjdp		  {
207033965Sjdp		    (*mangled)++;
207133965Sjdp		    volatilep = 1;
207233965Sjdp		  }
207333965Sjdp		if (*(*mangled)++ != 'F')
207433965Sjdp		  {
207533965Sjdp		    success = 0;
207633965Sjdp		    break;
207733965Sjdp		  }
207833965Sjdp	      }
207933965Sjdp	    if ((member && !demangle_args (work, mangled, &decl))
208033965Sjdp		|| **mangled != '_')
208133965Sjdp	      {
208233965Sjdp		success = 0;
208333965Sjdp		break;
208433965Sjdp	      }
208533965Sjdp	    (*mangled)++;
208633965Sjdp	    if (! PRINT_ANSI_QUALIFIERS)
208733965Sjdp	      {
208833965Sjdp		break;
208933965Sjdp	      }
209033965Sjdp	    if (constp)
209133965Sjdp	      {
209233965Sjdp		APPEND_BLANK (&decl);
209333965Sjdp		string_append (&decl, "const");
209433965Sjdp	      }
209533965Sjdp	    if (volatilep)
209633965Sjdp	      {
209733965Sjdp		APPEND_BLANK (&decl);
209833965Sjdp		string_append (&decl, "volatile");
209933965Sjdp	      }
210033965Sjdp	    break;
210133965Sjdp	  }
210233965Sjdp        case 'G':
210333965Sjdp	  (*mangled)++;
210433965Sjdp	  break;
210533965Sjdp
210633965Sjdp	case 'C':
210733965Sjdp	  (*mangled)++;
210833965Sjdp	  /*
210933965Sjdp	    if ((*mangled)[1] == 'P')
211033965Sjdp	    {
211133965Sjdp	    */
211233965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
211333965Sjdp	    {
211433965Sjdp	      if (!STRING_EMPTY (&decl))
211533965Sjdp		{
211633965Sjdp		  string_prepend (&decl, " ");
211733965Sjdp		}
211833965Sjdp	      string_prepend (&decl, "const");
211933965Sjdp	    }
212033965Sjdp	  break;
212133965Sjdp	  /*
212233965Sjdp	    }
212333965Sjdp	    */
212433965Sjdp
212533965Sjdp	  /* fall through */
212633965Sjdp	default:
212733965Sjdp	  done = 1;
212833965Sjdp	  break;
212933965Sjdp	}
213033965Sjdp    }
213133965Sjdp
213233965Sjdp  switch (**mangled)
213333965Sjdp    {
213433965Sjdp      /* A qualified name, such as "Outer::Inner".  */
213533965Sjdp    case 'Q':
213633965Sjdp      success = demangle_qualified (work, mangled, result, 0, 1);
213733965Sjdp      break;
213833965Sjdp
213933965Sjdp    default:
214033965Sjdp      success = demangle_fund_type (work, mangled, result);
214133965Sjdp      break;
214233965Sjdp    }
214333965Sjdp
214433965Sjdp  if (success)
214533965Sjdp    {
214633965Sjdp      if (!STRING_EMPTY (&decl))
214733965Sjdp	{
214833965Sjdp	  string_append (result, " ");
214933965Sjdp	  string_appends (result, &decl);
215033965Sjdp	}
215133965Sjdp    }
215233965Sjdp  else
215333965Sjdp    {
215433965Sjdp      string_delete (result);
215533965Sjdp    }
215633965Sjdp  string_delete (&decl);
215733965Sjdp  return (success);
215833965Sjdp}
215933965Sjdp
216033965Sjdp/* Given a pointer to a type string that represents a fundamental type
216133965Sjdp   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
216233965Sjdp   string in which the demangled output is being built in RESULT, and
216333965Sjdp   the WORK structure, decode the types and add them to the result.
216433965Sjdp
216533965Sjdp   For example:
216633965Sjdp
216733965Sjdp   	"Ci"	=>	"const int"
216833965Sjdp	"Sl"	=>	"signed long"
216933965Sjdp	"CUs"	=>	"const unsigned short"
217033965Sjdp
217133965Sjdp   */
217233965Sjdp
217333965Sjdpstatic int
217433965Sjdpdemangle_fund_type (work, mangled, result)
217533965Sjdp     struct work_stuff *work;
217633965Sjdp     const char **mangled;
217733965Sjdp     string *result;
217833965Sjdp{
217933965Sjdp  int done = 0;
218033965Sjdp  int success = 1;
218133965Sjdp
218233965Sjdp  /* First pick off any type qualifiers.  There can be more than one.  */
218333965Sjdp
218433965Sjdp  while (!done)
218533965Sjdp    {
218633965Sjdp      switch (**mangled)
218733965Sjdp	{
218833965Sjdp	case 'C':
218933965Sjdp	  (*mangled)++;
219033965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
219133965Sjdp	    {
219233965Sjdp	      APPEND_BLANK (result);
219333965Sjdp	      string_append (result, "const");
219433965Sjdp	    }
219533965Sjdp	  break;
219633965Sjdp	case 'U':
219733965Sjdp	  (*mangled)++;
219833965Sjdp	  APPEND_BLANK (result);
219933965Sjdp	  string_append (result, "unsigned");
220033965Sjdp	  break;
220133965Sjdp	case 'S': /* signed char only */
220233965Sjdp	  (*mangled)++;
220333965Sjdp	  APPEND_BLANK (result);
220433965Sjdp	  string_append (result, "signed");
220533965Sjdp	  break;
220633965Sjdp	case 'V':
220733965Sjdp	  (*mangled)++;
220833965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
220933965Sjdp	    {
221033965Sjdp	      APPEND_BLANK (result);
221133965Sjdp	      string_append (result, "volatile");
221233965Sjdp	    }
221333965Sjdp	  break;
221433965Sjdp	default:
221533965Sjdp	  done = 1;
221633965Sjdp	  break;
221733965Sjdp	}
221833965Sjdp    }
221933965Sjdp
222033965Sjdp  /* Now pick off the fundamental type.  There can be only one.  */
222133965Sjdp
222233965Sjdp  switch (**mangled)
222333965Sjdp    {
222433965Sjdp    case '\0':
222533965Sjdp    case '_':
222633965Sjdp      break;
222733965Sjdp    case 'v':
222833965Sjdp      (*mangled)++;
222933965Sjdp      APPEND_BLANK (result);
223033965Sjdp      string_append (result, "void");
223133965Sjdp      break;
223233965Sjdp    case 'x':
223333965Sjdp      (*mangled)++;
223433965Sjdp      APPEND_BLANK (result);
223533965Sjdp      string_append (result, "long long");
223633965Sjdp      break;
223733965Sjdp    case 'l':
223833965Sjdp      (*mangled)++;
223933965Sjdp      APPEND_BLANK (result);
224033965Sjdp      string_append (result, "long");
224133965Sjdp      break;
224233965Sjdp    case 'i':
224333965Sjdp      (*mangled)++;
224433965Sjdp      APPEND_BLANK (result);
224533965Sjdp      string_append (result, "int");
224633965Sjdp      break;
224733965Sjdp    case 's':
224833965Sjdp      (*mangled)++;
224933965Sjdp      APPEND_BLANK (result);
225033965Sjdp      string_append (result, "short");
225133965Sjdp      break;
225233965Sjdp    case 'b':
225333965Sjdp      (*mangled)++;
225433965Sjdp      APPEND_BLANK (result);
225533965Sjdp      string_append (result, "bool");
225633965Sjdp      break;
225733965Sjdp    case 'c':
225833965Sjdp      (*mangled)++;
225933965Sjdp      APPEND_BLANK (result);
226033965Sjdp      string_append (result, "char");
226133965Sjdp      break;
226233965Sjdp    case 'w':
226333965Sjdp      (*mangled)++;
226433965Sjdp      APPEND_BLANK (result);
226533965Sjdp      string_append (result, "wchar_t");
226633965Sjdp      break;
226733965Sjdp    case 'r':
226833965Sjdp      (*mangled)++;
226933965Sjdp      APPEND_BLANK (result);
227033965Sjdp      string_append (result, "long double");
227133965Sjdp      break;
227233965Sjdp    case 'd':
227333965Sjdp      (*mangled)++;
227433965Sjdp      APPEND_BLANK (result);
227533965Sjdp      string_append (result, "double");
227633965Sjdp      break;
227733965Sjdp    case 'f':
227833965Sjdp      (*mangled)++;
227933965Sjdp      APPEND_BLANK (result);
228033965Sjdp      string_append (result, "float");
228133965Sjdp      break;
228233965Sjdp    case 'G':
228333965Sjdp      (*mangled)++;
228433965Sjdp      if (!isdigit (**mangled))
228533965Sjdp	{
228633965Sjdp	  success = 0;
228733965Sjdp	  break;
228833965Sjdp	}
228933965Sjdp      /* fall through */
229033965Sjdp      /* An explicit type, such as "6mytype" or "7integer" */
229133965Sjdp    case '0':
229233965Sjdp    case '1':
229333965Sjdp    case '2':
229433965Sjdp    case '3':
229533965Sjdp    case '4':
229633965Sjdp    case '5':
229733965Sjdp    case '6':
229833965Sjdp    case '7':
229933965Sjdp    case '8':
230033965Sjdp    case '9':
230133965Sjdp      APPEND_BLANK (result);
230233965Sjdp      if (!demangle_class_name (work, mangled, result)) {
230333965Sjdp	--result->p;
230433965Sjdp	success = 0;
230533965Sjdp      }
230633965Sjdp      break;
230733965Sjdp    case 't':
230833965Sjdp      success = demangle_template(work,mangled, result, 0);
230933965Sjdp      break;
231033965Sjdp    default:
231133965Sjdp      success = 0;
231233965Sjdp      break;
231333965Sjdp    }
231433965Sjdp
231533965Sjdp  return (success);
231633965Sjdp}
231733965Sjdp
231833965Sjdp/* `result' will be initialized in do_type; it will be freed on failure */
231933965Sjdp
232033965Sjdpstatic int
232133965Sjdpdo_arg (work, mangled, result)
232233965Sjdp     struct work_stuff *work;
232333965Sjdp     const char **mangled;
232433965Sjdp     string *result;
232533965Sjdp{
232633965Sjdp  const char *start = *mangled;
232733965Sjdp
232833965Sjdp  if (!do_type (work, mangled, result))
232933965Sjdp    {
233033965Sjdp      return (0);
233133965Sjdp    }
233233965Sjdp  else
233333965Sjdp    {
233433965Sjdp      remember_type (work, start, *mangled - start);
233533965Sjdp      return (1);
233633965Sjdp    }
233733965Sjdp}
233833965Sjdp
233933965Sjdpstatic void
234033965Sjdpremember_type (work, start, len)
234133965Sjdp     struct work_stuff *work;
234233965Sjdp     const char *start;
234333965Sjdp     int len;
234433965Sjdp{
234533965Sjdp  char *tem;
234633965Sjdp
234733965Sjdp  if (work -> ntypes >= work -> typevec_size)
234833965Sjdp    {
234933965Sjdp      if (work -> typevec_size == 0)
235033965Sjdp	{
235133965Sjdp	  work -> typevec_size = 3;
235233965Sjdp	  work -> typevec =
235333965Sjdp	    (char **) xmalloc (sizeof (char *) * work -> typevec_size);
235433965Sjdp	}
235533965Sjdp      else
235633965Sjdp	{
235733965Sjdp	  work -> typevec_size *= 2;
235833965Sjdp	  work -> typevec =
235933965Sjdp	    (char **) xrealloc ((char *)work -> typevec,
236033965Sjdp				sizeof (char *) * work -> typevec_size);
236133965Sjdp	}
236233965Sjdp    }
236333965Sjdp  tem = xmalloc (len + 1);
236433965Sjdp  memcpy (tem, start, len);
236533965Sjdp  tem[len] = '\0';
236633965Sjdp  work -> typevec[work -> ntypes++] = tem;
236733965Sjdp}
236833965Sjdp
236933965Sjdp/* Forget the remembered types, but not the type vector itself.  */
237033965Sjdp
237133965Sjdpstatic void
237233965Sjdpforget_types (work)
237333965Sjdp     struct work_stuff *work;
237433965Sjdp{
237533965Sjdp  int i;
237633965Sjdp
237733965Sjdp  while (work -> ntypes > 0)
237833965Sjdp    {
237933965Sjdp      i = --(work -> ntypes);
238033965Sjdp      if (work -> typevec[i] != NULL)
238133965Sjdp	{
238233965Sjdp	  free (work -> typevec[i]);
238333965Sjdp	  work -> typevec[i] = NULL;
238433965Sjdp	}
238533965Sjdp    }
238633965Sjdp}
238733965Sjdp
238833965Sjdp/* Process the argument list part of the signature, after any class spec
238933965Sjdp   has been consumed, as well as the first 'F' character (if any).  For
239033965Sjdp   example:
239133965Sjdp
239233965Sjdp   "__als__3fooRT0"		=>	process "RT0"
239333965Sjdp   "complexfunc5__FPFPc_PFl_i"	=>	process "PFPc_PFl_i"
239433965Sjdp
239533965Sjdp   DECLP must be already initialised, usually non-empty.  It won't be freed
239633965Sjdp   on failure.
239733965Sjdp
239833965Sjdp   Note that g++ differs significantly from ARM and lucid style mangling
239933965Sjdp   with regards to references to previously seen types.  For example, given
240033965Sjdp   the source fragment:
240133965Sjdp
240233965Sjdp     class foo {
240333965Sjdp       public:
240433965Sjdp       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
240533965Sjdp     };
240633965Sjdp
240733965Sjdp     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
240833965Sjdp     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
240933965Sjdp
241033965Sjdp   g++ produces the names:
241133965Sjdp
241233965Sjdp     __3fooiRT0iT2iT2
241333965Sjdp     foo__FiR3fooiT1iT1
241433965Sjdp
241533965Sjdp   while lcc (and presumably other ARM style compilers as well) produces:
241633965Sjdp
241733965Sjdp     foo__FiR3fooT1T2T1T2
241833965Sjdp     __ct__3fooFiR3fooT1T2T1T2
241933965Sjdp
242033965Sjdp   Note that g++ bases it's type numbers starting at zero and counts all
242133965Sjdp   previously seen types, while lucid/ARM bases it's type numbers starting
242233965Sjdp   at one and only considers types after it has seen the 'F' character
242333965Sjdp   indicating the start of the function args.  For lucid/ARM style, we
242433965Sjdp   account for this difference by discarding any previously seen types when
242533965Sjdp   we see the 'F' character, and subtracting one from the type number
242633965Sjdp   reference.
242733965Sjdp
242833965Sjdp */
242933965Sjdp
243033965Sjdpstatic int
243133965Sjdpdemangle_args (work, mangled, declp)
243233965Sjdp     struct work_stuff *work;
243333965Sjdp     const char **mangled;
243433965Sjdp     string *declp;
243533965Sjdp{
243633965Sjdp  string arg;
243733965Sjdp  int need_comma = 0;
243833965Sjdp  int r;
243933965Sjdp  int t;
244033965Sjdp  const char *tem;
244133965Sjdp  char temptype;
244233965Sjdp
244333965Sjdp  if (PRINT_ARG_TYPES)
244433965Sjdp    {
244533965Sjdp      string_append (declp, "(");
244633965Sjdp      if (**mangled == '\0')
244733965Sjdp	{
244833965Sjdp	  string_append (declp, "void");
244933965Sjdp	}
245033965Sjdp    }
245133965Sjdp
245233965Sjdp  while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
245333965Sjdp    {
245433965Sjdp      if ((**mangled == 'N') || (**mangled == 'T'))
245533965Sjdp	{
245633965Sjdp	  temptype = *(*mangled)++;
245733965Sjdp
245833965Sjdp	  if (temptype == 'N')
245933965Sjdp	    {
246033965Sjdp	      if (!get_count (mangled, &r))
246133965Sjdp		{
246233965Sjdp		  return (0);
246333965Sjdp		}
246433965Sjdp	    }
246533965Sjdp	  else
246633965Sjdp	    {
246733965Sjdp	      r = 1;
246833965Sjdp	    }
246933965Sjdp          if (ARM_DEMANGLING && work -> ntypes >= 10)
247033965Sjdp            {
247133965Sjdp              /* If we have 10 or more types we might have more than a 1 digit
247233965Sjdp                 index so we'll have to consume the whole count here. This
247333965Sjdp                 will lose if the next thing is a type name preceded by a
247433965Sjdp                 count but it's impossible to demangle that case properly
247533965Sjdp                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
247633965Sjdp                 Pc, ...)"  or "(..., type12, char *, ...)" */
247733965Sjdp              if ((t = consume_count(mangled)) == 0)
247833965Sjdp                {
247933965Sjdp                  return (0);
248033965Sjdp                }
248133965Sjdp            }
248233965Sjdp          else
248333965Sjdp	    {
248433965Sjdp	      if (!get_count (mangled, &t))
248533965Sjdp	    	{
248633965Sjdp	          return (0);
248733965Sjdp	    	}
248833965Sjdp	    }
248933965Sjdp	  if (LUCID_DEMANGLING || ARM_DEMANGLING)
249033965Sjdp	    {
249133965Sjdp	      t--;
249233965Sjdp	    }
249333965Sjdp	  /* Validate the type index.  Protect against illegal indices from
249433965Sjdp	     malformed type strings.  */
249533965Sjdp	  if ((t < 0) || (t >= work -> ntypes))
249633965Sjdp	    {
249733965Sjdp	      return (0);
249833965Sjdp	    }
249933965Sjdp	  while (--r >= 0)
250033965Sjdp	    {
250133965Sjdp	      tem = work -> typevec[t];
250233965Sjdp	      if (need_comma && PRINT_ARG_TYPES)
250333965Sjdp		{
250433965Sjdp		  string_append (declp, ", ");
250533965Sjdp		}
250633965Sjdp	      if (!do_arg (work, &tem, &arg))
250733965Sjdp		{
250833965Sjdp		  return (0);
250933965Sjdp		}
251033965Sjdp	      if (PRINT_ARG_TYPES)
251133965Sjdp		{
251233965Sjdp		  string_appends (declp, &arg);
251333965Sjdp		}
251433965Sjdp	      string_delete (&arg);
251533965Sjdp	      need_comma = 1;
251633965Sjdp	    }
251733965Sjdp	}
251833965Sjdp      else
251933965Sjdp	{
252033965Sjdp	  if (need_comma & PRINT_ARG_TYPES)
252133965Sjdp	    {
252233965Sjdp	      string_append (declp, ", ");
252333965Sjdp	    }
252433965Sjdp	  if (!do_arg (work, mangled, &arg))
252533965Sjdp	    {
252633965Sjdp	      return (0);
252733965Sjdp	    }
252833965Sjdp	  if (PRINT_ARG_TYPES)
252933965Sjdp	    {
253033965Sjdp	      string_appends (declp, &arg);
253133965Sjdp	    }
253233965Sjdp	  string_delete (&arg);
253333965Sjdp	  need_comma = 1;
253433965Sjdp	}
253533965Sjdp    }
253633965Sjdp
253733965Sjdp  if (**mangled == 'e')
253833965Sjdp    {
253933965Sjdp      (*mangled)++;
254033965Sjdp      if (PRINT_ARG_TYPES)
254133965Sjdp	{
254233965Sjdp	  if (need_comma)
254333965Sjdp	    {
254433965Sjdp	      string_append (declp, ",");
254533965Sjdp	    }
254633965Sjdp	  string_append (declp, "...");
254733965Sjdp	}
254833965Sjdp    }
254933965Sjdp
255033965Sjdp  if (PRINT_ARG_TYPES)
255133965Sjdp    {
255233965Sjdp      string_append (declp, ")");
255333965Sjdp    }
255433965Sjdp  return (1);
255533965Sjdp}
255633965Sjdp
255733965Sjdpstatic void
255833965Sjdpdemangle_function_name (work, mangled, declp, scan)
255933965Sjdp     struct work_stuff *work;
256033965Sjdp     const char **mangled;
256133965Sjdp     string *declp;
256233965Sjdp     const char *scan;
256333965Sjdp{
256433965Sjdp  int i;
256533965Sjdp  int len;
256633965Sjdp  string type;
256733965Sjdp  const char *tem;
256833965Sjdp
256933965Sjdp  string_appendn (declp, (*mangled), scan - (*mangled));
257033965Sjdp  string_need (declp, 1);
257133965Sjdp  *(declp -> p) = '\0';
257233965Sjdp
257333965Sjdp  /* Consume the function name, including the "__" separating the name
257433965Sjdp     from the signature.  We are guaranteed that SCAN points to the
257533965Sjdp     separator.  */
257633965Sjdp
257733965Sjdp  (*mangled) = scan + 2;
257833965Sjdp
257933965Sjdp  if (LUCID_DEMANGLING || ARM_DEMANGLING)
258033965Sjdp    {
258133965Sjdp
258233965Sjdp      /* See if we have an ARM style constructor or destructor operator.
258333965Sjdp	 If so, then just record it, clear the decl, and return.
258433965Sjdp	 We can't build the actual constructor/destructor decl until later,
258533965Sjdp	 when we recover the class name from the signature.  */
258633965Sjdp
258733965Sjdp      if (strcmp (declp -> b, "__ct") == 0)
258833965Sjdp	{
258933965Sjdp	  work -> constructor += 1;
259033965Sjdp	  string_clear (declp);
259133965Sjdp	  return;
259233965Sjdp	}
259333965Sjdp      else if (strcmp (declp -> b, "__dt") == 0)
259433965Sjdp	{
259533965Sjdp	  work -> destructor += 1;
259633965Sjdp	  string_clear (declp);
259733965Sjdp	  return;
259833965Sjdp	}
259933965Sjdp    }
260033965Sjdp
260133965Sjdp  if (declp->p - declp->b >= 3
260233965Sjdp      && declp->b[0] == 'o'
260333965Sjdp      && declp->b[1] == 'p'
260433965Sjdp      && strchr (cplus_markers, declp->b[2]) != NULL)
260533965Sjdp    {
260633965Sjdp      /* see if it's an assignment expression */
260733965Sjdp      if (declp->p - declp->b >= 10 /* op$assign_ */
260833965Sjdp	  && memcmp (declp->b + 3, "assign_", 7) == 0)
260933965Sjdp	{
261033965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
261133965Sjdp	    {
261233965Sjdp	      len = declp->p - declp->b - 10;
261333965Sjdp	      if (strlen (optable[i].in) == len
261433965Sjdp		  && memcmp (optable[i].in, declp->b + 10, len) == 0)
261533965Sjdp		{
261633965Sjdp		  string_clear (declp);
261733965Sjdp		  string_append (declp, "operator");
261833965Sjdp		  string_append (declp, optable[i].out);
261933965Sjdp		  string_append (declp, "=");
262033965Sjdp		  break;
262133965Sjdp		}
262233965Sjdp	    }
262333965Sjdp	}
262433965Sjdp      else
262533965Sjdp	{
262633965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
262733965Sjdp	    {
262833965Sjdp	      int len = declp->p - declp->b - 3;
262933965Sjdp	      if (strlen (optable[i].in) == len
263033965Sjdp		  && memcmp (optable[i].in, declp->b + 3, len) == 0)
263133965Sjdp		{
263233965Sjdp		  string_clear (declp);
263333965Sjdp		  string_append (declp, "operator");
263433965Sjdp		  string_append (declp, optable[i].out);
263533965Sjdp		  break;
263633965Sjdp		}
263733965Sjdp	    }
263833965Sjdp	}
263933965Sjdp    }
264033965Sjdp  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
264133965Sjdp	   && strchr (cplus_markers, declp->b[4]) != NULL)
264233965Sjdp    {
264333965Sjdp      /* type conversion operator */
264433965Sjdp      tem = declp->b + 5;
264533965Sjdp      if (do_type (work, &tem, &type))
264633965Sjdp	{
264733965Sjdp	  string_clear (declp);
264833965Sjdp	  string_append (declp, "operator ");
264933965Sjdp	  string_appends (declp, &type);
265033965Sjdp	  string_delete (&type);
265133965Sjdp	}
265233965Sjdp    }
265333965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
265433965Sjdp	   && declp->b[2] == 'o' && declp->b[3] == 'p')
265533965Sjdp    {
265633965Sjdp      /* ANSI.  */
265733965Sjdp      /* type conversion operator.  */
265833965Sjdp      tem = declp->b + 4;
265933965Sjdp      if (do_type (work, &tem, &type))
266033965Sjdp	{
266133965Sjdp	  string_clear (declp);
266233965Sjdp	  string_append (declp, "operator ");
266333965Sjdp	  string_appends (declp, &type);
266433965Sjdp	  string_delete (&type);
266533965Sjdp	}
266633965Sjdp    }
266733965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
266833965Sjdp	   && declp->b[2] >= 'a' && declp->b[2] <= 'z'
266933965Sjdp	   && declp->b[3] >= 'a' && declp->b[3] <= 'z')
267033965Sjdp    {
267133965Sjdp      if (declp->b[4] == '\0')
267233965Sjdp	{
267333965Sjdp	  /* Operator.  */
267433965Sjdp	  for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
267533965Sjdp	    {
267633965Sjdp	      if (strlen (optable[i].in) == 2
267733965Sjdp		  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
267833965Sjdp		{
267933965Sjdp		  string_clear (declp);
268033965Sjdp		  string_append (declp, "operator");
268133965Sjdp		  string_append (declp, optable[i].out);
268233965Sjdp		  break;
268333965Sjdp		}
268433965Sjdp	    }
268533965Sjdp	}
268633965Sjdp      else
268733965Sjdp	{
268833965Sjdp	  if (declp->b[2] == 'a' && declp->b[5] == '\0')
268933965Sjdp	    {
269033965Sjdp	      /* Assignment.  */
269133965Sjdp	      for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
269233965Sjdp		{
269333965Sjdp		  if (strlen (optable[i].in) == 3
269433965Sjdp		      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
269533965Sjdp		    {
269633965Sjdp		      string_clear (declp);
269733965Sjdp		      string_append (declp, "operator");
269833965Sjdp		      string_append (declp, optable[i].out);
269933965Sjdp		      break;
270033965Sjdp		    }
270133965Sjdp		}
270233965Sjdp	    }
270333965Sjdp	}
270433965Sjdp    }
270533965Sjdp}
270633965Sjdp
270733965Sjdp/* a mini string-handling package */
270833965Sjdp
270933965Sjdpstatic void
271033965Sjdpstring_need (s, n)
271133965Sjdp     string *s;
271233965Sjdp     int n;
271333965Sjdp{
271433965Sjdp  int tem;
271533965Sjdp
271633965Sjdp  if (s->b == NULL)
271733965Sjdp    {
271833965Sjdp      if (n < 32)
271933965Sjdp	{
272033965Sjdp	  n = 32;
272133965Sjdp	}
272233965Sjdp      s->p = s->b = xmalloc (n);
272333965Sjdp      s->e = s->b + n;
272433965Sjdp    }
272533965Sjdp  else if (s->e - s->p < n)
272633965Sjdp    {
272733965Sjdp      tem = s->p - s->b;
272833965Sjdp      n += tem;
272933965Sjdp      n *= 2;
273033965Sjdp      s->b = xrealloc (s->b, n);
273133965Sjdp      s->p = s->b + tem;
273233965Sjdp      s->e = s->b + n;
273333965Sjdp    }
273433965Sjdp}
273533965Sjdp
273633965Sjdpstatic void
273733965Sjdpstring_delete (s)
273833965Sjdp     string *s;
273933965Sjdp{
274033965Sjdp  if (s->b != NULL)
274133965Sjdp    {
274233965Sjdp      free (s->b);
274333965Sjdp      s->b = s->e = s->p = NULL;
274433965Sjdp    }
274533965Sjdp}
274633965Sjdp
274733965Sjdpstatic void
274833965Sjdpstring_init (s)
274933965Sjdp     string *s;
275033965Sjdp{
275133965Sjdp  s->b = s->p = s->e = NULL;
275233965Sjdp}
275333965Sjdp
275433965Sjdpstatic void
275533965Sjdpstring_clear (s)
275633965Sjdp     string *s;
275733965Sjdp{
275833965Sjdp  s->p = s->b;
275933965Sjdp}
276033965Sjdp
276133965Sjdp#if 0
276233965Sjdp
276333965Sjdpstatic int
276433965Sjdpstring_empty (s)
276533965Sjdp     string *s;
276633965Sjdp{
276733965Sjdp  return (s->b == s->p);
276833965Sjdp}
276933965Sjdp
277033965Sjdp#endif
277133965Sjdp
277233965Sjdpstatic void
277333965Sjdpstring_append (p, s)
277433965Sjdp     string *p;
277533965Sjdp     const char *s;
277633965Sjdp{
277733965Sjdp  int n;
277833965Sjdp  if (s == NULL || *s == '\0')
277933965Sjdp    return;
278033965Sjdp  n = strlen (s);
278133965Sjdp  string_need (p, n);
278233965Sjdp  memcpy (p->p, s, n);
278333965Sjdp  p->p += n;
278433965Sjdp}
278533965Sjdp
278633965Sjdpstatic void
278733965Sjdpstring_appends (p, s)
278833965Sjdp     string *p, *s;
278933965Sjdp{
279033965Sjdp  int n;
279133965Sjdp
279233965Sjdp  if (s->b != s->p)
279333965Sjdp    {
279433965Sjdp      n = s->p - s->b;
279533965Sjdp      string_need (p, n);
279633965Sjdp      memcpy (p->p, s->b, n);
279733965Sjdp      p->p += n;
279833965Sjdp    }
279933965Sjdp}
280033965Sjdp
280133965Sjdpstatic void
280233965Sjdpstring_appendn (p, s, n)
280333965Sjdp     string *p;
280433965Sjdp     const char *s;
280533965Sjdp     int n;
280633965Sjdp{
280733965Sjdp  if (n != 0)
280833965Sjdp    {
280933965Sjdp      string_need (p, n);
281033965Sjdp      memcpy (p->p, s, n);
281133965Sjdp      p->p += n;
281233965Sjdp    }
281333965Sjdp}
281433965Sjdp
281533965Sjdpstatic void
281633965Sjdpstring_prepend (p, s)
281733965Sjdp     string *p;
281833965Sjdp     const char *s;
281933965Sjdp{
282033965Sjdp  if (s != NULL && *s != '\0')
282133965Sjdp    {
282233965Sjdp      string_prependn (p, s, strlen (s));
282333965Sjdp    }
282433965Sjdp}
282533965Sjdp
282633965Sjdpstatic void
282733965Sjdpstring_prepends (p, s)
282833965Sjdp     string *p, *s;
282933965Sjdp{
283033965Sjdp  if (s->b != s->p)
283133965Sjdp    {
283233965Sjdp      string_prependn (p, s->b, s->p - s->b);
283333965Sjdp    }
283433965Sjdp}
283533965Sjdp
283633965Sjdpstatic void
283733965Sjdpstring_prependn (p, s, n)
283833965Sjdp     string *p;
283933965Sjdp     const char *s;
284033965Sjdp     int n;
284133965Sjdp{
284233965Sjdp  char *q;
284333965Sjdp
284433965Sjdp  if (n != 0)
284533965Sjdp    {
284633965Sjdp      string_need (p, n);
284733965Sjdp      for (q = p->p - 1; q >= p->b; q--)
284833965Sjdp	{
284933965Sjdp	  q[n] = q[0];
285033965Sjdp	}
285133965Sjdp      memcpy (p->b, s, n);
285233965Sjdp      p->p += n;
285333965Sjdp    }
285433965Sjdp}
285533965Sjdp
285633965Sjdp/* To generate a standalone demangler program for testing purposes,
285733965Sjdp   just compile and link this file with -DMAIN and libiberty.a.  When
285833965Sjdp   run, it demangles each command line arg, or each stdin string, and
285933965Sjdp   prints the result on stdout.  */
286033965Sjdp
286133965Sjdp#ifdef MAIN
286233965Sjdp
286333965Sjdpstatic void demangle_it PARAMS ((char *));
286433965Sjdpstatic void usage PARAMS ((FILE *, int));
286533965Sjdpstatic void fatal PARAMS ((char *));
286633965Sjdp
286733965Sjdpstatic void
286833965Sjdpdemangle_it (mangled_name)
286933965Sjdp     char *mangled_name;
287033965Sjdp{
287133965Sjdp  char *result;
287233965Sjdp
287333965Sjdp  result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
287433965Sjdp  if (result == NULL)
287533965Sjdp    {
287633965Sjdp      printf ("%s\n", mangled_name);
287733965Sjdp    }
287833965Sjdp  else
287933965Sjdp    {
288033965Sjdp      printf ("%s\n", result);
288133965Sjdp      free (result);
288233965Sjdp    }
288333965Sjdp}
288433965Sjdp
288533965Sjdp#include "getopt.h"
288633965Sjdp
288733965Sjdpstatic char *program_name;
288833965Sjdpstatic char *program_version = VERSION;
288933965Sjdp
289033965Sjdpstatic void
289133965Sjdpusage (stream, status)
289233965Sjdp     FILE *stream;
289333965Sjdp     int status;
289433965Sjdp{
289533965Sjdp  fprintf (stream, "\
289633965SjdpUsage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
289733965Sjdp[--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
289833965Sjdp[--help] [--version] [arg...]\n",
289933965Sjdp	   program_name);
290033965Sjdp  exit (status);
290133965Sjdp}
290233965Sjdp
290333965Sjdp#define MBUF_SIZE 512
290433965Sjdpchar mbuffer[MBUF_SIZE];
290533965Sjdp
290633965Sjdp/* Defined in the automatically-generated underscore.c.  */
290733965Sjdpextern int prepends_underscore;
290833965Sjdp
290933965Sjdpint strip_underscore = 0;
291033965Sjdp
291133965Sjdpstatic struct option long_options[] = {
291233965Sjdp  {"strip-underscores", no_argument, 0, '_'},
291333965Sjdp  {"format", required_argument, 0, 's'},
291433965Sjdp  {"help", no_argument, 0, 'h'},
291533965Sjdp  {"no-strip-underscores", no_argument, 0, 'n'},
291633965Sjdp  {"version", no_argument, 0, 'v'},
291733965Sjdp  {0, no_argument, 0, 0}
291833965Sjdp};
291933965Sjdp
292033965Sjdpint
292133965Sjdpmain (argc, argv)
292233965Sjdp     int argc;
292333965Sjdp     char **argv;
292433965Sjdp{
292533965Sjdp  char *result;
292633965Sjdp  int c;
292733965Sjdp
292833965Sjdp  program_name = argv[0];
292933965Sjdp
293033965Sjdp  strip_underscore = prepends_underscore;
293133965Sjdp
293233965Sjdp  while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
293333965Sjdp    {
293433965Sjdp      switch (c)
293533965Sjdp	{
293633965Sjdp	case '?':
293733965Sjdp	  usage (stderr, 1);
293833965Sjdp	  break;
293933965Sjdp	case 'h':
294033965Sjdp	  usage (stdout, 0);
294133965Sjdp	case 'n':
294233965Sjdp	  strip_underscore = 0;
294333965Sjdp	  break;
294433965Sjdp	case 'v':
294533965Sjdp	  printf ("GNU %s version %s\n", program_name, program_version);
294633965Sjdp	  exit (0);
294733965Sjdp	case '_':
294833965Sjdp	  strip_underscore = 1;
294933965Sjdp	  break;
295033965Sjdp	case 's':
295133965Sjdp	  if (strcmp (optarg, "gnu") == 0)
295233965Sjdp	    {
295333965Sjdp	      current_demangling_style = gnu_demangling;
295433965Sjdp	    }
295533965Sjdp	  else if (strcmp (optarg, "lucid") == 0)
295633965Sjdp	    {
295733965Sjdp	      current_demangling_style = lucid_demangling;
295833965Sjdp	    }
295933965Sjdp	  else if (strcmp (optarg, "arm") == 0)
296033965Sjdp	    {
296133965Sjdp	      current_demangling_style = arm_demangling;
296233965Sjdp	    }
296333965Sjdp	  else
296433965Sjdp	    {
296533965Sjdp	      fprintf (stderr, "%s: unknown demangling style `%s'\n",
296633965Sjdp		       program_name, optarg);
296733965Sjdp	      exit (1);
296833965Sjdp	    }
296933965Sjdp	  break;
297033965Sjdp	}
297133965Sjdp    }
297233965Sjdp
297333965Sjdp  if (optind < argc)
297433965Sjdp    {
297533965Sjdp      for ( ; optind < argc; optind++)
297633965Sjdp	{
297733965Sjdp	  demangle_it (argv[optind]);
297833965Sjdp	}
297933965Sjdp    }
298033965Sjdp  else
298133965Sjdp    {
298233965Sjdp      for (;;)
298333965Sjdp	{
298433965Sjdp	  int i = 0;
298533965Sjdp	  c = getchar ();
298633965Sjdp	  /* Try to read a label.  */
298733965Sjdp	  while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
298833965Sjdp	    {
298933965Sjdp	      if (i >= MBUF_SIZE-1)
299033965Sjdp		break;
299133965Sjdp	      mbuffer[i++] = c;
299233965Sjdp	      c = getchar ();
299333965Sjdp	    }
299433965Sjdp	  if (i > 0)
299533965Sjdp	    {
299633965Sjdp	      int skip_first = 0;
299733965Sjdp
299833965Sjdp	      if (mbuffer[0] == '.')
299933965Sjdp		++skip_first;
300033965Sjdp	      if (strip_underscore && mbuffer[skip_first] == '_')
300133965Sjdp		++skip_first;
300233965Sjdp
300333965Sjdp	      if (skip_first > i)
300433965Sjdp		skip_first = i;
300533965Sjdp
300633965Sjdp	      mbuffer[i] = 0;
300733965Sjdp
300833965Sjdp	      result = cplus_demangle (mbuffer + skip_first,
300933965Sjdp				       DMGL_PARAMS | DMGL_ANSI);
301033965Sjdp	      if (result)
301133965Sjdp		{
301233965Sjdp		  if (mbuffer[0] == '.')
301333965Sjdp		    putc ('.', stdout);
301433965Sjdp		  fputs (result, stdout);
301533965Sjdp		  free (result);
301633965Sjdp		}
301733965Sjdp	      else
301833965Sjdp		fputs (mbuffer, stdout);
301933965Sjdp
302033965Sjdp	      fflush (stdout);
302133965Sjdp	    }
302233965Sjdp	  if (c == EOF)
302333965Sjdp	    break;
302433965Sjdp	  putchar (c);
302533965Sjdp	}
302633965Sjdp    }
302733965Sjdp
302833965Sjdp  exit (0);
302933965Sjdp}
303033965Sjdp
303133965Sjdpstatic void
303233965Sjdpfatal (str)
303333965Sjdp     char *str;
303433965Sjdp{
303533965Sjdp  fprintf (stderr, "%s: %s\n", program_name, str);
303633965Sjdp  exit (1);
303733965Sjdp}
303833965Sjdp
303933965Sjdpchar * malloc ();
304033965Sjdpchar * realloc ();
304133965Sjdp
304233965Sjdpchar *
304333965Sjdpxmalloc (size)
304433965Sjdp     unsigned size;
304533965Sjdp{
304633965Sjdp  register char *value = (char *) malloc (size);
304733965Sjdp  if (value == 0)
304833965Sjdp    fatal ("virtual memory exhausted");
304933965Sjdp  return value;
305033965Sjdp}
305133965Sjdp
305233965Sjdpchar *
305333965Sjdpxrealloc (ptr, size)
305433965Sjdp     char *ptr;
305533965Sjdp     unsigned size;
305633965Sjdp{
305733965Sjdp  register char *value = (char *) realloc (ptr, size);
305833965Sjdp  if (value == 0)
305933965Sjdp    fatal ("virtual memory exhausted");
306033965Sjdp  return value;
306133965Sjdp}
306233965Sjdp#endif	/* main */
3063