cplus-dem.c revision 77298
160484Sobrien/* Demangler for GNU C++
277298Sobrien   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
377298Sobrien   2000 Free Software Foundation, Inc.
433965Sjdp   Written by James Clark (jjc@jclark.uucp)
533965Sjdp   Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
660484Sobrien   Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
760484Sobrien
833965SjdpThis file is part of the libiberty library.
933965SjdpLibiberty is free software; you can redistribute it and/or
1033965Sjdpmodify it under the terms of the GNU Library General Public
1133965SjdpLicense as published by the Free Software Foundation; either
1233965Sjdpversion 2 of the License, or (at your option) any later version.
1333965Sjdp
1433965SjdpLibiberty is distributed in the hope that it will be useful,
1533965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1633965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1733965SjdpLibrary General Public License for more details.
1833965Sjdp
1933965SjdpYou should have received a copy of the GNU Library General Public
2033965SjdpLicense along with libiberty; see the file COPYING.LIB.  If
2133965Sjdpnot, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2233965SjdpBoston, MA 02111-1307, USA.  */
2333965Sjdp
2433965Sjdp/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
2533965Sjdp
2633965Sjdp   This file imports xmalloc and xrealloc, which are like malloc and
2733965Sjdp   realloc except that they generate a fatal error if there is no
2833965Sjdp   available memory.  */
2933965Sjdp
3033965Sjdp/* This file lives in both GCC and libiberty.  When making changes, please
3133965Sjdp   try not to break either.  */
3233965Sjdp
3360484Sobrien#ifdef HAVE_CONFIG_H
3460484Sobrien#include "config.h"
3560484Sobrien#endif
3660484Sobrien
3777298Sobrien#include "safe-ctype.h"
3877298Sobrien
3960484Sobrien#include <sys/types.h>
4033965Sjdp#include <string.h>
4133965Sjdp#include <stdio.h>
4233965Sjdp
4360484Sobrien#ifdef HAVE_STDLIB_H
4460484Sobrien#include <stdlib.h>
4560484Sobrien#else
4660484Sobrienchar * malloc ();
4760484Sobrienchar * realloc ();
4860484Sobrien#endif
4960484Sobrien
5033965Sjdp#include <demangle.h>
5133965Sjdp#undef CURRENT_DEMANGLING_STYLE
5233965Sjdp#define CURRENT_DEMANGLING_STYLE work->options
5333965Sjdp
5460484Sobrien#include "libiberty.h"
5533965Sjdp
5677298Sobrienstatic char *ada_demangle  PARAMS ((const char *, int));
5777298Sobrien
5860484Sobrien#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
5960484Sobrien
6060484Sobrien/* A value at least one greater than the maximum number of characters
6160484Sobrien   that will be output when using the `%d' format with `printf'.  */
6260484Sobrien#define INTBUF_SIZE 32
6360484Sobrien
6460484Sobrienextern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
6560484Sobrien
6633965Sjdpstatic const char *mystrstr PARAMS ((const char *, const char *));
6733965Sjdp
6833965Sjdpstatic const char *
6933965Sjdpmystrstr (s1, s2)
7033965Sjdp     const char *s1, *s2;
7133965Sjdp{
7233965Sjdp  register const char *p = s1;
7333965Sjdp  register int len = strlen (s2);
7433965Sjdp
7533965Sjdp  for (; (p = strchr (p, *s2)) != 0; p++)
7633965Sjdp    {
7733965Sjdp      if (strncmp (p, s2, len) == 0)
7833965Sjdp	{
7933965Sjdp	  return (p);
8033965Sjdp	}
8133965Sjdp    }
8233965Sjdp  return (0);
8333965Sjdp}
8433965Sjdp
8533965Sjdp/* In order to allow a single demangler executable to demangle strings
8633965Sjdp   using various common values of CPLUS_MARKER, as well as any specific
8733965Sjdp   one set at compile time, we maintain a string containing all the
8833965Sjdp   commonly used ones, and check to see if the marker we are looking for
8933965Sjdp   is in that string.  CPLUS_MARKER is usually '$' on systems where the
9033965Sjdp   assembler can deal with that.  Where the assembler can't, it's usually
9133965Sjdp   '.' (but on many systems '.' is used for other things).  We put the
9233965Sjdp   current defined CPLUS_MARKER first (which defaults to '$'), followed
9333965Sjdp   by the next most common value, followed by an explicit '$' in case
9433965Sjdp   the value of CPLUS_MARKER is not '$'.
9533965Sjdp
9633965Sjdp   We could avoid this if we could just get g++ to tell us what the actual
9733965Sjdp   cplus marker character is as part of the debug information, perhaps by
9833965Sjdp   ensuring that it is the character that terminates the gcc<n>_compiled
9933965Sjdp   marker symbol (FIXME).  */
10033965Sjdp
10133965Sjdp#if !defined (CPLUS_MARKER)
10233965Sjdp#define CPLUS_MARKER '$'
10333965Sjdp#endif
10433965Sjdp
10577298Sobrienenum demangling_styles current_demangling_style = auto_demangling;
10633965Sjdp
10733965Sjdpstatic char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
10833965Sjdp
10960484Sobrienstatic char char_str[2] = { '\000', '\000' };
11060484Sobrien
11133965Sjdpvoid
11233965Sjdpset_cplus_marker_for_demangling (ch)
11333965Sjdp     int ch;
11433965Sjdp{
11533965Sjdp  cplus_markers[0] = ch;
11633965Sjdp}
11733965Sjdp
11860484Sobrientypedef struct string		/* Beware: these aren't required to be */
11960484Sobrien{				/*  '\0' terminated.  */
12060484Sobrien  char *b;			/* pointer to start of string */
12160484Sobrien  char *p;			/* pointer after last character */
12260484Sobrien  char *e;			/* pointer after end of allocated space */
12360484Sobrien} string;
12460484Sobrien
12533965Sjdp/* Stuff that is shared between sub-routines.
12633965Sjdp   Using a shared structure allows cplus_demangle to be reentrant.  */
12733965Sjdp
12833965Sjdpstruct work_stuff
12933965Sjdp{
13033965Sjdp  int options;
13133965Sjdp  char **typevec;
13260484Sobrien  char **ktypevec;
13360484Sobrien  char **btypevec;
13460484Sobrien  int numk;
13560484Sobrien  int numb;
13660484Sobrien  int ksize;
13760484Sobrien  int bsize;
13833965Sjdp  int ntypes;
13933965Sjdp  int typevec_size;
14033965Sjdp  int constructor;
14133965Sjdp  int destructor;
14233965Sjdp  int static_type;	/* A static member function */
14360484Sobrien  int temp_start;       /* index in demangled to start of template args */
14460484Sobrien  int type_quals;       /* The type qualifiers.  */
14560484Sobrien  int dllimported;	/* Symbol imported from a PE DLL */
14638889Sjdp  char **tmpl_argvec;   /* Template function arguments. */
14738889Sjdp  int ntmpl_args;       /* The number of template function arguments. */
14860484Sobrien  int forgetting_types; /* Nonzero if we are not remembering the types
14960484Sobrien			   we see.  */
15060484Sobrien  string* previous_argument; /* The last function argument demangled.  */
15160484Sobrien  int nrepeats;         /* The number of times to repeat the previous
15260484Sobrien			   argument.  */
15333965Sjdp};
15433965Sjdp
15533965Sjdp#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
15633965Sjdp#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
15733965Sjdp
15833965Sjdpstatic const struct optable
15933965Sjdp{
16033965Sjdp  const char *in;
16133965Sjdp  const char *out;
16233965Sjdp  int flags;
16333965Sjdp} optable[] = {
16433965Sjdp  {"nw",	  " new",	DMGL_ANSI},	/* new (1.92,	 ansi) */
16533965Sjdp  {"dl",	  " delete",	DMGL_ANSI},	/* new (1.92,	 ansi) */
16633965Sjdp  {"new",	  " new",	0},		/* old (1.91,	 and 1.x) */
16733965Sjdp  {"delete",	  " delete",	0},		/* old (1.91,	 and 1.x) */
16833965Sjdp  {"vn",	  " new []",	DMGL_ANSI},	/* GNU, pending ansi */
16933965Sjdp  {"vd",	  " delete []",	DMGL_ANSI},	/* GNU, pending ansi */
17033965Sjdp  {"as",	  "=",		DMGL_ANSI},	/* ansi */
17133965Sjdp  {"ne",	  "!=",		DMGL_ANSI},	/* old, ansi */
17233965Sjdp  {"eq",	  "==",		DMGL_ANSI},	/* old,	ansi */
17333965Sjdp  {"ge",	  ">=",		DMGL_ANSI},	/* old,	ansi */
17433965Sjdp  {"gt",	  ">",		DMGL_ANSI},	/* old,	ansi */
17533965Sjdp  {"le",	  "<=",		DMGL_ANSI},	/* old,	ansi */
17633965Sjdp  {"lt",	  "<",		DMGL_ANSI},	/* old,	ansi */
17733965Sjdp  {"plus",	  "+",		0},		/* old */
17833965Sjdp  {"pl",	  "+",		DMGL_ANSI},	/* ansi */
17933965Sjdp  {"apl",	  "+=",		DMGL_ANSI},	/* ansi */
18033965Sjdp  {"minus",	  "-",		0},		/* old */
18133965Sjdp  {"mi",	  "-",		DMGL_ANSI},	/* ansi */
18233965Sjdp  {"ami",	  "-=",		DMGL_ANSI},	/* ansi */
18333965Sjdp  {"mult",	  "*",		0},		/* old */
18433965Sjdp  {"ml",	  "*",		DMGL_ANSI},	/* ansi */
18533965Sjdp  {"amu",	  "*=",		DMGL_ANSI},	/* ansi (ARM/Lucid) */
18633965Sjdp  {"aml",	  "*=",		DMGL_ANSI},	/* ansi (GNU/g++) */
18733965Sjdp  {"convert",	  "+",		0},		/* old (unary +) */
18833965Sjdp  {"negate",	  "-",		0},		/* old (unary -) */
18933965Sjdp  {"trunc_mod",	  "%",		0},		/* old */
19033965Sjdp  {"md",	  "%",		DMGL_ANSI},	/* ansi */
19133965Sjdp  {"amd",	  "%=",		DMGL_ANSI},	/* ansi */
19233965Sjdp  {"trunc_div",	  "/",		0},		/* old */
19333965Sjdp  {"dv",	  "/",		DMGL_ANSI},	/* ansi */
19433965Sjdp  {"adv",	  "/=",		DMGL_ANSI},	/* ansi */
19533965Sjdp  {"truth_andif", "&&",		0},		/* old */
19633965Sjdp  {"aa",	  "&&",		DMGL_ANSI},	/* ansi */
19733965Sjdp  {"truth_orif",  "||",		0},		/* old */
19833965Sjdp  {"oo",	  "||",		DMGL_ANSI},	/* ansi */
19933965Sjdp  {"truth_not",	  "!",		0},		/* old */
20033965Sjdp  {"nt",	  "!",		DMGL_ANSI},	/* ansi */
20133965Sjdp  {"postincrement","++",	0},		/* old */
20233965Sjdp  {"pp",	  "++",		DMGL_ANSI},	/* ansi */
20333965Sjdp  {"postdecrement","--",	0},		/* old */
20433965Sjdp  {"mm",	  "--",		DMGL_ANSI},	/* ansi */
20533965Sjdp  {"bit_ior",	  "|",		0},		/* old */
20633965Sjdp  {"or",	  "|",		DMGL_ANSI},	/* ansi */
20733965Sjdp  {"aor",	  "|=",		DMGL_ANSI},	/* ansi */
20833965Sjdp  {"bit_xor",	  "^",		0},		/* old */
20933965Sjdp  {"er",	  "^",		DMGL_ANSI},	/* ansi */
21033965Sjdp  {"aer",	  "^=",		DMGL_ANSI},	/* ansi */
21133965Sjdp  {"bit_and",	  "&",		0},		/* old */
21233965Sjdp  {"ad",	  "&",		DMGL_ANSI},	/* ansi */
21333965Sjdp  {"aad",	  "&=",		DMGL_ANSI},	/* ansi */
21433965Sjdp  {"bit_not",	  "~",		0},		/* old */
21533965Sjdp  {"co",	  "~",		DMGL_ANSI},	/* ansi */
21633965Sjdp  {"call",	  "()",		0},		/* old */
21733965Sjdp  {"cl",	  "()",		DMGL_ANSI},	/* ansi */
21833965Sjdp  {"alshift",	  "<<",		0},		/* old */
21933965Sjdp  {"ls",	  "<<",		DMGL_ANSI},	/* ansi */
22033965Sjdp  {"als",	  "<<=",	DMGL_ANSI},	/* ansi */
22133965Sjdp  {"arshift",	  ">>",		0},		/* old */
22233965Sjdp  {"rs",	  ">>",		DMGL_ANSI},	/* ansi */
22333965Sjdp  {"ars",	  ">>=",	DMGL_ANSI},	/* ansi */
22433965Sjdp  {"component",	  "->",		0},		/* old */
22533965Sjdp  {"pt",	  "->",		DMGL_ANSI},	/* ansi; Lucid C++ form */
22633965Sjdp  {"rf",	  "->",		DMGL_ANSI},	/* ansi; ARM/GNU form */
22733965Sjdp  {"indirect",	  "*",		0},		/* old */
22833965Sjdp  {"method_call",  "->()",	0},		/* old */
22933965Sjdp  {"addr",	  "&",		0},		/* old (unary &) */
23033965Sjdp  {"array",	  "[]",		0},		/* old */
23133965Sjdp  {"vc",	  "[]",		DMGL_ANSI},	/* ansi */
23233965Sjdp  {"compound",	  ", ",		0},		/* old */
23333965Sjdp  {"cm",	  ", ",		DMGL_ANSI},	/* ansi */
23433965Sjdp  {"cond",	  "?:",		0},		/* old */
23533965Sjdp  {"cn",	  "?:",		DMGL_ANSI},	/* pseudo-ansi */
23633965Sjdp  {"max",	  ">?",		0},		/* old */
23733965Sjdp  {"mx",	  ">?",		DMGL_ANSI},	/* pseudo-ansi */
23833965Sjdp  {"min",	  "<?",		0},		/* old */
23933965Sjdp  {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
24033965Sjdp  {"nop",	  "",		0},		/* old (for operator=) */
24160484Sobrien  {"rm",	  "->*",	DMGL_ANSI},	/* ansi */
24260484Sobrien  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
24333965Sjdp};
24433965Sjdp
24560484Sobrien/* These values are used to indicate the various type varieties.
24660484Sobrien   They are all non-zero so that they can be used as `success'
24760484Sobrien   values.  */
24860484Sobrientypedef enum type_kind_t
24960484Sobrien{
25060484Sobrien  tk_none,
25160484Sobrien  tk_pointer,
25260484Sobrien  tk_reference,
25360484Sobrien  tk_integral,
25460484Sobrien  tk_bool,
25560484Sobrien  tk_char,
25660484Sobrien  tk_real
25760484Sobrien} type_kind_t;
25833965Sjdp
25968765Sobrienstruct demangler_engine libiberty_demanglers[] =
26068765Sobrien{
26168765Sobrien  {
26268765Sobrien    AUTO_DEMANGLING_STYLE_STRING,
26368765Sobrien      auto_demangling,
26468765Sobrien      "Automatic selection based on executable"
26568765Sobrien  }
26668765Sobrien  ,
26768765Sobrien  {
26868765Sobrien    GNU_DEMANGLING_STYLE_STRING,
26968765Sobrien      gnu_demangling,
27068765Sobrien      "GNU (g++) style demangling"
27168765Sobrien  }
27268765Sobrien  ,
27368765Sobrien  {
27468765Sobrien    LUCID_DEMANGLING_STYLE_STRING,
27568765Sobrien      lucid_demangling,
27668765Sobrien      "Lucid (lcc) style demangling"
27768765Sobrien  }
27868765Sobrien  ,
27968765Sobrien  {
28068765Sobrien    ARM_DEMANGLING_STYLE_STRING,
28168765Sobrien      arm_demangling,
28268765Sobrien      "ARM style demangling"
28368765Sobrien  }
28468765Sobrien  ,
28568765Sobrien  {
28668765Sobrien    HP_DEMANGLING_STYLE_STRING,
28768765Sobrien      hp_demangling,
28868765Sobrien      "HP (aCC) style demangling"
28968765Sobrien  }
29068765Sobrien  ,
29168765Sobrien  {
29268765Sobrien    EDG_DEMANGLING_STYLE_STRING,
29368765Sobrien      edg_demangling,
29468765Sobrien      "EDG style demangling"
29568765Sobrien  }
29668765Sobrien  ,
29768765Sobrien  {
29877298Sobrien    GNU_V3_DEMANGLING_STYLE_STRING,
29977298Sobrien    gnu_v3_demangling,
30077298Sobrien    "GNU (g++) V3 ABI-style demangling"
30168765Sobrien  }
30268765Sobrien  ,
30368765Sobrien  {
30477298Sobrien    JAVA_DEMANGLING_STYLE_STRING,
30577298Sobrien    java_demangling,
30677298Sobrien    "Java style demangling"
30777298Sobrien  }
30877298Sobrien  ,
30977298Sobrien  {
31077298Sobrien    GNAT_DEMANGLING_STYLE_STRING,
31177298Sobrien    gnat_demangling,
31277298Sobrien    "GNAT style demangling"
31377298Sobrien  }
31477298Sobrien  ,
31577298Sobrien  {
31668765Sobrien    NULL, unknown_demangling, NULL
31768765Sobrien  }
31868765Sobrien};
31968765Sobrien
32033965Sjdp#define STRING_EMPTY(str)	((str) -> b == (str) -> p)
32133965Sjdp#define PREPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
32233965Sjdp    string_prepend(str, " ");}
32333965Sjdp#define APPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
32433965Sjdp    string_append(str, " ");}
32560484Sobrien#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
32633965Sjdp
32760484Sobrien/* The scope separator appropriate for the language being demangled.  */
32860484Sobrien
32960484Sobrien#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
33060484Sobrien
33133965Sjdp#define ARM_VTABLE_STRING "__vtbl__"	/* Lucid/ARM virtual table prefix */
33233965Sjdp#define ARM_VTABLE_STRLEN 8		/* strlen (ARM_VTABLE_STRING) */
33333965Sjdp
33433965Sjdp/* Prototypes for local functions */
33533965Sjdp
33668765Sobrienstatic void
33768765Sobriendelete_work_stuff PARAMS ((struct work_stuff *));
33868765Sobrien
33968765Sobrienstatic void
34068765Sobriendelete_non_B_K_work_stuff PARAMS ((struct work_stuff *));
34168765Sobrien
34233965Sjdpstatic char *
34333965Sjdpmop_up PARAMS ((struct work_stuff *, string *, int));
34433965Sjdp
34560484Sobrienstatic void
34660484Sobriensquangle_mop_up PARAMS ((struct work_stuff *));
34760484Sobrien
34868765Sobrienstatic void
34968765Sobrienwork_stuff_copy_to_from PARAMS ((struct work_stuff *, struct work_stuff *));
35068765Sobrien
35133965Sjdp#if 0
35233965Sjdpstatic int
35360484Sobriendemangle_method_args PARAMS ((struct work_stuff *, const char **, string *));
35433965Sjdp#endif
35533965Sjdp
35660484Sobrienstatic char *
35760484Sobrieninternal_cplus_demangle PARAMS ((struct work_stuff *, const char *));
35860484Sobrien
35933965Sjdpstatic int
36060484Sobriendemangle_template_template_parm PARAMS ((struct work_stuff *work,
36160484Sobrien					 const char **, string *));
36260484Sobrien
36360484Sobrienstatic int
36433965Sjdpdemangle_template PARAMS ((struct work_stuff *work, const char **, string *,
36560484Sobrien			   string *, int, int));
36633965Sjdp
36733965Sjdpstatic int
36833965Sjdparm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
36933965Sjdp		const char **));
37033965Sjdp
37133965Sjdpstatic int
37233965Sjdpdemangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
37333965Sjdp
37433965Sjdpstatic int
37533965Sjdpdemangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
37633965Sjdp			    int, int));
37733965Sjdp
37833965Sjdpstatic int
37933965Sjdpdemangle_class PARAMS ((struct work_stuff *, const char **, string *));
38033965Sjdp
38133965Sjdpstatic int
38233965Sjdpdemangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
38333965Sjdp
38433965Sjdpstatic int
38533965Sjdpdemangle_signature PARAMS ((struct work_stuff *, const char **, string *));
38633965Sjdp
38733965Sjdpstatic int
38833965Sjdpdemangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
38933965Sjdp
39033965Sjdpstatic int
39133965Sjdpgnu_special PARAMS ((struct work_stuff *, const char **, string *));
39233965Sjdp
39333965Sjdpstatic int
39460484Sobrienarm_special PARAMS ((const char **, string *));
39533965Sjdp
39633965Sjdpstatic void
39733965Sjdpstring_need PARAMS ((string *, int));
39833965Sjdp
39933965Sjdpstatic void
40033965Sjdpstring_delete PARAMS ((string *));
40133965Sjdp
40233965Sjdpstatic void
40333965Sjdpstring_init PARAMS ((string *));
40433965Sjdp
40533965Sjdpstatic void
40633965Sjdpstring_clear PARAMS ((string *));
40733965Sjdp
40833965Sjdp#if 0
40933965Sjdpstatic int
41033965Sjdpstring_empty PARAMS ((string *));
41133965Sjdp#endif
41233965Sjdp
41333965Sjdpstatic void
41433965Sjdpstring_append PARAMS ((string *, const char *));
41533965Sjdp
41633965Sjdpstatic void
41733965Sjdpstring_appends PARAMS ((string *, string *));
41833965Sjdp
41933965Sjdpstatic void
42033965Sjdpstring_appendn PARAMS ((string *, const char *, int));
42133965Sjdp
42233965Sjdpstatic void
42333965Sjdpstring_prepend PARAMS ((string *, const char *));
42433965Sjdp
42533965Sjdpstatic void
42633965Sjdpstring_prependn PARAMS ((string *, const char *, int));
42733965Sjdp
42860484Sobrienstatic void
42960484Sobrienstring_append_template_idx PARAMS ((string *, int));
43060484Sobrien
43133965Sjdpstatic int
43233965Sjdpget_count PARAMS ((const char **, int *));
43333965Sjdp
43433965Sjdpstatic int
43533965Sjdpconsume_count PARAMS ((const char **));
43633965Sjdp
43760484Sobrienstatic int
43838889Sjdpconsume_count_with_underscores PARAMS ((const char**));
43938889Sjdp
44033965Sjdpstatic int
44133965Sjdpdemangle_args PARAMS ((struct work_stuff *, const char **, string *));
44233965Sjdp
44333965Sjdpstatic int
44460484Sobriendemangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
44560484Sobrien
44660484Sobrienstatic int
44733965Sjdpdo_type PARAMS ((struct work_stuff *, const char **, string *));
44833965Sjdp
44933965Sjdpstatic int
45033965Sjdpdo_arg PARAMS ((struct work_stuff *, const char **, string *));
45133965Sjdp
45233965Sjdpstatic void
45333965Sjdpdemangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
45433965Sjdp				const char *));
45533965Sjdp
45668765Sobrienstatic int
45768765Sobrieniterate_demangle_function PARAMS ((struct work_stuff *,
45868765Sobrien				   const char **, string *, const char *));
45968765Sobrien
46033965Sjdpstatic void
46133965Sjdpremember_type PARAMS ((struct work_stuff *, const char *, int));
46233965Sjdp
46333965Sjdpstatic void
46460484Sobrienremember_Btype PARAMS ((struct work_stuff *, const char *, int, int));
46560484Sobrien
46660484Sobrienstatic int
46760484Sobrienregister_Btype PARAMS ((struct work_stuff *));
46860484Sobrien
46960484Sobrienstatic void
47060484Sobrienremember_Ktype PARAMS ((struct work_stuff *, const char *, int));
47160484Sobrien
47260484Sobrienstatic void
47333965Sjdpforget_types PARAMS ((struct work_stuff *));
47433965Sjdp
47533965Sjdpstatic void
47660484Sobrienforget_B_and_K_types PARAMS ((struct work_stuff *));
47760484Sobrien
47860484Sobrienstatic void
47933965Sjdpstring_prepends PARAMS ((string *, string *));
48033965Sjdp
48160484Sobrienstatic int
48260484Sobriendemangle_template_value_parm PARAMS ((struct work_stuff*, const char**,
48360484Sobrien				      string*, type_kind_t));
48433965Sjdp
48533965Sjdpstatic int
48660484Sobriendo_hpacc_template_const_value PARAMS ((struct work_stuff *, const char **, string *));
48760484Sobrien
48860484Sobrienstatic int
48960484Sobriendo_hpacc_template_literal PARAMS ((struct work_stuff *, const char **, string *));
49060484Sobrien
49160484Sobrienstatic int
49260484Sobriensnarf_numeric_literal PARAMS ((const char **, string *));
49360484Sobrien
49460484Sobrien/* There is a TYPE_QUAL value for each type qualifier.  They can be
49560484Sobrien   combined by bitwise-or to form the complete set of qualifiers for a
49660484Sobrien   type.  */
49760484Sobrien
49860484Sobrien#define TYPE_UNQUALIFIED   0x0
49960484Sobrien#define TYPE_QUAL_CONST    0x1
50060484Sobrien#define TYPE_QUAL_VOLATILE 0x2
50160484Sobrien#define TYPE_QUAL_RESTRICT 0x4
50260484Sobrien
50360484Sobrienstatic int
50460484Sobriencode_for_qualifier PARAMS ((int));
50560484Sobrien
50660484Sobrienstatic const char*
50760484Sobrienqualifier_string PARAMS ((int));
50860484Sobrien
50960484Sobrienstatic const char*
51060484Sobriendemangle_qualifier PARAMS ((int));
51160484Sobrien
51260484Sobrienstatic int
51360484Sobriendemangle_expression PARAMS ((struct work_stuff *, const char **, string *,
51460484Sobrien			     type_kind_t));
51560484Sobrien
51660484Sobrienstatic int
51760484Sobriendemangle_integral_value PARAMS ((struct work_stuff *, const char **,
51860484Sobrien				 string *));
51960484Sobrien
52060484Sobrienstatic int
52160484Sobriendemangle_real_value PARAMS ((struct work_stuff *, const char **, string *));
52260484Sobrien
52360484Sobrienstatic void
52460484Sobriendemangle_arm_hp_template PARAMS ((struct work_stuff *, const char **, int,
52560484Sobrien				  string *));
52660484Sobrien
52760484Sobrienstatic void
52860484Sobrienrecursively_demangle PARAMS ((struct work_stuff *, const char **, string *,
52960484Sobrien			      int));
53060484Sobrien
53177298Sobrienstatic void
53277298Sobriengrow_vect PARAMS ((void **, size_t *, size_t, int));
53377298Sobrien
53460484Sobrien/* Translate count to integer, consuming tokens in the process.
53560484Sobrien   Conversion terminates on the first non-digit character.
53660484Sobrien
53760484Sobrien   Trying to consume something that isn't a count results in no
53860484Sobrien   consumption of input and a return of -1.
53960484Sobrien
54060484Sobrien   Overflow consumes the rest of the digits, and returns -1.  */
54160484Sobrien
54260484Sobrienstatic int
54333965Sjdpconsume_count (type)
54433965Sjdp     const char **type;
54533965Sjdp{
54633965Sjdp  int count = 0;
54733965Sjdp
54877298Sobrien  if (! ISDIGIT ((unsigned char)**type))
54960484Sobrien    return -1;
55060484Sobrien
55177298Sobrien  while (ISDIGIT ((unsigned char)**type))
55233965Sjdp    {
55333965Sjdp      count *= 10;
55460484Sobrien
55560484Sobrien      /* Check for overflow.
55660484Sobrien	 We assume that count is represented using two's-complement;
55760484Sobrien	 no power of two is divisible by ten, so if an overflow occurs
55860484Sobrien	 when multiplying by ten, the result will not be a multiple of
55960484Sobrien	 ten.  */
56060484Sobrien      if ((count % 10) != 0)
56160484Sobrien	{
56277298Sobrien	  while (ISDIGIT ((unsigned char) **type))
56360484Sobrien	    (*type)++;
56460484Sobrien	  return -1;
56560484Sobrien	}
56660484Sobrien
56733965Sjdp      count += **type - '0';
56833965Sjdp      (*type)++;
56933965Sjdp    }
57060484Sobrien
57133965Sjdp  return (count);
57233965Sjdp}
57333965Sjdp
57438889Sjdp
57560484Sobrien/* Like consume_count, but for counts that are preceded and followed
57638889Sjdp   by '_' if they are greater than 10.  Also, -1 is returned for
57738889Sjdp   failure, since 0 can be a valid value.  */
57838889Sjdp
57938889Sjdpstatic int
58038889Sjdpconsume_count_with_underscores (mangled)
58138889Sjdp     const char **mangled;
58238889Sjdp{
58338889Sjdp  int idx;
58438889Sjdp
58538889Sjdp  if (**mangled == '_')
58638889Sjdp    {
58738889Sjdp      (*mangled)++;
58877298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
58938889Sjdp	return -1;
59038889Sjdp
59138889Sjdp      idx = consume_count (mangled);
59238889Sjdp      if (**mangled != '_')
59338889Sjdp	/* The trailing underscore was missing. */
59438889Sjdp	return -1;
59560484Sobrien
59638889Sjdp      (*mangled)++;
59738889Sjdp    }
59838889Sjdp  else
59938889Sjdp    {
60038889Sjdp      if (**mangled < '0' || **mangled > '9')
60138889Sjdp	return -1;
60260484Sobrien
60338889Sjdp      idx = **mangled - '0';
60438889Sjdp      (*mangled)++;
60538889Sjdp    }
60638889Sjdp
60738889Sjdp  return idx;
60838889Sjdp}
60938889Sjdp
61060484Sobrien/* C is the code for a type-qualifier.  Return the TYPE_QUAL
61160484Sobrien   corresponding to this qualifier.  */
61260484Sobrien
61360484Sobrienstatic int
61460484Sobriencode_for_qualifier (c)
61560484Sobrien  int c;
61660484Sobrien{
61760484Sobrien  switch (c)
61860484Sobrien    {
61960484Sobrien    case 'C':
62060484Sobrien      return TYPE_QUAL_CONST;
62160484Sobrien
62260484Sobrien    case 'V':
62360484Sobrien      return TYPE_QUAL_VOLATILE;
62460484Sobrien
62560484Sobrien    case 'u':
62660484Sobrien      return TYPE_QUAL_RESTRICT;
62760484Sobrien
62860484Sobrien    default:
62960484Sobrien      break;
63060484Sobrien    }
63160484Sobrien
63260484Sobrien  /* C was an invalid qualifier.  */
63360484Sobrien  abort ();
63460484Sobrien}
63560484Sobrien
63660484Sobrien/* Return the string corresponding to the qualifiers given by
63760484Sobrien   TYPE_QUALS.  */
63860484Sobrien
63960484Sobrienstatic const char*
64060484Sobrienqualifier_string (type_quals)
64160484Sobrien     int type_quals;
64260484Sobrien{
64360484Sobrien  switch (type_quals)
64460484Sobrien    {
64560484Sobrien    case TYPE_UNQUALIFIED:
64660484Sobrien      return "";
64760484Sobrien
64860484Sobrien    case TYPE_QUAL_CONST:
64960484Sobrien      return "const";
65060484Sobrien
65160484Sobrien    case TYPE_QUAL_VOLATILE:
65260484Sobrien      return "volatile";
65360484Sobrien
65460484Sobrien    case TYPE_QUAL_RESTRICT:
65560484Sobrien      return "__restrict";
65660484Sobrien
65760484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
65860484Sobrien      return "const volatile";
65960484Sobrien
66060484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
66160484Sobrien      return "const __restrict";
66260484Sobrien
66360484Sobrien    case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
66460484Sobrien      return "volatile __restrict";
66560484Sobrien
66660484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
66760484Sobrien      return "const volatile __restrict";
66860484Sobrien
66960484Sobrien    default:
67060484Sobrien      break;
67160484Sobrien    }
67260484Sobrien
67360484Sobrien  /* TYPE_QUALS was an invalid qualifier set.  */
67460484Sobrien  abort ();
67560484Sobrien}
67660484Sobrien
67760484Sobrien/* C is the code for a type-qualifier.  Return the string
67860484Sobrien   corresponding to this qualifier.  This function should only be
67960484Sobrien   called with a valid qualifier code.  */
68060484Sobrien
68160484Sobrienstatic const char*
68260484Sobriendemangle_qualifier (c)
68360484Sobrien  int c;
68460484Sobrien{
68560484Sobrien  return qualifier_string (code_for_qualifier (c));
68660484Sobrien}
68760484Sobrien
68833965Sjdpint
68933965Sjdpcplus_demangle_opname (opname, result, options)
69033965Sjdp     const char *opname;
69133965Sjdp     char *result;
69233965Sjdp     int options;
69333965Sjdp{
69460484Sobrien  int len, len1, ret;
69533965Sjdp  string type;
69633965Sjdp  struct work_stuff work[1];
69733965Sjdp  const char *tem;
69833965Sjdp
69933965Sjdp  len = strlen(opname);
70033965Sjdp  result[0] = '\0';
70133965Sjdp  ret = 0;
70260484Sobrien  memset ((char *) work, 0, sizeof (work));
70333965Sjdp  work->options = options;
70460484Sobrien
70533965Sjdp  if (opname[0] == '_' && opname[1] == '_'
70633965Sjdp      && opname[2] == 'o' && opname[3] == 'p')
70733965Sjdp    {
70833965Sjdp      /* ANSI.  */
70933965Sjdp      /* type conversion operator.  */
71033965Sjdp      tem = opname + 4;
71133965Sjdp      if (do_type (work, &tem, &type))
71233965Sjdp	{
71333965Sjdp	  strcat (result, "operator ");
71433965Sjdp	  strncat (result, type.b, type.p - type.b);
71533965Sjdp	  string_delete (&type);
71633965Sjdp	  ret = 1;
71733965Sjdp	}
71833965Sjdp    }
71933965Sjdp  else if (opname[0] == '_' && opname[1] == '_'
72077298Sobrien	   && ISLOWER((unsigned char)opname[2])
72177298Sobrien	   && ISLOWER((unsigned char)opname[3]))
72233965Sjdp    {
72333965Sjdp      if (opname[4] == '\0')
72433965Sjdp	{
72533965Sjdp	  /* Operator.  */
72660484Sobrien	  size_t i;
72777298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
72833965Sjdp	    {
72933965Sjdp	      if (strlen (optable[i].in) == 2
73033965Sjdp		  && memcmp (optable[i].in, opname + 2, 2) == 0)
73133965Sjdp		{
73233965Sjdp		  strcat (result, "operator");
73333965Sjdp		  strcat (result, optable[i].out);
73433965Sjdp		  ret = 1;
73533965Sjdp		  break;
73633965Sjdp		}
73733965Sjdp	    }
73833965Sjdp	}
73933965Sjdp      else
74033965Sjdp	{
74133965Sjdp	  if (opname[2] == 'a' && opname[5] == '\0')
74233965Sjdp	    {
74333965Sjdp	      /* Assignment.  */
74460484Sobrien	      size_t i;
74577298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
74633965Sjdp		{
74733965Sjdp		  if (strlen (optable[i].in) == 3
74833965Sjdp		      && memcmp (optable[i].in, opname + 2, 3) == 0)
74933965Sjdp		    {
75033965Sjdp		      strcat (result, "operator");
75133965Sjdp		      strcat (result, optable[i].out);
75233965Sjdp		      ret = 1;
75333965Sjdp		      break;
75460484Sobrien		    }
75533965Sjdp		}
75633965Sjdp	    }
75733965Sjdp	}
75833965Sjdp    }
75960484Sobrien  else if (len >= 3
76033965Sjdp	   && opname[0] == 'o'
76133965Sjdp	   && opname[1] == 'p'
76233965Sjdp	   && strchr (cplus_markers, opname[2]) != NULL)
76333965Sjdp    {
76433965Sjdp      /* see if it's an assignment expression */
76533965Sjdp      if (len >= 10 /* op$assign_ */
76633965Sjdp	  && memcmp (opname + 3, "assign_", 7) == 0)
76733965Sjdp	{
76860484Sobrien	  size_t i;
76977298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
77033965Sjdp	    {
77133965Sjdp	      len1 = len - 10;
77260484Sobrien	      if ((int) strlen (optable[i].in) == len1
77333965Sjdp		  && memcmp (optable[i].in, opname + 10, len1) == 0)
77433965Sjdp		{
77533965Sjdp		  strcat (result, "operator");
77633965Sjdp		  strcat (result, optable[i].out);
77733965Sjdp		  strcat (result, "=");
77833965Sjdp		  ret = 1;
77933965Sjdp		  break;
78033965Sjdp		}
78133965Sjdp	    }
78233965Sjdp	}
78333965Sjdp      else
78433965Sjdp	{
78560484Sobrien	  size_t i;
78677298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
78733965Sjdp	    {
78833965Sjdp	      len1 = len - 3;
78960484Sobrien	      if ((int) strlen (optable[i].in) == len1
79033965Sjdp		  && memcmp (optable[i].in, opname + 3, len1) == 0)
79133965Sjdp		{
79233965Sjdp		  strcat (result, "operator");
79333965Sjdp		  strcat (result, optable[i].out);
79433965Sjdp		  ret = 1;
79533965Sjdp		  break;
79633965Sjdp		}
79733965Sjdp	    }
79833965Sjdp	}
79933965Sjdp    }
80033965Sjdp  else if (len >= 5 && memcmp (opname, "type", 4) == 0
80133965Sjdp	   && strchr (cplus_markers, opname[4]) != NULL)
80233965Sjdp    {
80333965Sjdp      /* type conversion operator */
80433965Sjdp      tem = opname + 5;
80533965Sjdp      if (do_type (work, &tem, &type))
80633965Sjdp	{
80733965Sjdp	  strcat (result, "operator ");
80833965Sjdp	  strncat (result, type.b, type.p - type.b);
80933965Sjdp	  string_delete (&type);
81033965Sjdp	  ret = 1;
81133965Sjdp	}
81233965Sjdp    }
81360484Sobrien  squangle_mop_up (work);
81433965Sjdp  return ret;
81533965Sjdp
81633965Sjdp}
81768765Sobrien
81833965Sjdp/* Takes operator name as e.g. "++" and returns mangled
81933965Sjdp   operator name (e.g. "postincrement_expr"), or NULL if not found.
82033965Sjdp
82133965Sjdp   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
82233965Sjdp   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
82333965Sjdp
82433965Sjdpconst char *
82533965Sjdpcplus_mangle_opname (opname, options)
82633965Sjdp     const char *opname;
82733965Sjdp     int options;
82833965Sjdp{
82960484Sobrien  size_t i;
83033965Sjdp  int len;
83133965Sjdp
83233965Sjdp  len = strlen (opname);
83377298Sobrien  for (i = 0; i < ARRAY_SIZE (optable); i++)
83433965Sjdp    {
83560484Sobrien      if ((int) strlen (optable[i].out) == len
83633965Sjdp	  && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
83733965Sjdp	  && memcmp (optable[i].out, opname, len) == 0)
83833965Sjdp	return optable[i].in;
83933965Sjdp    }
84033965Sjdp  return (0);
84133965Sjdp}
84233965Sjdp
84368765Sobrien/* Add a routine to set the demangling style to be sure it is valid and
84468765Sobrien   allow for any demangler initialization that maybe necessary. */
84568765Sobrien
84668765Sobrienenum demangling_styles
84768765Sobriencplus_demangle_set_style (style)
84868765Sobrien     enum demangling_styles style;
84968765Sobrien{
85068765Sobrien  struct demangler_engine *demangler = libiberty_demanglers;
85168765Sobrien
85268765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
85368765Sobrien    if (style == demangler->demangling_style)
85468765Sobrien      {
85568765Sobrien	current_demangling_style = style;
85668765Sobrien	return current_demangling_style;
85768765Sobrien      }
85868765Sobrien
85968765Sobrien  return unknown_demangling;
86068765Sobrien}
86168765Sobrien
86268765Sobrien/* Do string name to style translation */
86368765Sobrien
86468765Sobrienenum demangling_styles
86568765Sobriencplus_demangle_name_to_style (name)
86668765Sobrien     const char *name;
86768765Sobrien{
86868765Sobrien  struct demangler_engine *demangler = libiberty_demanglers;
86968765Sobrien
87068765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
87168765Sobrien    if (strcmp (name, demangler->demangling_style_name) == 0)
87268765Sobrien      return demangler->demangling_style;
87368765Sobrien
87468765Sobrien  return unknown_demangling;
87568765Sobrien}
87668765Sobrien
87733965Sjdp/* char *cplus_demangle (const char *mangled, int options)
87833965Sjdp
87933965Sjdp   If MANGLED is a mangled function name produced by GNU C++, then
88033965Sjdp   a pointer to a malloced string giving a C++ representation
88133965Sjdp   of the name will be returned; otherwise NULL will be returned.
88233965Sjdp   It is the caller's responsibility to free the string which
88333965Sjdp   is returned.
88433965Sjdp
88533965Sjdp   The OPTIONS arg may contain one or more of the following bits:
88633965Sjdp
88733965Sjdp   	DMGL_ANSI	ANSI qualifiers such as `const' and `void' are
88833965Sjdp			included.
88933965Sjdp	DMGL_PARAMS	Function parameters are included.
89033965Sjdp
89133965Sjdp   For example,
89260484Sobrien
89333965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS)		=> "A::foo(int)"
89433965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)	=> "A::foo(int)"
89533965Sjdp   cplus_demangle ("foo__1Ai", 0)			=> "A::foo"
89633965Sjdp
89733965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS)		=> "A::foo(float,...)"
89833965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
89933965Sjdp   cplus_demangle ("foo__1Afe", 0)			=> "A::foo"
90033965Sjdp
90133965Sjdp   Note that any leading underscores, or other such characters prepended by
90233965Sjdp   the compilation system, are presumed to have already been stripped from
90333965Sjdp   MANGLED.  */
90433965Sjdp
90533965Sjdpchar *
90633965Sjdpcplus_demangle (mangled, options)
90733965Sjdp     const char *mangled;
90833965Sjdp     int options;
90933965Sjdp{
91060484Sobrien  char *ret;
91160484Sobrien  struct work_stuff work[1];
91260484Sobrien  memset ((char *) work, 0, sizeof (work));
91377298Sobrien  work->options = options;
91477298Sobrien  if ((work->options & DMGL_STYLE_MASK) == 0)
91577298Sobrien    work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
91660484Sobrien
91777298Sobrien  /* The V3 ABI demangling is implemented elsewhere.  */
91877298Sobrien  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
91977298Sobrien    {
92077298Sobrien      ret = cplus_demangle_v3 (mangled);
92177298Sobrien      if (ret || GNU_V3_DEMANGLING)
92277298Sobrien	return ret;
92377298Sobrien    }
92468765Sobrien
92577298Sobrien  if (GNAT_DEMANGLING)
92677298Sobrien    return ada_demangle(mangled,options);
92777298Sobrien
92860484Sobrien  ret = internal_cplus_demangle (work, mangled);
92960484Sobrien  squangle_mop_up (work);
93060484Sobrien  return (ret);
93160484Sobrien}
93260484Sobrien
93360484Sobrien
93477298Sobrien/* Assuming *OLD_VECT points to an array of *SIZE objects of size
93577298Sobrien   ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
93677298Sobrien   updating *OLD_VECT and *SIZE as necessary.  */
93777298Sobrien
93877298Sobrienstatic void
93977298Sobriengrow_vect (old_vect, size, min_size, element_size)
94077298Sobrien     void **old_vect;
94177298Sobrien     size_t *size;
94277298Sobrien     size_t min_size;
94377298Sobrien     int element_size;
94477298Sobrien{
94577298Sobrien  if (*size < min_size)
94677298Sobrien    {
94777298Sobrien      *size *= 2;
94877298Sobrien      if (*size < min_size)
94977298Sobrien	*size = min_size;
95077298Sobrien      *old_vect = xrealloc (*old_vect, *size * element_size);
95177298Sobrien    }
95277298Sobrien}
95377298Sobrien
95477298Sobrien/* Demangle ada names:
95577298Sobrien   1. Discard final __{DIGIT}+ or ${DIGIT}+
95677298Sobrien   2. Convert other instances of embedded "__" to `.'.
95777298Sobrien   3. Discard leading _ada_.
95877298Sobrien   4. Remove everything after first ___ if it is followed by 'X'.
95977298Sobrien   5. Put symbols that should be suppressed in <...> brackets.
96077298Sobrien   The resulting string is valid until the next call of ada_demangle.  */
96177298Sobrien
96277298Sobrienstatic char *
96377298Sobrienada_demangle (mangled, option)
96477298Sobrien     const char *mangled;
96577298Sobrien     int option ATTRIBUTE_UNUSED;
96677298Sobrien{
96777298Sobrien  int i, j;
96877298Sobrien  int len0;
96977298Sobrien  const char* p;
97077298Sobrien  char *demangled = NULL;
97177298Sobrien  int at_start_name;
97277298Sobrien  int changed;
97377298Sobrien  char *demangling_buffer = NULL;
97477298Sobrien  size_t demangling_buffer_size = 0;
97577298Sobrien
97677298Sobrien  changed = 0;
97777298Sobrien
97877298Sobrien  if (strncmp (mangled, "_ada_", 5) == 0)
97977298Sobrien    {
98077298Sobrien      mangled += 5;
98177298Sobrien      changed = 1;
98277298Sobrien    }
98377298Sobrien
98477298Sobrien  if (mangled[0] == '_' || mangled[0] == '<')
98577298Sobrien    goto Suppress;
98677298Sobrien
98777298Sobrien  p = strstr (mangled, "___");
98877298Sobrien  if (p == NULL)
98977298Sobrien    len0 = strlen (mangled);
99077298Sobrien  else
99177298Sobrien    {
99277298Sobrien      if (p[3] == 'X')
99377298Sobrien	{
99477298Sobrien	  len0 = p - mangled;
99577298Sobrien	  changed = 1;
99677298Sobrien	}
99777298Sobrien      else
99877298Sobrien	goto Suppress;
99977298Sobrien    }
100077298Sobrien
100177298Sobrien  /* Make demangled big enough for possible expansion by operator name.  */
100277298Sobrien  grow_vect ((void **) &(demangling_buffer),
100377298Sobrien	     &demangling_buffer_size,  2 * len0 + 1,
100477298Sobrien	     sizeof (char));
100577298Sobrien  demangled = demangling_buffer;
100677298Sobrien
100777298Sobrien  if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
100877298Sobrien    for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
100977298Sobrien      ;
101077298Sobrien    if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
101177298Sobrien      {
101277298Sobrien	len0 = i - 1;
101377298Sobrien	changed = 1;
101477298Sobrien      }
101577298Sobrien    else if (mangled[i] == '$')
101677298Sobrien      {
101777298Sobrien	len0 = i;
101877298Sobrien	changed = 1;
101977298Sobrien      }
102077298Sobrien  }
102177298Sobrien
102277298Sobrien  for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
102377298Sobrien       i += 1, j += 1)
102477298Sobrien    demangled[j] = mangled[i];
102577298Sobrien
102677298Sobrien  at_start_name = 1;
102777298Sobrien  while (i < len0)
102877298Sobrien    {
102977298Sobrien      at_start_name = 0;
103077298Sobrien
103177298Sobrien      if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
103277298Sobrien	{
103377298Sobrien	  demangled[j] = '.';
103477298Sobrien	  changed = at_start_name = 1;
103577298Sobrien	  i += 2; j += 1;
103677298Sobrien	}
103777298Sobrien      else
103877298Sobrien	{
103977298Sobrien	  demangled[j] = mangled[i];
104077298Sobrien	  i += 1;  j += 1;
104177298Sobrien	}
104277298Sobrien    }
104377298Sobrien  demangled[j] = '\000';
104477298Sobrien
104577298Sobrien  for (i = 0; demangled[i] != '\0'; i += 1)
104677298Sobrien    if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
104777298Sobrien      goto Suppress;
104877298Sobrien
104977298Sobrien  if (! changed)
105077298Sobrien    return NULL;
105177298Sobrien  else
105277298Sobrien    return demangled;
105377298Sobrien
105477298Sobrien Suppress:
105577298Sobrien  grow_vect ((void **) &(demangling_buffer),
105677298Sobrien	     &demangling_buffer_size,  strlen (mangled) + 3,
105777298Sobrien	     sizeof (char));
105877298Sobrien  demangled = demangling_buffer;
105977298Sobrien  if (mangled[0] == '<')
106077298Sobrien     strcpy (demangled, mangled);
106177298Sobrien  else
106277298Sobrien    sprintf (demangled, "<%s>", mangled);
106377298Sobrien
106477298Sobrien  return demangled;
106577298Sobrien}
106677298Sobrien
106760484Sobrien/* This function performs most of what cplus_demangle use to do, but
106860484Sobrien   to be able to demangle a name with a B, K or n code, we need to
106960484Sobrien   have a longer term memory of what types have been seen. The original
107060484Sobrien   now intializes and cleans up the squangle code info, while internal
107160484Sobrien   calls go directly to this routine to avoid resetting that info. */
107260484Sobrien
107360484Sobrienstatic char *
107460484Sobrieninternal_cplus_demangle (work, mangled)
107560484Sobrien     struct work_stuff *work;
107660484Sobrien     const char *mangled;
107760484Sobrien{
107860484Sobrien
107933965Sjdp  string decl;
108033965Sjdp  int success = 0;
108133965Sjdp  char *demangled = NULL;
108277298Sobrien  int s1, s2, s3, s4;
108360484Sobrien  s1 = work->constructor;
108460484Sobrien  s2 = work->destructor;
108560484Sobrien  s3 = work->static_type;
108660484Sobrien  s4 = work->type_quals;
108760484Sobrien  work->constructor = work->destructor = 0;
108860484Sobrien  work->type_quals = TYPE_UNQUALIFIED;
108960484Sobrien  work->dllimported = 0;
109033965Sjdp
109133965Sjdp  if ((mangled != NULL) && (*mangled != '\0'))
109233965Sjdp    {
109333965Sjdp      string_init (&decl);
109433965Sjdp
109533965Sjdp      /* First check to see if gnu style demangling is active and if the
109633965Sjdp	 string to be demangled contains a CPLUS_MARKER.  If so, attempt to
109733965Sjdp	 recognize one of the gnu special forms rather than looking for a
109833965Sjdp	 standard prefix.  In particular, don't worry about whether there
109933965Sjdp	 is a "__" string in the mangled string.  Consider "_$_5__foo" for
110033965Sjdp	 example.  */
110133965Sjdp
110233965Sjdp      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
110333965Sjdp	{
110433965Sjdp	  success = gnu_special (work, &mangled, &decl);
110533965Sjdp	}
110633965Sjdp      if (!success)
110733965Sjdp	{
110833965Sjdp	  success = demangle_prefix (work, &mangled, &decl);
110933965Sjdp	}
111033965Sjdp      if (success && (*mangled != '\0'))
111133965Sjdp	{
111233965Sjdp	  success = demangle_signature (work, &mangled, &decl);
111333965Sjdp	}
111433965Sjdp      if (work->constructor == 2)
111533965Sjdp        {
111660484Sobrien          string_prepend (&decl, "global constructors keyed to ");
111733965Sjdp          work->constructor = 0;
111833965Sjdp        }
111933965Sjdp      else if (work->destructor == 2)
112033965Sjdp        {
112160484Sobrien          string_prepend (&decl, "global destructors keyed to ");
112233965Sjdp          work->destructor = 0;
112333965Sjdp        }
112460484Sobrien      else if (work->dllimported == 1)
112560484Sobrien        {
112660484Sobrien          string_prepend (&decl, "import stub for ");
112760484Sobrien          work->dllimported = 0;
112860484Sobrien        }
112933965Sjdp      demangled = mop_up (work, &decl, success);
113033965Sjdp    }
113160484Sobrien  work->constructor = s1;
113260484Sobrien  work->destructor = s2;
113360484Sobrien  work->static_type = s3;
113460484Sobrien  work->type_quals = s4;
113577298Sobrien  return demangled;
113633965Sjdp}
113733965Sjdp
113860484Sobrien
113960484Sobrien/* Clear out and squangling related storage */
114060484Sobrienstatic void
114160484Sobriensquangle_mop_up (work)
114260484Sobrien     struct work_stuff *work;
114360484Sobrien{
114460484Sobrien  /* clean up the B and K type mangling types. */
114560484Sobrien  forget_B_and_K_types (work);
114660484Sobrien  if (work -> btypevec != NULL)
114760484Sobrien    {
114860484Sobrien      free ((char *) work -> btypevec);
114960484Sobrien    }
115060484Sobrien  if (work -> ktypevec != NULL)
115160484Sobrien    {
115260484Sobrien      free ((char *) work -> ktypevec);
115360484Sobrien    }
115460484Sobrien}
115560484Sobrien
115660484Sobrien
115768765Sobrien/* Copy the work state and storage.  */
115868765Sobrien
115968765Sobrienstatic void
116068765Sobrienwork_stuff_copy_to_from (to, from)
116168765Sobrien     struct work_stuff *to;
116268765Sobrien     struct work_stuff *from;
116368765Sobrien{
116468765Sobrien  int i;
116568765Sobrien
116668765Sobrien  delete_work_stuff (to);
116768765Sobrien
116868765Sobrien  /* Shallow-copy scalars.  */
116968765Sobrien  memcpy (to, from, sizeof (*to));
117068765Sobrien
117168765Sobrien  /* Deep-copy dynamic storage.  */
117268765Sobrien  if (from->typevec_size)
117368765Sobrien    to->typevec
117468765Sobrien      = (char **) xmalloc (from->typevec_size * sizeof (to->typevec[0]));
117568765Sobrien
117668765Sobrien  for (i = 0; i < from->ntypes; i++)
117768765Sobrien    {
117868765Sobrien      int len = strlen (from->typevec[i]) + 1;
117968765Sobrien
118068765Sobrien      to->typevec[i] = xmalloc (len);
118168765Sobrien      memcpy (to->typevec[i], from->typevec[i], len);
118268765Sobrien    }
118368765Sobrien
118468765Sobrien  if (from->ksize)
118568765Sobrien    to->ktypevec
118668765Sobrien      = (char **) xmalloc (from->ksize * sizeof (to->ktypevec[0]));
118768765Sobrien
118868765Sobrien  for (i = 0; i < from->numk; i++)
118968765Sobrien    {
119068765Sobrien      int len = strlen (from->ktypevec[i]) + 1;
119168765Sobrien
119268765Sobrien      to->ktypevec[i] = xmalloc (len);
119368765Sobrien      memcpy (to->ktypevec[i], from->ktypevec[i], len);
119468765Sobrien    }
119568765Sobrien
119668765Sobrien  if (from->bsize)
119768765Sobrien    to->btypevec
119868765Sobrien      = (char **) xmalloc (from->bsize * sizeof (to->btypevec[0]));
119968765Sobrien
120068765Sobrien  for (i = 0; i < from->numb; i++)
120168765Sobrien    {
120268765Sobrien      int len = strlen (from->btypevec[i]) + 1;
120368765Sobrien
120468765Sobrien      to->btypevec[i] = xmalloc (len);
120568765Sobrien      memcpy (to->btypevec[i], from->btypevec[i], len);
120668765Sobrien    }
120768765Sobrien
120868765Sobrien  if (from->ntmpl_args)
120968765Sobrien    to->tmpl_argvec
121068765Sobrien      = xmalloc (from->ntmpl_args * sizeof (to->tmpl_argvec[0]));
121168765Sobrien
121268765Sobrien  for (i = 0; i < from->ntmpl_args; i++)
121368765Sobrien    {
121468765Sobrien      int len = strlen (from->tmpl_argvec[i]) + 1;
121568765Sobrien
121668765Sobrien      to->tmpl_argvec[i] = xmalloc (len);
121768765Sobrien      memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
121868765Sobrien    }
121968765Sobrien
122068765Sobrien  if (from->previous_argument)
122168765Sobrien    {
122268765Sobrien      to->previous_argument = (string*) xmalloc (sizeof (string));
122368765Sobrien      string_init (to->previous_argument);
122468765Sobrien      string_appends (to->previous_argument, from->previous_argument);
122568765Sobrien    }
122668765Sobrien}
122768765Sobrien
122868765Sobrien
122968765Sobrien/* Delete dynamic stuff in work_stuff that is not to be re-used.  */
123068765Sobrien
123168765Sobrienstatic void
123268765Sobriendelete_non_B_K_work_stuff (work)
123333965Sjdp     struct work_stuff *work;
123433965Sjdp{
123533965Sjdp  /* Discard the remembered types, if any.  */
123660484Sobrien
123733965Sjdp  forget_types (work);
123833965Sjdp  if (work -> typevec != NULL)
123933965Sjdp    {
124033965Sjdp      free ((char *) work -> typevec);
124160484Sobrien      work -> typevec = NULL;
124260484Sobrien      work -> typevec_size = 0;
124333965Sjdp    }
124438889Sjdp  if (work->tmpl_argvec)
124538889Sjdp    {
124638889Sjdp      int i;
124738889Sjdp
124838889Sjdp      for (i = 0; i < work->ntmpl_args; i++)
124938889Sjdp	if (work->tmpl_argvec[i])
125038889Sjdp	  free ((char*) work->tmpl_argvec[i]);
125160484Sobrien
125238889Sjdp      free ((char*) work->tmpl_argvec);
125360484Sobrien      work->tmpl_argvec = NULL;
125438889Sjdp    }
125560484Sobrien  if (work->previous_argument)
125660484Sobrien    {
125760484Sobrien      string_delete (work->previous_argument);
125860484Sobrien      free ((char*) work->previous_argument);
125960484Sobrien      work->previous_argument = NULL;
126060484Sobrien    }
126168765Sobrien}
126238889Sjdp
126368765Sobrien
126468765Sobrien/* Delete all dynamic storage in work_stuff.  */
126568765Sobrienstatic void
126668765Sobriendelete_work_stuff (work)
126768765Sobrien     struct work_stuff *work;
126868765Sobrien{
126968765Sobrien  delete_non_B_K_work_stuff (work);
127068765Sobrien  squangle_mop_up (work);
127168765Sobrien}
127268765Sobrien
127368765Sobrien
127468765Sobrien/* Clear out any mangled storage */
127568765Sobrien
127668765Sobrienstatic char *
127768765Sobrienmop_up (work, declp, success)
127868765Sobrien     struct work_stuff *work;
127968765Sobrien     string *declp;
128068765Sobrien     int success;
128168765Sobrien{
128268765Sobrien  char *demangled = NULL;
128368765Sobrien
128468765Sobrien  delete_non_B_K_work_stuff (work);
128568765Sobrien
128633965Sjdp  /* If demangling was successful, ensure that the demangled string is null
128733965Sjdp     terminated and return it.  Otherwise, free the demangling decl.  */
128860484Sobrien
128933965Sjdp  if (!success)
129033965Sjdp    {
129133965Sjdp      string_delete (declp);
129233965Sjdp    }
129333965Sjdp  else
129433965Sjdp    {
129533965Sjdp      string_appendn (declp, "", 1);
129677298Sobrien      demangled = declp->b;
129733965Sjdp    }
129833965Sjdp  return (demangled);
129933965Sjdp}
130033965Sjdp
130133965Sjdp/*
130233965Sjdp
130333965SjdpLOCAL FUNCTION
130433965Sjdp
130533965Sjdp	demangle_signature -- demangle the signature part of a mangled name
130633965Sjdp
130733965SjdpSYNOPSIS
130833965Sjdp
130933965Sjdp	static int
131033965Sjdp	demangle_signature (struct work_stuff *work, const char **mangled,
131133965Sjdp			    string *declp);
131233965Sjdp
131333965SjdpDESCRIPTION
131433965Sjdp
131533965Sjdp	Consume and demangle the signature portion of the mangled name.
131633965Sjdp
131733965Sjdp	DECLP is the string where demangled output is being built.  At
131833965Sjdp	entry it contains the demangled root name from the mangled name
131933965Sjdp	prefix.  I.E. either a demangled operator name or the root function
132033965Sjdp	name.  In some special cases, it may contain nothing.
132133965Sjdp
132233965Sjdp	*MANGLED points to the current unconsumed location in the mangled
132333965Sjdp	name.  As tokens are consumed and demangling is performed, the
132433965Sjdp	pointer is updated to continuously point at the next token to
132533965Sjdp	be consumed.
132633965Sjdp
132733965Sjdp	Demangling GNU style mangled names is nasty because there is no
132833965Sjdp	explicit token that marks the start of the outermost function
132933965Sjdp	argument list.  */
133033965Sjdp
133133965Sjdpstatic int
133233965Sjdpdemangle_signature (work, mangled, declp)
133333965Sjdp     struct work_stuff *work;
133433965Sjdp     const char **mangled;
133533965Sjdp     string *declp;
133633965Sjdp{
133733965Sjdp  int success = 1;
133833965Sjdp  int func_done = 0;
133933965Sjdp  int expect_func = 0;
134038889Sjdp  int expect_return_type = 0;
134133965Sjdp  const char *oldmangled = NULL;
134233965Sjdp  string trawname;
134333965Sjdp  string tname;
134433965Sjdp
134533965Sjdp  while (success && (**mangled != '\0'))
134633965Sjdp    {
134733965Sjdp      switch (**mangled)
134833965Sjdp	{
134933965Sjdp	case 'Q':
135033965Sjdp	  oldmangled = *mangled;
135133965Sjdp	  success = demangle_qualified (work, mangled, declp, 1, 0);
135233965Sjdp	  if (success)
135360484Sobrien	    remember_type (work, oldmangled, *mangled - oldmangled);
135433965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
135560484Sobrien	    expect_func = 1;
135660484Sobrien	  oldmangled = NULL;
135760484Sobrien	  break;
135860484Sobrien
135960484Sobrien        case 'K':
136060484Sobrien	  oldmangled = *mangled;
136160484Sobrien	  success = demangle_qualified (work, mangled, declp, 1, 0);
136260484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
136333965Sjdp	    {
136433965Sjdp	      expect_func = 1;
136533965Sjdp	    }
136633965Sjdp	  oldmangled = NULL;
136733965Sjdp	  break;
136860484Sobrien
136933965Sjdp	case 'S':
137033965Sjdp	  /* Static member function */
137133965Sjdp	  if (oldmangled == NULL)
137233965Sjdp	    {
137333965Sjdp	      oldmangled = *mangled;
137433965Sjdp	    }
137533965Sjdp	  (*mangled)++;
137633965Sjdp	  work -> static_type = 1;
137733965Sjdp	  break;
137833965Sjdp
137933965Sjdp	case 'C':
138060484Sobrien	case 'V':
138160484Sobrien	case 'u':
138260484Sobrien	  work->type_quals |= code_for_qualifier (**mangled);
138360484Sobrien
138460484Sobrien	  /* a qualified member function */
138533965Sjdp	  if (oldmangled == NULL)
138660484Sobrien	    oldmangled = *mangled;
138760484Sobrien	  (*mangled)++;
138860484Sobrien	  break;
138960484Sobrien
139060484Sobrien	case 'L':
139160484Sobrien	  /* Local class name follows after "Lnnn_" */
139260484Sobrien	  if (HP_DEMANGLING)
139333965Sjdp	    {
139460484Sobrien	      while (**mangled && (**mangled != '_'))
139560484Sobrien		(*mangled)++;
139660484Sobrien	      if (!**mangled)
139760484Sobrien		success = 0;
139860484Sobrien	      else
139960484Sobrien		(*mangled)++;
140033965Sjdp	    }
140160484Sobrien	  else
140260484Sobrien	    success = 0;
140333965Sjdp	  break;
140460484Sobrien
140533965Sjdp	case '0': case '1': case '2': case '3': case '4':
140633965Sjdp	case '5': case '6': case '7': case '8': case '9':
140733965Sjdp	  if (oldmangled == NULL)
140833965Sjdp	    {
140933965Sjdp	      oldmangled = *mangled;
141033965Sjdp	    }
141160484Sobrien          work->temp_start = -1; /* uppermost call to demangle_class */
141233965Sjdp	  success = demangle_class (work, mangled, declp);
141333965Sjdp	  if (success)
141433965Sjdp	    {
141533965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
141633965Sjdp	    }
141760484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
141833965Sjdp	    {
141960484Sobrien              /* EDG and others will have the "F", so we let the loop cycle
142060484Sobrien                 if we are looking at one. */
142160484Sobrien              if (**mangled != 'F')
142260484Sobrien                 expect_func = 1;
142333965Sjdp	    }
142433965Sjdp	  oldmangled = NULL;
142533965Sjdp	  break;
142660484Sobrien
142760484Sobrien	case 'B':
142860484Sobrien	  {
142960484Sobrien	    string s;
143060484Sobrien	    success = do_type (work, mangled, &s);
143160484Sobrien	    if (success)
143260484Sobrien	      {
143360484Sobrien		string_append (&s, SCOPE_STRING (work));
143460484Sobrien		string_prepends (declp, &s);
143560484Sobrien	      }
143660484Sobrien	    oldmangled = NULL;
143760484Sobrien	    expect_func = 1;
143860484Sobrien	  }
143960484Sobrien	  break;
144060484Sobrien
144133965Sjdp	case 'F':
144233965Sjdp	  /* Function */
144360484Sobrien	  /* ARM/HP style demangling includes a specific 'F' character after
144433965Sjdp	     the class name.  For GNU style, it is just implied.  So we can
144533965Sjdp	     safely just consume any 'F' at this point and be compatible
144633965Sjdp	     with either style.  */
144733965Sjdp
144833965Sjdp	  oldmangled = NULL;
144933965Sjdp	  func_done = 1;
145033965Sjdp	  (*mangled)++;
145133965Sjdp
145260484Sobrien	  /* For lucid/ARM/HP style we have to forget any types we might
145333965Sjdp	     have remembered up to this point, since they were not argument
145433965Sjdp	     types.  GNU style considers all types seen as available for
145533965Sjdp	     back references.  See comment in demangle_args() */
145633965Sjdp
145760484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
145833965Sjdp	    {
145933965Sjdp	      forget_types (work);
146033965Sjdp	    }
146133965Sjdp	  success = demangle_args (work, mangled, declp);
146260484Sobrien	  /* After picking off the function args, we expect to either
146360484Sobrien	     find the function return type (preceded by an '_') or the
146460484Sobrien	     end of the string. */
146560484Sobrien	  if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
146660484Sobrien	    {
146760484Sobrien	      ++(*mangled);
146860484Sobrien              /* At this level, we do not care about the return type. */
146960484Sobrien              success = do_type (work, mangled, &tname);
147060484Sobrien              string_delete (&tname);
147160484Sobrien            }
147260484Sobrien
147333965Sjdp	  break;
147460484Sobrien
147533965Sjdp	case 't':
147633965Sjdp	  /* G++ Template */
147760484Sobrien	  string_init(&trawname);
147833965Sjdp	  string_init(&tname);
147933965Sjdp	  if (oldmangled == NULL)
148033965Sjdp	    {
148133965Sjdp	      oldmangled = *mangled;
148233965Sjdp	    }
148360484Sobrien	  success = demangle_template (work, mangled, &tname,
148460484Sobrien				       &trawname, 1, 1);
148533965Sjdp	  if (success)
148633965Sjdp	    {
148733965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
148833965Sjdp	    }
148960484Sobrien	  string_append (&tname, SCOPE_STRING (work));
149060484Sobrien
149133965Sjdp	  string_prepends(declp, &tname);
149233965Sjdp	  if (work -> destructor & 1)
149333965Sjdp	    {
149433965Sjdp	      string_prepend (&trawname, "~");
149533965Sjdp	      string_appends (declp, &trawname);
149633965Sjdp	      work->destructor -= 1;
149733965Sjdp	    }
149833965Sjdp	  if ((work->constructor & 1) || (work->destructor & 1))
149933965Sjdp	    {
150033965Sjdp	      string_appends (declp, &trawname);
150133965Sjdp	      work->constructor -= 1;
150233965Sjdp	    }
150333965Sjdp	  string_delete(&trawname);
150433965Sjdp	  string_delete(&tname);
150533965Sjdp	  oldmangled = NULL;
150633965Sjdp	  expect_func = 1;
150733965Sjdp	  break;
150833965Sjdp
150933965Sjdp	case '_':
151068765Sobrien	  if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
151138889Sjdp	    {
151238889Sjdp	      /* Read the return type. */
151338889Sjdp	      string return_type;
151438889Sjdp	      string_init (&return_type);
151538889Sjdp
151638889Sjdp	      (*mangled)++;
151738889Sjdp	      success = do_type (work, mangled, &return_type);
151838889Sjdp	      APPEND_BLANK (&return_type);
151938889Sjdp
152038889Sjdp	      string_prepends (declp, &return_type);
152138889Sjdp	      string_delete (&return_type);
152238889Sjdp	      break;
152338889Sjdp	    }
152438889Sjdp	  else
152538889Sjdp	    /* At the outermost level, we cannot have a return type specified,
152638889Sjdp	       so if we run into another '_' at this point we are dealing with
152738889Sjdp	       a mangled name that is either bogus, or has been mangled by
152838889Sjdp	       some algorithm we don't know how to deal with.  So just
152938889Sjdp	       reject the entire demangling.  */
153060484Sobrien            /* However, "_nnn" is an expected suffix for alternate entry point
153160484Sobrien               numbered nnn for a function, with HP aCC, so skip over that
153260484Sobrien               without reporting failure. pai/1997-09-04 */
153360484Sobrien            if (HP_DEMANGLING)
153460484Sobrien              {
153560484Sobrien                (*mangled)++;
153677298Sobrien                while (**mangled && ISDIGIT ((unsigned char)**mangled))
153760484Sobrien                  (*mangled)++;
153860484Sobrien              }
153960484Sobrien            else
154060484Sobrien	      success = 0;
154133965Sjdp	  break;
154233965Sjdp
154338889Sjdp	case 'H':
154468765Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
154538889Sjdp	    {
154638889Sjdp	      /* A G++ template function.  Read the template arguments. */
154760484Sobrien	      success = demangle_template (work, mangled, declp, 0, 0,
154860484Sobrien					   0);
154938889Sjdp	      if (!(work->constructor & 1))
155038889Sjdp		expect_return_type = 1;
155138889Sjdp	      (*mangled)++;
155238889Sjdp	      break;
155338889Sjdp	    }
155438889Sjdp	  else
155538889Sjdp	    /* fall through */
155660484Sobrien	    {;}
155738889Sjdp
155833965Sjdp	default:
155933965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
156033965Sjdp	    {
156133965Sjdp	      /* Assume we have stumbled onto the first outermost function
156233965Sjdp		 argument token, and start processing args.  */
156333965Sjdp	      func_done = 1;
156433965Sjdp	      success = demangle_args (work, mangled, declp);
156533965Sjdp	    }
156633965Sjdp	  else
156733965Sjdp	    {
156833965Sjdp	      /* Non-GNU demanglers use a specific token to mark the start
156933965Sjdp		 of the outermost function argument tokens.  Typically 'F',
157060484Sobrien		 for ARM/HP-demangling, for example.  So if we find something
157133965Sjdp		 we are not prepared for, it must be an error.  */
157233965Sjdp	      success = 0;
157333965Sjdp	    }
157433965Sjdp	  break;
157533965Sjdp	}
157633965Sjdp      /*
157733965Sjdp	if (AUTO_DEMANGLING || GNU_DEMANGLING)
157833965Sjdp	*/
157933965Sjdp      {
158033965Sjdp	if (success && expect_func)
158133965Sjdp	  {
158233965Sjdp	    func_done = 1;
158360484Sobrien              if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
158460484Sobrien                {
158560484Sobrien                  forget_types (work);
158660484Sobrien                }
158733965Sjdp	    success = demangle_args (work, mangled, declp);
158838889Sjdp	    /* Since template include the mangling of their return types,
158938889Sjdp	       we must set expect_func to 0 so that we don't try do
159038889Sjdp	       demangle more arguments the next time we get here.  */
159138889Sjdp	    expect_func = 0;
159233965Sjdp	  }
159333965Sjdp      }
159433965Sjdp    }
159533965Sjdp  if (success && !func_done)
159633965Sjdp    {
159733965Sjdp      if (AUTO_DEMANGLING || GNU_DEMANGLING)
159833965Sjdp	{
159933965Sjdp	  /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
160033965Sjdp	     bar__3fooi is 'foo::bar(int)'.  We get here when we find the
160133965Sjdp	     first case, and need to ensure that the '(void)' gets added to
160260484Sobrien	     the current declp.  Note that with ARM/HP, the first case
160333965Sjdp	     represents the name of a static data member 'foo::bar',
160433965Sjdp	     which is in the current declp, so we leave it alone.  */
160533965Sjdp	  success = demangle_args (work, mangled, declp);
160633965Sjdp	}
160733965Sjdp    }
160860484Sobrien  if (success && PRINT_ARG_TYPES)
160933965Sjdp    {
161060484Sobrien      if (work->static_type)
161160484Sobrien	string_append (declp, " static");
161260484Sobrien      if (work->type_quals != TYPE_UNQUALIFIED)
161360484Sobrien	{
161460484Sobrien	  APPEND_BLANK (declp);
161560484Sobrien	  string_append (declp, qualifier_string (work->type_quals));
161660484Sobrien	}
161733965Sjdp    }
161860484Sobrien
161933965Sjdp  return (success);
162033965Sjdp}
162133965Sjdp
162233965Sjdp#if 0
162333965Sjdp
162433965Sjdpstatic int
162533965Sjdpdemangle_method_args (work, mangled, declp)
162633965Sjdp     struct work_stuff *work;
162733965Sjdp     const char **mangled;
162833965Sjdp     string *declp;
162933965Sjdp{
163033965Sjdp  int success = 0;
163133965Sjdp
163233965Sjdp  if (work -> static_type)
163333965Sjdp    {
163433965Sjdp      string_append (declp, *mangled + 1);
163533965Sjdp      *mangled += strlen (*mangled);
163633965Sjdp      success = 1;
163733965Sjdp    }
163833965Sjdp  else
163933965Sjdp    {
164033965Sjdp      success = demangle_args (work, mangled, declp);
164133965Sjdp    }
164233965Sjdp  return (success);
164333965Sjdp}
164433965Sjdp
164533965Sjdp#endif
164633965Sjdp
164733965Sjdpstatic int
164860484Sobriendemangle_template_template_parm (work, mangled, tname)
164933965Sjdp     struct work_stuff *work;
165033965Sjdp     const char **mangled;
165133965Sjdp     string *tname;
165260484Sobrien{
165360484Sobrien  int i;
165460484Sobrien  int r;
165560484Sobrien  int need_comma = 0;
165660484Sobrien  int success = 1;
165760484Sobrien  string temp;
165860484Sobrien
165960484Sobrien  string_append (tname, "template <");
166060484Sobrien  /* get size of template parameter list */
166160484Sobrien  if (get_count (mangled, &r))
166260484Sobrien    {
166360484Sobrien      for (i = 0; i < r; i++)
166460484Sobrien	{
166560484Sobrien	  if (need_comma)
166660484Sobrien	    {
166760484Sobrien	      string_append (tname, ", ");
166860484Sobrien	    }
166960484Sobrien
167060484Sobrien	    /* Z for type parameters */
167160484Sobrien	    if (**mangled == 'Z')
167260484Sobrien	      {
167360484Sobrien		(*mangled)++;
167460484Sobrien		string_append (tname, "class");
167560484Sobrien	      }
167660484Sobrien	      /* z for template parameters */
167760484Sobrien	    else if (**mangled == 'z')
167860484Sobrien	      {
167960484Sobrien		(*mangled)++;
168060484Sobrien		success =
168160484Sobrien		  demangle_template_template_parm (work, mangled, tname);
168260484Sobrien		if (!success)
168360484Sobrien		  {
168460484Sobrien		    break;
168560484Sobrien		  }
168660484Sobrien	      }
168760484Sobrien	    else
168860484Sobrien	      {
168960484Sobrien		/* temp is initialized in do_type */
169060484Sobrien		success = do_type (work, mangled, &temp);
169160484Sobrien		if (success)
169260484Sobrien		  {
169360484Sobrien		    string_appends (tname, &temp);
169460484Sobrien		  }
169560484Sobrien		string_delete(&temp);
169660484Sobrien		if (!success)
169760484Sobrien		  {
169860484Sobrien		    break;
169960484Sobrien		  }
170060484Sobrien	      }
170160484Sobrien	  need_comma = 1;
170260484Sobrien	}
170360484Sobrien
170460484Sobrien    }
170560484Sobrien  if (tname->p[-1] == '>')
170660484Sobrien    string_append (tname, " ");
170760484Sobrien  string_append (tname, "> class");
170860484Sobrien  return (success);
170960484Sobrien}
171060484Sobrien
171160484Sobrienstatic int
171260484Sobriendemangle_expression (work, mangled, s, tk)
171360484Sobrien     struct work_stuff *work;
171460484Sobrien     const char** mangled;
171560484Sobrien     string* s;
171660484Sobrien     type_kind_t tk;
171760484Sobrien{
171860484Sobrien  int need_operator = 0;
171960484Sobrien  int success;
172060484Sobrien
172160484Sobrien  success = 1;
172260484Sobrien  string_appendn (s, "(", 1);
172360484Sobrien  (*mangled)++;
172460484Sobrien  while (success && **mangled != 'W' && **mangled != '\0')
172560484Sobrien    {
172660484Sobrien      if (need_operator)
172760484Sobrien	{
172860484Sobrien	  size_t i;
172960484Sobrien	  size_t len;
173060484Sobrien
173160484Sobrien	  success = 0;
173260484Sobrien
173360484Sobrien	  len = strlen (*mangled);
173460484Sobrien
173577298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); ++i)
173660484Sobrien	    {
173760484Sobrien	      size_t l = strlen (optable[i].in);
173860484Sobrien
173960484Sobrien	      if (l <= len
174060484Sobrien		  && memcmp (optable[i].in, *mangled, l) == 0)
174160484Sobrien		{
174260484Sobrien		  string_appendn (s, " ", 1);
174360484Sobrien		  string_append (s, optable[i].out);
174460484Sobrien		  string_appendn (s, " ", 1);
174560484Sobrien		  success = 1;
174660484Sobrien		  (*mangled) += l;
174760484Sobrien		  break;
174860484Sobrien		}
174960484Sobrien	    }
175060484Sobrien
175160484Sobrien	  if (!success)
175260484Sobrien	    break;
175360484Sobrien	}
175460484Sobrien      else
175560484Sobrien	need_operator = 1;
175660484Sobrien
175760484Sobrien      success = demangle_template_value_parm (work, mangled, s, tk);
175860484Sobrien    }
175960484Sobrien
176060484Sobrien  if (**mangled != 'W')
176160484Sobrien    success = 0;
176260484Sobrien  else
176360484Sobrien    {
176460484Sobrien      string_appendn (s, ")", 1);
176560484Sobrien      (*mangled)++;
176660484Sobrien    }
176760484Sobrien
176860484Sobrien  return success;
176960484Sobrien}
177060484Sobrien
177160484Sobrienstatic int
177260484Sobriendemangle_integral_value (work, mangled, s)
177360484Sobrien     struct work_stuff *work;
177460484Sobrien     const char** mangled;
177560484Sobrien     string* s;
177660484Sobrien{
177760484Sobrien  int success;
177860484Sobrien
177960484Sobrien  if (**mangled == 'E')
178060484Sobrien    success = demangle_expression (work, mangled, s, tk_integral);
178160484Sobrien  else if (**mangled == 'Q' || **mangled == 'K')
178260484Sobrien    success = demangle_qualified (work, mangled, s, 0, 1);
178360484Sobrien  else
178460484Sobrien    {
178560484Sobrien      int value;
178660484Sobrien
178768765Sobrien      /* By default, we let the number decide whether we shall consume an
178868765Sobrien	 underscore.  */
178968765Sobrien      int consume_following_underscore = 0;
179068765Sobrien      int leave_following_underscore = 0;
179168765Sobrien
179260484Sobrien      success = 0;
179360484Sobrien
179460484Sobrien      /* Negative numbers are indicated with a leading `m'.  */
179560484Sobrien      if (**mangled == 'm')
179660484Sobrien	{
179760484Sobrien	  string_appendn (s, "-", 1);
179860484Sobrien	  (*mangled)++;
179960484Sobrien	}
180068765Sobrien      else if (mangled[0][0] == '_' && mangled[0][1] == 'm')
180168765Sobrien	{
180268765Sobrien	  /* Since consume_count_with_underscores does not handle the
180368765Sobrien	     `m'-prefix we must do it here, using consume_count and
180468765Sobrien	     adjusting underscores: we have to consume the underscore
180568765Sobrien	     matching the prepended one.  */
180668765Sobrien	  consume_following_underscore = 1;
180768765Sobrien	  string_appendn (s, "-", 1);
180868765Sobrien	  (*mangled) += 2;
180968765Sobrien	}
181068765Sobrien      else if (**mangled == '_')
181168765Sobrien	{
181268765Sobrien	  /* Do not consume a following underscore;
181368765Sobrien	     consume_following_underscore will consume what should be
181468765Sobrien	     consumed.  */
181568765Sobrien	  leave_following_underscore = 1;
181668765Sobrien	}
181760484Sobrien
181868765Sobrien      /* We must call consume_count if we expect to remove a trailing
181968765Sobrien	 underscore, since consume_count_with_underscores expects
182068765Sobrien	 the leading underscore (that we consumed) if it is to handle
182168765Sobrien	 multi-digit numbers.  */
182268765Sobrien      if (consume_following_underscore)
182368765Sobrien	value = consume_count (mangled);
182468765Sobrien      else
182568765Sobrien	value = consume_count_with_underscores (mangled);
182668765Sobrien
182760484Sobrien      if (value != -1)
182860484Sobrien	{
182960484Sobrien	  char buf[INTBUF_SIZE];
183060484Sobrien	  sprintf (buf, "%d", value);
183160484Sobrien	  string_append (s, buf);
183260484Sobrien
183368765Sobrien	  /* Numbers not otherwise delimited, might have an underscore
183468765Sobrien	     appended as a delimeter, which we should skip.
183568765Sobrien
183668765Sobrien	     ??? This used to always remove a following underscore, which
183768765Sobrien	     is wrong.  If other (arbitrary) cases are followed by an
183868765Sobrien	     underscore, we need to do something more radical.  */
183968765Sobrien
184068765Sobrien	  if ((value > 9 || consume_following_underscore)
184168765Sobrien	      && ! leave_following_underscore
184268765Sobrien	      && **mangled == '_')
184360484Sobrien	    (*mangled)++;
184460484Sobrien
184560484Sobrien	  /* All is well.  */
184660484Sobrien	  success = 1;
184760484Sobrien	}
184860484Sobrien    }
184960484Sobrien
185060484Sobrien  return success;
185160484Sobrien}
185260484Sobrien
185360484Sobrien/* Demangle the real value in MANGLED.  */
185460484Sobrien
185560484Sobrienstatic int
185660484Sobriendemangle_real_value (work, mangled, s)
185760484Sobrien     struct work_stuff *work;
185860484Sobrien     const char **mangled;
185960484Sobrien     string* s;
186060484Sobrien{
186160484Sobrien  if (**mangled == 'E')
186260484Sobrien    return demangle_expression (work, mangled, s, tk_real);
186360484Sobrien
186460484Sobrien  if (**mangled == 'm')
186560484Sobrien    {
186660484Sobrien      string_appendn (s, "-", 1);
186760484Sobrien      (*mangled)++;
186860484Sobrien    }
186977298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
187060484Sobrien    {
187160484Sobrien      string_appendn (s, *mangled, 1);
187260484Sobrien      (*mangled)++;
187360484Sobrien    }
187460484Sobrien  if (**mangled == '.') /* fraction */
187560484Sobrien    {
187660484Sobrien      string_appendn (s, ".", 1);
187760484Sobrien      (*mangled)++;
187877298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
187960484Sobrien	{
188060484Sobrien	  string_appendn (s, *mangled, 1);
188160484Sobrien	  (*mangled)++;
188260484Sobrien	}
188360484Sobrien    }
188460484Sobrien  if (**mangled == 'e') /* exponent */
188560484Sobrien    {
188660484Sobrien      string_appendn (s, "e", 1);
188760484Sobrien      (*mangled)++;
188877298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
188960484Sobrien	{
189060484Sobrien	  string_appendn (s, *mangled, 1);
189160484Sobrien	  (*mangled)++;
189260484Sobrien	}
189360484Sobrien    }
189460484Sobrien
189560484Sobrien  return 1;
189660484Sobrien}
189760484Sobrien
189860484Sobrienstatic int
189960484Sobriendemangle_template_value_parm (work, mangled, s, tk)
190060484Sobrien     struct work_stuff *work;
190160484Sobrien     const char **mangled;
190260484Sobrien     string* s;
190360484Sobrien     type_kind_t tk;
190460484Sobrien{
190560484Sobrien  int success = 1;
190660484Sobrien
190760484Sobrien  if (**mangled == 'Y')
190860484Sobrien    {
190960484Sobrien      /* The next argument is a template parameter. */
191060484Sobrien      int idx;
191160484Sobrien
191260484Sobrien      (*mangled)++;
191360484Sobrien      idx = consume_count_with_underscores (mangled);
191460484Sobrien      if (idx == -1
191560484Sobrien	  || (work->tmpl_argvec && idx >= work->ntmpl_args)
191660484Sobrien	  || consume_count_with_underscores (mangled) == -1)
191760484Sobrien	return -1;
191860484Sobrien      if (work->tmpl_argvec)
191960484Sobrien	string_append (s, work->tmpl_argvec[idx]);
192060484Sobrien      else
192160484Sobrien	string_append_template_idx (s, idx);
192260484Sobrien    }
192360484Sobrien  else if (tk == tk_integral)
192460484Sobrien    success = demangle_integral_value (work, mangled, s);
192560484Sobrien  else if (tk == tk_char)
192660484Sobrien    {
192760484Sobrien      char tmp[2];
192860484Sobrien      int val;
192960484Sobrien      if (**mangled == 'm')
193060484Sobrien	{
193160484Sobrien	  string_appendn (s, "-", 1);
193260484Sobrien	  (*mangled)++;
193360484Sobrien	}
193460484Sobrien      string_appendn (s, "'", 1);
193560484Sobrien      val = consume_count(mangled);
193660484Sobrien      if (val <= 0)
193760484Sobrien	success = 0;
193860484Sobrien      else
193960484Sobrien	{
194060484Sobrien	  tmp[0] = (char)val;
194160484Sobrien	  tmp[1] = '\0';
194260484Sobrien	  string_appendn (s, &tmp[0], 1);
194360484Sobrien	  string_appendn (s, "'", 1);
194460484Sobrien	}
194560484Sobrien    }
194660484Sobrien  else if (tk == tk_bool)
194760484Sobrien    {
194860484Sobrien      int val = consume_count (mangled);
194960484Sobrien      if (val == 0)
195060484Sobrien	string_appendn (s, "false", 5);
195160484Sobrien      else if (val == 1)
195260484Sobrien	string_appendn (s, "true", 4);
195360484Sobrien      else
195460484Sobrien	success = 0;
195560484Sobrien    }
195660484Sobrien  else if (tk == tk_real)
195760484Sobrien    success = demangle_real_value (work, mangled, s);
195860484Sobrien  else if (tk == tk_pointer || tk == tk_reference)
195960484Sobrien    {
196060484Sobrien      if (**mangled == 'Q')
196160484Sobrien	success = demangle_qualified (work, mangled, s,
196260484Sobrien				      /*isfuncname=*/0,
196360484Sobrien				      /*append=*/1);
196460484Sobrien      else
196560484Sobrien	{
196660484Sobrien	  int symbol_len  = consume_count (mangled);
196760484Sobrien	  if (symbol_len == -1)
196860484Sobrien	    return -1;
196960484Sobrien	  if (symbol_len == 0)
197060484Sobrien	    string_appendn (s, "0", 1);
197160484Sobrien	  else
197260484Sobrien	    {
197360484Sobrien	      char *p = xmalloc (symbol_len + 1), *q;
197460484Sobrien	      strncpy (p, *mangled, symbol_len);
197560484Sobrien	      p [symbol_len] = '\0';
197660484Sobrien	      /* We use cplus_demangle here, rather than
197760484Sobrien		 internal_cplus_demangle, because the name of the entity
197860484Sobrien		 mangled here does not make use of any of the squangling
197960484Sobrien		 or type-code information we have built up thus far; it is
198060484Sobrien		 mangled independently.  */
198160484Sobrien	      q = cplus_demangle (p, work->options);
198260484Sobrien	      if (tk == tk_pointer)
198360484Sobrien		string_appendn (s, "&", 1);
198460484Sobrien	      /* FIXME: Pointer-to-member constants should get a
198560484Sobrien		 qualifying class name here.  */
198660484Sobrien	      if (q)
198760484Sobrien		{
198860484Sobrien		  string_append (s, q);
198960484Sobrien		  free (q);
199060484Sobrien		}
199160484Sobrien	      else
199260484Sobrien		string_append (s, p);
199360484Sobrien	      free (p);
199460484Sobrien	    }
199560484Sobrien	  *mangled += symbol_len;
199660484Sobrien	}
199760484Sobrien    }
199860484Sobrien
199960484Sobrien  return success;
200060484Sobrien}
200160484Sobrien
200260484Sobrien/* Demangle the template name in MANGLED.  The full name of the
200360484Sobrien   template (e.g., S<int>) is placed in TNAME.  The name without the
200460484Sobrien   template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
200560484Sobrien   non-NULL.  If IS_TYPE is nonzero, this template is a type template,
200660484Sobrien   not a function template.  If both IS_TYPE and REMEMBER are nonzero,
200768765Sobrien   the template is remembered in the list of back-referenceable
200860484Sobrien   types.  */
200960484Sobrien
201060484Sobrienstatic int
201160484Sobriendemangle_template (work, mangled, tname, trawname, is_type, remember)
201260484Sobrien     struct work_stuff *work;
201360484Sobrien     const char **mangled;
201460484Sobrien     string *tname;
201533965Sjdp     string *trawname;
201638889Sjdp     int is_type;
201760484Sobrien     int remember;
201833965Sjdp{
201933965Sjdp  int i;
202033965Sjdp  int r;
202133965Sjdp  int need_comma = 0;
202233965Sjdp  int success = 0;
202333965Sjdp  const char *start;
202438889Sjdp  int is_java_array = 0;
202533965Sjdp  string temp;
202660484Sobrien  int bindex = 0;
202733965Sjdp
202833965Sjdp  (*mangled)++;
202938889Sjdp  if (is_type)
203033965Sjdp    {
203160484Sobrien      if (remember)
203260484Sobrien	bindex = register_Btype (work);
203338889Sjdp      start = *mangled;
203438889Sjdp      /* get template name */
203560484Sobrien      if (**mangled == 'z')
203638889Sjdp	{
203760484Sobrien	  int idx;
203860484Sobrien	  (*mangled)++;
203960484Sobrien	  (*mangled)++;
204060484Sobrien
204160484Sobrien	  idx = consume_count_with_underscores (mangled);
204260484Sobrien	  if (idx == -1
204360484Sobrien	      || (work->tmpl_argvec && idx >= work->ntmpl_args)
204460484Sobrien	      || consume_count_with_underscores (mangled) == -1)
204560484Sobrien	    return (0);
204660484Sobrien
204760484Sobrien	  if (work->tmpl_argvec)
204860484Sobrien	    {
204960484Sobrien	      string_append (tname, work->tmpl_argvec[idx]);
205060484Sobrien	      if (trawname)
205160484Sobrien		string_append (trawname, work->tmpl_argvec[idx]);
205260484Sobrien	    }
205360484Sobrien	  else
205460484Sobrien	    {
205560484Sobrien	      string_append_template_idx (tname, idx);
205660484Sobrien	      if (trawname)
205760484Sobrien		string_append_template_idx (trawname, idx);
205860484Sobrien	    }
205938889Sjdp	}
206060484Sobrien      else
206138889Sjdp	{
206260484Sobrien	  if ((r = consume_count (mangled)) <= 0
206360484Sobrien	      || (int) strlen (*mangled) < r)
206460484Sobrien	    {
206560484Sobrien	      return (0);
206660484Sobrien	    }
206760484Sobrien	  is_java_array = (work -> options & DMGL_JAVA)
206860484Sobrien	    && strncmp (*mangled, "JArray1Z", 8) == 0;
206960484Sobrien	  if (! is_java_array)
207060484Sobrien	    {
207160484Sobrien	      string_appendn (tname, *mangled, r);
207260484Sobrien	    }
207360484Sobrien	  if (trawname)
207460484Sobrien	    string_appendn (trawname, *mangled, r);
207560484Sobrien	  *mangled += r;
207638889Sjdp	}
207733965Sjdp    }
207838889Sjdp  if (!is_java_array)
207938889Sjdp    string_append (tname, "<");
208033965Sjdp  /* get size of template parameter list */
208133965Sjdp  if (!get_count (mangled, &r))
208233965Sjdp    {
208333965Sjdp      return (0);
208433965Sjdp    }
208538889Sjdp  if (!is_type)
208638889Sjdp    {
208738889Sjdp      /* Create an array for saving the template argument values. */
208838889Sjdp      work->tmpl_argvec = (char**) xmalloc (r * sizeof (char *));
208938889Sjdp      work->ntmpl_args = r;
209038889Sjdp      for (i = 0; i < r; i++)
209138889Sjdp	work->tmpl_argvec[i] = 0;
209238889Sjdp    }
209333965Sjdp  for (i = 0; i < r; i++)
209433965Sjdp    {
209533965Sjdp      if (need_comma)
209633965Sjdp	{
209733965Sjdp	  string_append (tname, ", ");
209833965Sjdp	}
209933965Sjdp      /* Z for type parameters */
210033965Sjdp      if (**mangled == 'Z')
210133965Sjdp	{
210233965Sjdp	  (*mangled)++;
210333965Sjdp	  /* temp is initialized in do_type */
210433965Sjdp	  success = do_type (work, mangled, &temp);
210533965Sjdp	  if (success)
210633965Sjdp	    {
210733965Sjdp	      string_appends (tname, &temp);
210838889Sjdp
210938889Sjdp	      if (!is_type)
211038889Sjdp		{
211138889Sjdp		  /* Save the template argument. */
211238889Sjdp		  int len = temp.p - temp.b;
211338889Sjdp		  work->tmpl_argvec[i] = xmalloc (len + 1);
211438889Sjdp		  memcpy (work->tmpl_argvec[i], temp.b, len);
211538889Sjdp		  work->tmpl_argvec[i][len] = '\0';
211638889Sjdp		}
211733965Sjdp	    }
211833965Sjdp	  string_delete(&temp);
211933965Sjdp	  if (!success)
212033965Sjdp	    {
212133965Sjdp	      break;
212233965Sjdp	    }
212333965Sjdp	}
212460484Sobrien      /* z for template parameters */
212560484Sobrien      else if (**mangled == 'z')
212660484Sobrien	{
212760484Sobrien	  int r2;
212860484Sobrien	  (*mangled)++;
212960484Sobrien	  success = demangle_template_template_parm (work, mangled, tname);
213060484Sobrien
213160484Sobrien	  if (success
213260484Sobrien	      && (r2 = consume_count (mangled)) > 0
213360484Sobrien	      && (int) strlen (*mangled) >= r2)
213460484Sobrien	    {
213560484Sobrien	      string_append (tname, " ");
213660484Sobrien	      string_appendn (tname, *mangled, r2);
213760484Sobrien	      if (!is_type)
213860484Sobrien		{
213960484Sobrien		  /* Save the template argument. */
214060484Sobrien		  int len = r2;
214160484Sobrien		  work->tmpl_argvec[i] = xmalloc (len + 1);
214260484Sobrien		  memcpy (work->tmpl_argvec[i], *mangled, len);
214360484Sobrien		  work->tmpl_argvec[i][len] = '\0';
214460484Sobrien		}
214560484Sobrien	      *mangled += r2;
214660484Sobrien	    }
214760484Sobrien	  if (!success)
214860484Sobrien	    {
214960484Sobrien	      break;
215060484Sobrien	    }
215160484Sobrien	}
215233965Sjdp      else
215333965Sjdp	{
215438889Sjdp	  string  param;
215538889Sjdp	  string* s;
215638889Sjdp
215733965Sjdp	  /* otherwise, value parameter */
215860484Sobrien
215933965Sjdp	  /* temp is initialized in do_type */
216033965Sjdp	  success = do_type (work, mangled, &temp);
216133965Sjdp	  string_delete(&temp);
216233965Sjdp	  if (!success)
216360484Sobrien	    break;
216438889Sjdp
216538889Sjdp	  if (!is_type)
216638889Sjdp	    {
216738889Sjdp	      s = &param;
216838889Sjdp	      string_init (s);
216938889Sjdp	    }
217038889Sjdp	  else
217138889Sjdp	    s = tname;
217238889Sjdp
217360484Sobrien	  success = demangle_template_value_parm (work, mangled, s,
217460484Sobrien						  (type_kind_t) success);
217538889Sjdp
217660484Sobrien	  if (!success)
217738889Sjdp	    {
217860484Sobrien	      if (!is_type)
217960484Sobrien		string_delete (s);
218060484Sobrien	      success = 0;
218160484Sobrien	      break;
218233965Sjdp	    }
218360484Sobrien
218438889Sjdp	  if (!is_type)
218538889Sjdp	    {
218638889Sjdp	      int len = s->p - s->b;
218738889Sjdp	      work->tmpl_argvec[i] = xmalloc (len + 1);
218838889Sjdp	      memcpy (work->tmpl_argvec[i], s->b, len);
218938889Sjdp	      work->tmpl_argvec[i][len] = '\0';
219060484Sobrien
219138889Sjdp	      string_appends (tname, s);
219238889Sjdp	      string_delete (s);
219338889Sjdp	    }
219433965Sjdp	}
219533965Sjdp      need_comma = 1;
219633965Sjdp    }
219738889Sjdp  if (is_java_array)
219838889Sjdp    {
219938889Sjdp      string_append (tname, "[]");
220038889Sjdp    }
220138889Sjdp  else
220238889Sjdp    {
220338889Sjdp      if (tname->p[-1] == '>')
220438889Sjdp	string_append (tname, " ");
220538889Sjdp      string_append (tname, ">");
220638889Sjdp    }
220760484Sobrien
220860484Sobrien  if (is_type && remember)
220960484Sobrien    remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
221060484Sobrien
221133965Sjdp  /*
221233965Sjdp    if (work -> static_type)
221333965Sjdp    {
221433965Sjdp    string_append (declp, *mangled + 1);
221533965Sjdp    *mangled += strlen (*mangled);
221633965Sjdp    success = 1;
221733965Sjdp    }
221833965Sjdp    else
221933965Sjdp    {
222033965Sjdp    success = demangle_args (work, mangled, declp);
222133965Sjdp    }
222233965Sjdp    }
222333965Sjdp    */
222433965Sjdp  return (success);
222533965Sjdp}
222633965Sjdp
222733965Sjdpstatic int
222833965Sjdparm_pt (work, mangled, n, anchor, args)
222933965Sjdp     struct work_stuff *work;
223033965Sjdp     const char *mangled;
223133965Sjdp     int n;
223233965Sjdp     const char **anchor, **args;
223333965Sjdp{
223460484Sobrien  /* Check if ARM template with "__pt__" in it ("parameterized type") */
223560484Sobrien  /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
223660484Sobrien  if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = mystrstr (mangled, "__pt__")))
223733965Sjdp    {
223833965Sjdp      int len;
223933965Sjdp      *args = *anchor + 6;
224033965Sjdp      len = consume_count (args);
224160484Sobrien      if (len == -1)
224260484Sobrien	return 0;
224333965Sjdp      if (*args + len == mangled + n && **args == '_')
224433965Sjdp	{
224533965Sjdp	  ++*args;
224633965Sjdp	  return 1;
224733965Sjdp	}
224833965Sjdp    }
224960484Sobrien  if (AUTO_DEMANGLING || EDG_DEMANGLING)
225060484Sobrien    {
225160484Sobrien      if ((*anchor = mystrstr (mangled, "__tm__"))
225260484Sobrien          || (*anchor = mystrstr (mangled, "__ps__"))
225360484Sobrien          || (*anchor = mystrstr (mangled, "__pt__")))
225460484Sobrien        {
225560484Sobrien          int len;
225660484Sobrien          *args = *anchor + 6;
225760484Sobrien          len = consume_count (args);
225860484Sobrien	  if (len == -1)
225960484Sobrien	    return 0;
226060484Sobrien          if (*args + len == mangled + n && **args == '_')
226160484Sobrien            {
226260484Sobrien              ++*args;
226360484Sobrien              return 1;
226460484Sobrien            }
226560484Sobrien        }
226660484Sobrien      else if ((*anchor = mystrstr (mangled, "__S")))
226760484Sobrien        {
226860484Sobrien 	  int len;
226960484Sobrien 	  *args = *anchor + 3;
227060484Sobrien 	  len = consume_count (args);
227160484Sobrien	  if (len == -1)
227260484Sobrien	    return 0;
227360484Sobrien 	  if (*args + len == mangled + n && **args == '_')
227460484Sobrien            {
227560484Sobrien              ++*args;
227660484Sobrien 	      return 1;
227760484Sobrien            }
227860484Sobrien        }
227960484Sobrien    }
228060484Sobrien
228133965Sjdp  return 0;
228233965Sjdp}
228333965Sjdp
228433965Sjdpstatic void
228560484Sobriendemangle_arm_hp_template (work, mangled, n, declp)
228633965Sjdp     struct work_stuff *work;
228733965Sjdp     const char **mangled;
228833965Sjdp     int n;
228933965Sjdp     string *declp;
229033965Sjdp{
229133965Sjdp  const char *p;
229233965Sjdp  const char *args;
229333965Sjdp  const char *e = *mangled + n;
229460484Sobrien  string arg;
229533965Sjdp
229660484Sobrien  /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
229760484Sobrien     template args */
229860484Sobrien  if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
229933965Sjdp    {
230060484Sobrien      char *start_spec_args = NULL;
230160484Sobrien
230260484Sobrien      /* First check for and omit template specialization pseudo-arguments,
230360484Sobrien         such as in "Spec<#1,#1.*>" */
230460484Sobrien      start_spec_args = strchr (*mangled, '<');
230560484Sobrien      if (start_spec_args && (start_spec_args - *mangled < n))
230660484Sobrien        string_appendn (declp, *mangled, start_spec_args - *mangled);
230760484Sobrien      else
230860484Sobrien        string_appendn (declp, *mangled, n);
230960484Sobrien      (*mangled) += n + 1;
231033965Sjdp      string_init (&arg);
231160484Sobrien      if (work->temp_start == -1) /* non-recursive call */
231260484Sobrien        work->temp_start = declp->p - declp->b;
231360484Sobrien      string_append (declp, "<");
231460484Sobrien      while (1)
231560484Sobrien        {
231660484Sobrien          string_clear (&arg);
231760484Sobrien          switch (**mangled)
231860484Sobrien            {
231960484Sobrien              case 'T':
232060484Sobrien                /* 'T' signals a type parameter */
232160484Sobrien                (*mangled)++;
232260484Sobrien                if (!do_type (work, mangled, &arg))
232360484Sobrien                  goto hpacc_template_args_done;
232460484Sobrien                break;
232560484Sobrien
232660484Sobrien              case 'U':
232760484Sobrien              case 'S':
232860484Sobrien                /* 'U' or 'S' signals an integral value */
232960484Sobrien                if (!do_hpacc_template_const_value (work, mangled, &arg))
233060484Sobrien                  goto hpacc_template_args_done;
233160484Sobrien                break;
233260484Sobrien
233360484Sobrien              case 'A':
233460484Sobrien                /* 'A' signals a named constant expression (literal) */
233560484Sobrien                if (!do_hpacc_template_literal (work, mangled, &arg))
233660484Sobrien                  goto hpacc_template_args_done;
233760484Sobrien                break;
233860484Sobrien
233960484Sobrien              default:
234060484Sobrien                /* Today, 1997-09-03, we have only the above types
234160484Sobrien                   of template parameters */
234260484Sobrien                /* FIXME: maybe this should fail and return null */
234360484Sobrien                goto hpacc_template_args_done;
234460484Sobrien            }
234560484Sobrien          string_appends (declp, &arg);
234660484Sobrien         /* Check if we're at the end of template args.
234760484Sobrien             0 if at end of static member of template class,
234860484Sobrien             _ if done with template args for a function */
234960484Sobrien          if ((**mangled == '\000') || (**mangled == '_'))
235060484Sobrien            break;
235160484Sobrien          else
235260484Sobrien            string_append (declp, ",");
235360484Sobrien        }
235460484Sobrien    hpacc_template_args_done:
235560484Sobrien      string_append (declp, ">");
235660484Sobrien      string_delete (&arg);
235760484Sobrien      if (**mangled == '_')
235860484Sobrien        (*mangled)++;
235960484Sobrien      return;
236060484Sobrien    }
236160484Sobrien  /* ARM template? (Also handles HP cfront extensions) */
236260484Sobrien  else if (arm_pt (work, *mangled, n, &p, &args))
236360484Sobrien    {
236460484Sobrien      string type_str;
236560484Sobrien
236660484Sobrien      string_init (&arg);
236733965Sjdp      string_appendn (declp, *mangled, p - *mangled);
236860484Sobrien      if (work->temp_start == -1)  /* non-recursive call */
236960484Sobrien	work->temp_start = declp->p - declp->b;
237033965Sjdp      string_append (declp, "<");
237133965Sjdp      /* should do error checking here */
237233965Sjdp      while (args < e) {
237333965Sjdp	string_clear (&arg);
237460484Sobrien
237560484Sobrien	/* Check for type or literal here */
237660484Sobrien	switch (*args)
237760484Sobrien	  {
237860484Sobrien	    /* HP cfront extensions to ARM for template args */
237960484Sobrien	    /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
238060484Sobrien	    /* FIXME: We handle only numeric literals for HP cfront */
238160484Sobrien          case 'X':
238260484Sobrien            /* A typed constant value follows */
238360484Sobrien            args++;
238460484Sobrien            if (!do_type (work, &args, &type_str))
238560484Sobrien	      goto cfront_template_args_done;
238660484Sobrien            string_append (&arg, "(");
238760484Sobrien            string_appends (&arg, &type_str);
238860484Sobrien            string_append (&arg, ")");
238960484Sobrien            if (*args != 'L')
239060484Sobrien              goto cfront_template_args_done;
239160484Sobrien            args++;
239260484Sobrien            /* Now snarf a literal value following 'L' */
239360484Sobrien            if (!snarf_numeric_literal (&args, &arg))
239460484Sobrien	      goto cfront_template_args_done;
239560484Sobrien            break;
239660484Sobrien
239760484Sobrien          case 'L':
239860484Sobrien            /* Snarf a literal following 'L' */
239960484Sobrien            args++;
240060484Sobrien            if (!snarf_numeric_literal (&args, &arg))
240160484Sobrien	      goto cfront_template_args_done;
240260484Sobrien            break;
240360484Sobrien          default:
240460484Sobrien            /* Not handling other HP cfront stuff */
240560484Sobrien            if (!do_type (work, &args, &arg))
240660484Sobrien              goto cfront_template_args_done;
240760484Sobrien	  }
240833965Sjdp	string_appends (declp, &arg);
240933965Sjdp	string_append (declp, ",");
241033965Sjdp      }
241160484Sobrien    cfront_template_args_done:
241233965Sjdp      string_delete (&arg);
241360484Sobrien      if (args >= e)
241460484Sobrien	--declp->p; /* remove extra comma */
241533965Sjdp      string_append (declp, ">");
241633965Sjdp    }
241760484Sobrien  else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
241860484Sobrien	   && (*mangled)[9] == 'N'
241960484Sobrien	   && (*mangled)[8] == (*mangled)[10]
242060484Sobrien	   && strchr (cplus_markers, (*mangled)[8]))
242160484Sobrien    {
242260484Sobrien      /* A member of the anonymous namespace.  */
242360484Sobrien      string_append (declp, "{anonymous}");
242460484Sobrien    }
242533965Sjdp  else
242633965Sjdp    {
242760484Sobrien      if (work->temp_start == -1) /* non-recursive call only */
242860484Sobrien	work->temp_start = 0;     /* disable in recursive calls */
242933965Sjdp      string_appendn (declp, *mangled, n);
243033965Sjdp    }
243133965Sjdp  *mangled += n;
243233965Sjdp}
243333965Sjdp
243460484Sobrien/* Extract a class name, possibly a template with arguments, from the
243560484Sobrien   mangled string; qualifiers, local class indicators, etc. have
243660484Sobrien   already been dealt with */
243760484Sobrien
243833965Sjdpstatic int
243933965Sjdpdemangle_class_name (work, mangled, declp)
244033965Sjdp     struct work_stuff *work;
244133965Sjdp     const char **mangled;
244233965Sjdp     string *declp;
244333965Sjdp{
244433965Sjdp  int n;
244533965Sjdp  int success = 0;
244633965Sjdp
244733965Sjdp  n = consume_count (mangled);
244860484Sobrien  if (n == -1)
244960484Sobrien    return 0;
245060484Sobrien  if ((int) strlen (*mangled) >= n)
245133965Sjdp    {
245260484Sobrien      demangle_arm_hp_template (work, mangled, n, declp);
245333965Sjdp      success = 1;
245433965Sjdp    }
245533965Sjdp
245633965Sjdp  return (success);
245733965Sjdp}
245833965Sjdp
245933965Sjdp/*
246033965Sjdp
246133965SjdpLOCAL FUNCTION
246233965Sjdp
246333965Sjdp	demangle_class -- demangle a mangled class sequence
246433965Sjdp
246533965SjdpSYNOPSIS
246633965Sjdp
246733965Sjdp	static int
246833965Sjdp	demangle_class (struct work_stuff *work, const char **mangled,
246933965Sjdp			strint *declp)
247033965Sjdp
247133965SjdpDESCRIPTION
247233965Sjdp
247333965Sjdp	DECLP points to the buffer into which demangling is being done.
247433965Sjdp
247533965Sjdp	*MANGLED points to the current token to be demangled.  On input,
247633965Sjdp	it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
247733965Sjdp	On exit, it points to the next token after the mangled class on
247833965Sjdp	success, or the first unconsumed token on failure.
247933965Sjdp
248033965Sjdp	If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
248133965Sjdp	we are demangling a constructor or destructor.  In this case
248233965Sjdp	we prepend "class::class" or "class::~class" to DECLP.
248333965Sjdp
248433965Sjdp	Otherwise, we prepend "class::" to the current DECLP.
248533965Sjdp
248633965Sjdp	Reset the constructor/destructor flags once they have been
248733965Sjdp	"consumed".  This allows demangle_class to be called later during
248833965Sjdp	the same demangling, to do normal class demangling.
248933965Sjdp
249033965Sjdp	Returns 1 if demangling is successful, 0 otherwise.
249133965Sjdp
249233965Sjdp*/
249333965Sjdp
249433965Sjdpstatic int
249533965Sjdpdemangle_class (work, mangled, declp)
249633965Sjdp     struct work_stuff *work;
249733965Sjdp     const char **mangled;
249833965Sjdp     string *declp;
249933965Sjdp{
250033965Sjdp  int success = 0;
250160484Sobrien  int btype;
250233965Sjdp  string class_name;
250360484Sobrien  char *save_class_name_end = 0;
250433965Sjdp
250533965Sjdp  string_init (&class_name);
250660484Sobrien  btype = register_Btype (work);
250733965Sjdp  if (demangle_class_name (work, mangled, &class_name))
250833965Sjdp    {
250960484Sobrien      save_class_name_end = class_name.p;
251033965Sjdp      if ((work->constructor & 1) || (work->destructor & 1))
251133965Sjdp	{
251260484Sobrien          /* adjust so we don't include template args */
251360484Sobrien          if (work->temp_start && (work->temp_start != -1))
251460484Sobrien            {
251560484Sobrien              class_name.p = class_name.b + work->temp_start;
251660484Sobrien            }
251733965Sjdp	  string_prepends (declp, &class_name);
251833965Sjdp	  if (work -> destructor & 1)
251933965Sjdp	    {
252033965Sjdp	      string_prepend (declp, "~");
252133965Sjdp              work -> destructor -= 1;
252233965Sjdp	    }
252333965Sjdp	  else
252433965Sjdp	    {
252560484Sobrien	      work -> constructor -= 1;
252633965Sjdp	    }
252733965Sjdp	}
252860484Sobrien      class_name.p = save_class_name_end;
252960484Sobrien      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
253060484Sobrien      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
253160484Sobrien      string_prepend (declp, SCOPE_STRING (work));
253233965Sjdp      string_prepends (declp, &class_name);
253333965Sjdp      success = 1;
253433965Sjdp    }
253533965Sjdp  string_delete (&class_name);
253633965Sjdp  return (success);
253733965Sjdp}
253833965Sjdp
253968765Sobrien
254068765Sobrien/* Called when there's a "__" in the mangled name, with `scan' pointing to
254168765Sobrien   the rightmost guess.
254268765Sobrien
254368765Sobrien   Find the correct "__"-sequence where the function name ends and the
254468765Sobrien   signature starts, which is ambiguous with GNU mangling.
254568765Sobrien   Call demangle_signature here, so we can make sure we found the right
254668765Sobrien   one; *mangled will be consumed so caller will not make further calls to
254768765Sobrien   demangle_signature.  */
254868765Sobrien
254968765Sobrienstatic int
255068765Sobrieniterate_demangle_function (work, mangled, declp, scan)
255168765Sobrien     struct work_stuff *work;
255268765Sobrien     const char **mangled;
255368765Sobrien     string *declp;
255468765Sobrien     const char *scan;
255568765Sobrien{
255668765Sobrien  const char *mangle_init = *mangled;
255768765Sobrien  int success = 0;
255868765Sobrien  string decl_init;
255968765Sobrien  struct work_stuff work_init;
256068765Sobrien
256168765Sobrien  if (*(scan + 2) == '\0')
256268765Sobrien    return 0;
256368765Sobrien
256468765Sobrien  /* Do not iterate for some demangling modes, or if there's only one
256568765Sobrien     "__"-sequence.  This is the normal case.  */
256668765Sobrien  if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
256768765Sobrien      || mystrstr (scan + 2, "__") == NULL)
256868765Sobrien    {
256968765Sobrien      demangle_function_name (work, mangled, declp, scan);
257068765Sobrien      return 1;
257168765Sobrien    }
257268765Sobrien
257368765Sobrien  /* Save state so we can restart if the guess at the correct "__" was
257468765Sobrien     wrong.  */
257568765Sobrien  string_init (&decl_init);
257668765Sobrien  string_appends (&decl_init, declp);
257768765Sobrien  memset (&work_init, 0, sizeof work_init);
257868765Sobrien  work_stuff_copy_to_from (&work_init, work);
257968765Sobrien
258068765Sobrien  /* Iterate over occurrences of __, allowing names and types to have a
258168765Sobrien     "__" sequence in them.  We must start with the first (not the last)
258268765Sobrien     occurrence, since "__" most often occur between independent mangled
258368765Sobrien     parts, hence starting at the last occurence inside a signature
258468765Sobrien     might get us a "successful" demangling of the signature.  */
258568765Sobrien
258668765Sobrien  while (scan[2])
258768765Sobrien    {
258868765Sobrien      demangle_function_name (work, mangled, declp, scan);
258968765Sobrien      success = demangle_signature (work, mangled, declp);
259068765Sobrien      if (success)
259168765Sobrien	break;
259268765Sobrien
259368765Sobrien      /* Reset demangle state for the next round.  */
259468765Sobrien      *mangled = mangle_init;
259568765Sobrien      string_clear (declp);
259668765Sobrien      string_appends (declp, &decl_init);
259768765Sobrien      work_stuff_copy_to_from (work, &work_init);
259868765Sobrien
259968765Sobrien      /* Leave this underscore-sequence.  */
260068765Sobrien      scan += 2;
260168765Sobrien
260268765Sobrien      /* Scan for the next "__" sequence.  */
260368765Sobrien      while (*scan && (scan[0] != '_' || scan[1] != '_'))
260468765Sobrien	scan++;
260568765Sobrien
260668765Sobrien      /* Move to last "__" in this sequence.  */
260768765Sobrien      while (*scan && *scan == '_')
260868765Sobrien	scan++;
260968765Sobrien      scan -= 2;
261068765Sobrien    }
261168765Sobrien
261268765Sobrien  /* Delete saved state.  */
261368765Sobrien  delete_work_stuff (&work_init);
261468765Sobrien  string_delete (&decl_init);
261568765Sobrien
261668765Sobrien  return success;
261768765Sobrien}
261868765Sobrien
261933965Sjdp/*
262033965Sjdp
262133965SjdpLOCAL FUNCTION
262233965Sjdp
262333965Sjdp	demangle_prefix -- consume the mangled name prefix and find signature
262433965Sjdp
262533965SjdpSYNOPSIS
262633965Sjdp
262733965Sjdp	static int
262833965Sjdp	demangle_prefix (struct work_stuff *work, const char **mangled,
262933965Sjdp			 string *declp);
263033965Sjdp
263133965SjdpDESCRIPTION
263233965Sjdp
263333965Sjdp	Consume and demangle the prefix of the mangled name.
263468765Sobrien	While processing the function name root, arrange to call
263568765Sobrien	demangle_signature if the root is ambiguous.
263633965Sjdp
263733965Sjdp	DECLP points to the string buffer into which demangled output is
263833965Sjdp	placed.  On entry, the buffer is empty.  On exit it contains
263933965Sjdp	the root function name, the demangled operator name, or in some
264033965Sjdp	special cases either nothing or the completely demangled result.
264133965Sjdp
264233965Sjdp	MANGLED points to the current pointer into the mangled name.  As each
264333965Sjdp	token of the mangled name is consumed, it is updated.  Upon entry
264433965Sjdp	the current mangled name pointer points to the first character of
264533965Sjdp	the mangled name.  Upon exit, it should point to the first character
264633965Sjdp	of the signature if demangling was successful, or to the first
264733965Sjdp	unconsumed character if demangling of the prefix was unsuccessful.
264860484Sobrien
264933965Sjdp	Returns 1 on success, 0 otherwise.
265033965Sjdp */
265133965Sjdp
265233965Sjdpstatic int
265333965Sjdpdemangle_prefix (work, mangled, declp)
265433965Sjdp     struct work_stuff *work;
265533965Sjdp     const char **mangled;
265633965Sjdp     string *declp;
265733965Sjdp{
265833965Sjdp  int success = 1;
265933965Sjdp  const char *scan;
266033965Sjdp  int i;
266133965Sjdp
266260484Sobrien  if (strlen(*mangled) > 6
266360484Sobrien      && (strncmp(*mangled, "_imp__", 6) == 0
266460484Sobrien          || strncmp(*mangled, "__imp_", 6) == 0))
266533965Sjdp    {
266660484Sobrien      /* it's a symbol imported from a PE dynamic library. Check for both
266760484Sobrien         new style prefix _imp__ and legacy __imp_ used by older versions
266860484Sobrien	 of dlltool. */
266960484Sobrien      (*mangled) += 6;
267060484Sobrien      work->dllimported = 1;
267160484Sobrien    }
267260484Sobrien  else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
267360484Sobrien    {
267433965Sjdp      char *marker = strchr (cplus_markers, (*mangled)[8]);
267533965Sjdp      if (marker != NULL && *marker == (*mangled)[10])
267633965Sjdp	{
267733965Sjdp	  if ((*mangled)[9] == 'D')
267833965Sjdp	    {
267933965Sjdp	      /* it's a GNU global destructor to be executed at program exit */
268033965Sjdp	      (*mangled) += 11;
268133965Sjdp	      work->destructor = 2;
268233965Sjdp	      if (gnu_special (work, mangled, declp))
268333965Sjdp		return success;
268433965Sjdp	    }
268533965Sjdp	  else if ((*mangled)[9] == 'I')
268633965Sjdp	    {
268733965Sjdp	      /* it's a GNU global constructor to be executed at program init */
268833965Sjdp	      (*mangled) += 11;
268933965Sjdp	      work->constructor = 2;
269033965Sjdp	      if (gnu_special (work, mangled, declp))
269133965Sjdp		return success;
269233965Sjdp	    }
269333965Sjdp	}
269433965Sjdp    }
269560484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
269633965Sjdp    {
269733965Sjdp      /* it's a ARM global destructor to be executed at program exit */
269833965Sjdp      (*mangled) += 7;
269933965Sjdp      work->destructor = 2;
270033965Sjdp    }
270160484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
270233965Sjdp    {
270333965Sjdp      /* it's a ARM global constructor to be executed at program initial */
270433965Sjdp      (*mangled) += 7;
270533965Sjdp      work->constructor = 2;
270633965Sjdp    }
270733965Sjdp
270833965Sjdp  /*  This block of code is a reduction in strength time optimization
270933965Sjdp      of:
271033965Sjdp      scan = mystrstr (*mangled, "__"); */
271133965Sjdp
271233965Sjdp  {
271333965Sjdp    scan = *mangled;
271433965Sjdp
271533965Sjdp    do {
271633965Sjdp      scan = strchr (scan, '_');
271733965Sjdp    } while (scan != NULL && *++scan != '_');
271833965Sjdp
271933965Sjdp    if (scan != NULL) --scan;
272033965Sjdp  }
272133965Sjdp
272233965Sjdp  if (scan != NULL)
272333965Sjdp    {
272433965Sjdp      /* We found a sequence of two or more '_', ensure that we start at
272533965Sjdp	 the last pair in the sequence.  */
272633965Sjdp      i = strspn (scan, "_");
272733965Sjdp      if (i > 2)
272833965Sjdp	{
272960484Sobrien	  scan += (i - 2);
273033965Sjdp	}
273133965Sjdp    }
273260484Sobrien
273333965Sjdp  if (scan == NULL)
273433965Sjdp    {
273533965Sjdp      success = 0;
273633965Sjdp    }
273733965Sjdp  else if (work -> static_type)
273833965Sjdp    {
273977298Sobrien      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
274033965Sjdp	{
274133965Sjdp	  success = 0;
274233965Sjdp	}
274333965Sjdp    }
274438889Sjdp  else if ((scan == *mangled)
274577298Sobrien	   && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
274660484Sobrien	       || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
274733965Sjdp    {
274833965Sjdp      /* The ARM says nothing about the mangling of local variables.
274933965Sjdp	 But cfront mangles local variables by prepending __<nesting_level>
275033965Sjdp	 to them. As an extension to ARM demangling we handle this case.  */
275160484Sobrien      if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
275277298Sobrien	  && ISDIGIT ((unsigned char)scan[2]))
275333965Sjdp	{
275433965Sjdp	  *mangled = scan + 2;
275533965Sjdp	  consume_count (mangled);
275633965Sjdp	  string_append (declp, *mangled);
275733965Sjdp	  *mangled += strlen (*mangled);
275860484Sobrien	  success = 1;
275933965Sjdp	}
276033965Sjdp      else
276133965Sjdp	{
276233965Sjdp	  /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
276333965Sjdp	     names like __Q2_3foo3bar for nested type names.  So don't accept
276438889Sjdp	     this style of constructor for cfront demangling.  A GNU
276538889Sjdp	     style member-template constructor starts with 'H'. */
276660484Sobrien	  if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
276733965Sjdp	    work -> constructor += 1;
276833965Sjdp	  *mangled = scan + 2;
276933965Sjdp	}
277033965Sjdp    }
277160484Sobrien  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
277233965Sjdp    {
277360484Sobrien      /* Cfront-style parameterized type.  Handled later as a signature. */
277460484Sobrien      success = 1;
277560484Sobrien
277660484Sobrien      /* ARM template? */
277760484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
277860484Sobrien    }
277960484Sobrien  else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
278060484Sobrien                              || (scan[2] == 'p' && scan[3] == 's')
278160484Sobrien                              || (scan[2] == 'p' && scan[3] == 't')))
278260484Sobrien    {
278360484Sobrien      /* EDG-style parameterized type.  Handled later as a signature. */
278460484Sobrien      success = 1;
278560484Sobrien
278660484Sobrien      /* EDG template? */
278760484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
278860484Sobrien    }
278977298Sobrien  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
279060484Sobrien	   && (scan[2] != 't'))
279160484Sobrien    {
279233965Sjdp      /* Mangled name starts with "__".  Skip over any leading '_' characters,
279333965Sjdp	 then find the next "__" that separates the prefix from the signature.
279433965Sjdp	 */
279560484Sobrien      if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
279660484Sobrien	  || (arm_special (mangled, declp) == 0))
279733965Sjdp	{
279833965Sjdp	  while (*scan == '_')
279933965Sjdp	    {
280033965Sjdp	      scan++;
280133965Sjdp	    }
280233965Sjdp	  if ((scan = mystrstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
280333965Sjdp	    {
280433965Sjdp	      /* No separator (I.E. "__not_mangled"), or empty signature
280533965Sjdp		 (I.E. "__not_mangled_either__") */
280633965Sjdp	      success = 0;
280733965Sjdp	    }
280833965Sjdp	  else
280968765Sobrien	    return iterate_demangle_function (work, mangled, declp, scan);
281033965Sjdp	}
281133965Sjdp    }
281233965Sjdp  else if (*(scan + 2) != '\0')
281333965Sjdp    {
281433965Sjdp      /* Mangled name does not start with "__" but does have one somewhere
281533965Sjdp	 in there with non empty stuff after it.  Looks like a global
281668765Sobrien	 function name.  Iterate over all "__":s until the right
281768765Sobrien	 one is found.  */
281868765Sobrien      return iterate_demangle_function (work, mangled, declp, scan);
281933965Sjdp    }
282033965Sjdp  else
282133965Sjdp    {
282233965Sjdp      /* Doesn't look like a mangled name */
282333965Sjdp      success = 0;
282433965Sjdp    }
282533965Sjdp
282633965Sjdp  if (!success && (work->constructor == 2 || work->destructor == 2))
282733965Sjdp    {
282833965Sjdp      string_append (declp, *mangled);
282933965Sjdp      *mangled += strlen (*mangled);
283033965Sjdp      success = 1;
283160484Sobrien    }
283233965Sjdp  return (success);
283333965Sjdp}
283433965Sjdp
283533965Sjdp/*
283633965Sjdp
283733965SjdpLOCAL FUNCTION
283833965Sjdp
283933965Sjdp	gnu_special -- special handling of gnu mangled strings
284033965Sjdp
284133965SjdpSYNOPSIS
284233965Sjdp
284333965Sjdp	static int
284433965Sjdp	gnu_special (struct work_stuff *work, const char **mangled,
284533965Sjdp		     string *declp);
284633965Sjdp
284733965Sjdp
284833965SjdpDESCRIPTION
284933965Sjdp
285033965Sjdp	Process some special GNU style mangling forms that don't fit
285133965Sjdp	the normal pattern.  For example:
285233965Sjdp
285333965Sjdp		_$_3foo		(destructor for class foo)
285433965Sjdp		_vt$foo		(foo virtual table)
285533965Sjdp		_vt$foo$bar	(foo::bar virtual table)
285633965Sjdp		__vt_foo	(foo virtual table, new style with thunks)
285733965Sjdp		_3foo$varname	(static data member)
285833965Sjdp		_Q22rs2tu$vw	(static data member)
285933965Sjdp		__t6vector1Zii	(constructor with template)
286033965Sjdp		__thunk_4__$_7ostream (virtual function thunk)
286133965Sjdp */
286233965Sjdp
286333965Sjdpstatic int
286433965Sjdpgnu_special (work, mangled, declp)
286533965Sjdp     struct work_stuff *work;
286633965Sjdp     const char **mangled;
286733965Sjdp     string *declp;
286833965Sjdp{
286933965Sjdp  int n;
287033965Sjdp  int success = 1;
287133965Sjdp  const char *p;
287233965Sjdp
287333965Sjdp  if ((*mangled)[0] == '_'
287433965Sjdp      && strchr (cplus_markers, (*mangled)[1]) != NULL
287533965Sjdp      && (*mangled)[2] == '_')
287633965Sjdp    {
287733965Sjdp      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
287833965Sjdp      (*mangled) += 3;
287933965Sjdp      work -> destructor += 1;
288033965Sjdp    }
288133965Sjdp  else if ((*mangled)[0] == '_'
288233965Sjdp	   && (((*mangled)[1] == '_'
288333965Sjdp		&& (*mangled)[2] == 'v'
288433965Sjdp		&& (*mangled)[3] == 't'
288533965Sjdp		&& (*mangled)[4] == '_')
288633965Sjdp	       || ((*mangled)[1] == 'v'
288733965Sjdp		   && (*mangled)[2] == 't'
288833965Sjdp		   && strchr (cplus_markers, (*mangled)[3]) != NULL)))
288933965Sjdp    {
289033965Sjdp      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
289133965Sjdp         and create the decl.  Note that we consume the entire mangled
289233965Sjdp	 input string, which means that demangle_signature has no work
289333965Sjdp	 to do.  */
289433965Sjdp      if ((*mangled)[2] == 'v')
289533965Sjdp	(*mangled) += 5; /* New style, with thunks: "__vt_" */
289633965Sjdp      else
289733965Sjdp	(*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
289833965Sjdp      while (**mangled != '\0')
289933965Sjdp	{
290033965Sjdp	  switch (**mangled)
290133965Sjdp	    {
290233965Sjdp	    case 'Q':
290360484Sobrien	    case 'K':
290433965Sjdp	      success = demangle_qualified (work, mangled, declp, 0, 1);
290533965Sjdp	      break;
290633965Sjdp	    case 't':
290760484Sobrien	      success = demangle_template (work, mangled, declp, 0, 1,
290860484Sobrien					   1);
290933965Sjdp	      break;
291033965Sjdp	    default:
291177298Sobrien	      if (ISDIGIT((unsigned char)*mangled[0]))
291233965Sjdp		{
291333965Sjdp		  n = consume_count(mangled);
291438889Sjdp		  /* We may be seeing a too-large size, or else a
291538889Sjdp		     ".<digits>" indicating a static local symbol.  In
291638889Sjdp		     any case, declare victory and move on; *don't* try
291738889Sjdp		     to use n to allocate.  */
291860484Sobrien		  if (n > (int) strlen (*mangled))
291938889Sjdp		    {
292038889Sjdp		      success = 1;
292138889Sjdp		      break;
292238889Sjdp		    }
292333965Sjdp		}
292433965Sjdp	      else
292533965Sjdp		{
292633965Sjdp		  n = strcspn (*mangled, cplus_markers);
292733965Sjdp		}
292833965Sjdp	      string_appendn (declp, *mangled, n);
292933965Sjdp	      (*mangled) += n;
293033965Sjdp	    }
293133965Sjdp
293260484Sobrien	  p = strpbrk (*mangled, cplus_markers);
293333965Sjdp	  if (success && ((p == NULL) || (p == *mangled)))
293433965Sjdp	    {
293533965Sjdp	      if (p != NULL)
293633965Sjdp		{
293760484Sobrien		  string_append (declp, SCOPE_STRING (work));
293833965Sjdp		  (*mangled)++;
293933965Sjdp		}
294033965Sjdp	    }
294133965Sjdp	  else
294233965Sjdp	    {
294333965Sjdp	      success = 0;
294433965Sjdp	      break;
294533965Sjdp	    }
294633965Sjdp	}
294733965Sjdp      if (success)
294833965Sjdp	string_append (declp, " virtual table");
294933965Sjdp    }
295033965Sjdp  else if ((*mangled)[0] == '_'
295133965Sjdp	   && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
295233965Sjdp	   && (p = strpbrk (*mangled, cplus_markers)) != NULL)
295333965Sjdp    {
295433965Sjdp      /* static data member, "_3foo$varname" for example */
295533965Sjdp      (*mangled)++;
295633965Sjdp      switch (**mangled)
295733965Sjdp	{
295833965Sjdp	case 'Q':
295960484Sobrien	case 'K':
296033965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
296133965Sjdp	  break;
296233965Sjdp	case 't':
296360484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
296433965Sjdp	  break;
296533965Sjdp	default:
296633965Sjdp	  n = consume_count (mangled);
296760484Sobrien	  if (n < 0 || n > (long) strlen (*mangled))
296860484Sobrien	    {
296960484Sobrien	      success = 0;
297060484Sobrien	      break;
297160484Sobrien	    }
297268765Sobrien
297368765Sobrien	  if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
297468765Sobrien	      && (*mangled)[9] == 'N'
297568765Sobrien	      && (*mangled)[8] == (*mangled)[10]
297668765Sobrien	      && strchr (cplus_markers, (*mangled)[8]))
297768765Sobrien	    {
297868765Sobrien	      /* A member of the anonymous namespace.  There's information
297968765Sobrien		 about what identifier or filename it was keyed to, but
298068765Sobrien		 it's just there to make the mangled name unique; we just
298168765Sobrien		 step over it.  */
298268765Sobrien	      string_append (declp, "{anonymous}");
298368765Sobrien	      (*mangled) += n;
298468765Sobrien
298568765Sobrien	      /* Now p points to the marker before the N, so we need to
298668765Sobrien		 update it to the first marker after what we consumed.  */
298768765Sobrien	      p = strpbrk (*mangled, cplus_markers);
298868765Sobrien	      break;
298968765Sobrien	    }
299068765Sobrien
299133965Sjdp	  string_appendn (declp, *mangled, n);
299233965Sjdp	  (*mangled) += n;
299333965Sjdp	}
299433965Sjdp      if (success && (p == *mangled))
299533965Sjdp	{
299633965Sjdp	  /* Consumed everything up to the cplus_marker, append the
299733965Sjdp	     variable name.  */
299833965Sjdp	  (*mangled)++;
299960484Sobrien	  string_append (declp, SCOPE_STRING (work));
300033965Sjdp	  n = strlen (*mangled);
300133965Sjdp	  string_appendn (declp, *mangled, n);
300233965Sjdp	  (*mangled) += n;
300333965Sjdp	}
300433965Sjdp      else
300533965Sjdp	{
300633965Sjdp	  success = 0;
300733965Sjdp	}
300833965Sjdp    }
300933965Sjdp  else if (strncmp (*mangled, "__thunk_", 8) == 0)
301033965Sjdp    {
301160484Sobrien      int delta;
301260484Sobrien
301360484Sobrien      (*mangled) += 8;
301460484Sobrien      delta = consume_count (mangled);
301560484Sobrien      if (delta == -1)
301660484Sobrien	success = 0;
301733965Sjdp      else
301833965Sjdp	{
301960484Sobrien	  char *method = internal_cplus_demangle (work, ++*mangled);
302060484Sobrien
302160484Sobrien	  if (method)
302260484Sobrien	    {
302360484Sobrien	      char buf[50];
302460484Sobrien	      sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
302560484Sobrien	      string_append (declp, buf);
302660484Sobrien	      string_append (declp, method);
302760484Sobrien	      free (method);
302860484Sobrien	      n = strlen (*mangled);
302960484Sobrien	      (*mangled) += n;
303060484Sobrien	    }
303160484Sobrien	  else
303260484Sobrien	    {
303360484Sobrien	      success = 0;
303460484Sobrien	    }
303533965Sjdp	}
303633965Sjdp    }
303733965Sjdp  else if (strncmp (*mangled, "__t", 3) == 0
303833965Sjdp	   && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
303933965Sjdp    {
304033965Sjdp      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
304133965Sjdp      (*mangled) += 4;
304233965Sjdp      switch (**mangled)
304333965Sjdp	{
304433965Sjdp	case 'Q':
304560484Sobrien	case 'K':
304633965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
304733965Sjdp	  break;
304833965Sjdp	case 't':
304960484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
305033965Sjdp	  break;
305133965Sjdp	default:
305268765Sobrien	  success = do_type (work, mangled, declp);
305333965Sjdp	  break;
305433965Sjdp	}
305533965Sjdp      if (success && **mangled != '\0')
305633965Sjdp	success = 0;
305733965Sjdp      if (success)
305833965Sjdp	string_append (declp, p);
305933965Sjdp    }
306033965Sjdp  else
306133965Sjdp    {
306233965Sjdp      success = 0;
306333965Sjdp    }
306433965Sjdp  return (success);
306533965Sjdp}
306633965Sjdp
306760484Sobrienstatic void
306860484Sobrienrecursively_demangle(work, mangled, result, namelength)
306960484Sobrien     struct work_stuff *work;
307060484Sobrien     const char **mangled;
307160484Sobrien     string *result;
307260484Sobrien     int namelength;
307360484Sobrien{
307460484Sobrien  char * recurse = (char *)NULL;
307560484Sobrien  char * recurse_dem = (char *)NULL;
307660484Sobrien
307760484Sobrien  recurse = (char *) xmalloc (namelength + 1);
307860484Sobrien  memcpy (recurse, *mangled, namelength);
307960484Sobrien  recurse[namelength] = '\000';
308060484Sobrien
308160484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
308260484Sobrien
308360484Sobrien  if (recurse_dem)
308460484Sobrien    {
308560484Sobrien      string_append (result, recurse_dem);
308660484Sobrien      free (recurse_dem);
308760484Sobrien    }
308860484Sobrien  else
308960484Sobrien    {
309060484Sobrien      string_appendn (result, *mangled, namelength);
309160484Sobrien    }
309260484Sobrien  free (recurse);
309360484Sobrien  *mangled += namelength;
309460484Sobrien}
309560484Sobrien
309633965Sjdp/*
309733965Sjdp
309833965SjdpLOCAL FUNCTION
309933965Sjdp
310033965Sjdp	arm_special -- special handling of ARM/lucid mangled strings
310133965Sjdp
310233965SjdpSYNOPSIS
310333965Sjdp
310433965Sjdp	static int
310560484Sobrien	arm_special (const char **mangled,
310660484Sobrien		     string *declp);
310733965Sjdp
310833965Sjdp
310933965SjdpDESCRIPTION
311033965Sjdp
311133965Sjdp	Process some special ARM style mangling forms that don't fit
311233965Sjdp	the normal pattern.  For example:
311333965Sjdp
311433965Sjdp		__vtbl__3foo		(foo virtual table)
311533965Sjdp		__vtbl__3foo__3bar	(bar::foo virtual table)
311633965Sjdp
311733965Sjdp */
311833965Sjdp
311933965Sjdpstatic int
312060484Sobrienarm_special (mangled, declp)
312133965Sjdp     const char **mangled;
312233965Sjdp     string *declp;
312333965Sjdp{
312433965Sjdp  int n;
312533965Sjdp  int success = 1;
312633965Sjdp  const char *scan;
312733965Sjdp
312833965Sjdp  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
312933965Sjdp    {
313033965Sjdp      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
313133965Sjdp         and create the decl.  Note that we consume the entire mangled
313233965Sjdp	 input string, which means that demangle_signature has no work
313333965Sjdp	 to do.  */
313433965Sjdp      scan = *mangled + ARM_VTABLE_STRLEN;
313533965Sjdp      while (*scan != '\0')        /* first check it can be demangled */
313633965Sjdp        {
313733965Sjdp          n = consume_count (&scan);
313860484Sobrien          if (n == -1)
313933965Sjdp	    {
314033965Sjdp	      return (0);           /* no good */
314133965Sjdp	    }
314233965Sjdp          scan += n;
314333965Sjdp          if (scan[0] == '_' && scan[1] == '_')
314433965Sjdp	    {
314533965Sjdp	      scan += 2;
314633965Sjdp	    }
314733965Sjdp        }
314833965Sjdp      (*mangled) += ARM_VTABLE_STRLEN;
314933965Sjdp      while (**mangled != '\0')
315033965Sjdp	{
315133965Sjdp	  n = consume_count (mangled);
315260484Sobrien          if (n == -1
315360484Sobrien	      || n > (long) strlen (*mangled))
315460484Sobrien	    return 0;
315533965Sjdp	  string_prependn (declp, *mangled, n);
315633965Sjdp	  (*mangled) += n;
315733965Sjdp	  if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
315833965Sjdp	    {
315933965Sjdp	      string_prepend (declp, "::");
316033965Sjdp	      (*mangled) += 2;
316133965Sjdp	    }
316233965Sjdp	}
316333965Sjdp      string_append (declp, " virtual table");
316433965Sjdp    }
316533965Sjdp  else
316633965Sjdp    {
316733965Sjdp      success = 0;
316833965Sjdp    }
316933965Sjdp  return (success);
317033965Sjdp}
317133965Sjdp
317233965Sjdp/*
317333965Sjdp
317433965SjdpLOCAL FUNCTION
317533965Sjdp
317633965Sjdp	demangle_qualified -- demangle 'Q' qualified name strings
317733965Sjdp
317833965SjdpSYNOPSIS
317933965Sjdp
318033965Sjdp	static int
318133965Sjdp	demangle_qualified (struct work_stuff *, const char *mangled,
318233965Sjdp			    string *result, int isfuncname, int append);
318333965Sjdp
318433965SjdpDESCRIPTION
318533965Sjdp
318633965Sjdp	Demangle a qualified name, such as "Q25Outer5Inner" which is
318733965Sjdp	the mangled form of "Outer::Inner".  The demangled output is
318833965Sjdp	prepended or appended to the result string according to the
318933965Sjdp	state of the append flag.
319033965Sjdp
319133965Sjdp	If isfuncname is nonzero, then the qualified name we are building
319233965Sjdp	is going to be used as a member function name, so if it is a
319333965Sjdp	constructor or destructor function, append an appropriate
319433965Sjdp	constructor or destructor name.  I.E. for the above example,
319533965Sjdp	the result for use as a constructor is "Outer::Inner::Inner"
319633965Sjdp	and the result for use as a destructor is "Outer::Inner::~Inner".
319733965Sjdp
319833965SjdpBUGS
319933965Sjdp
320033965Sjdp	Numeric conversion is ASCII dependent (FIXME).
320133965Sjdp
320233965Sjdp */
320333965Sjdp
320433965Sjdpstatic int
320533965Sjdpdemangle_qualified (work, mangled, result, isfuncname, append)
320633965Sjdp     struct work_stuff *work;
320733965Sjdp     const char **mangled;
320833965Sjdp     string *result;
320933965Sjdp     int isfuncname;
321033965Sjdp     int append;
321133965Sjdp{
321260484Sobrien  int qualifiers = 0;
321333965Sjdp  int success = 1;
321433965Sjdp  char num[2];
321533965Sjdp  string temp;
321660484Sobrien  string last_name;
321760484Sobrien  int bindex = register_Btype (work);
321833965Sjdp
321960484Sobrien  /* We only make use of ISFUNCNAME if the entity is a constructor or
322060484Sobrien     destructor.  */
322160484Sobrien  isfuncname = (isfuncname
322260484Sobrien		&& ((work->constructor & 1) || (work->destructor & 1)));
322360484Sobrien
322433965Sjdp  string_init (&temp);
322560484Sobrien  string_init (&last_name);
322660484Sobrien
322760484Sobrien  if ((*mangled)[0] == 'K')
322833965Sjdp    {
322960484Sobrien    /* Squangling qualified name reuse */
323060484Sobrien      int idx;
323160484Sobrien      (*mangled)++;
323260484Sobrien      idx = consume_count_with_underscores (mangled);
323360484Sobrien      if (idx == -1 || idx >= work -> numk)
323460484Sobrien        success = 0;
323560484Sobrien      else
323660484Sobrien        string_append (&temp, work -> ktypevec[idx]);
323760484Sobrien    }
323860484Sobrien  else
323960484Sobrien    switch ((*mangled)[1])
324060484Sobrien    {
324133965Sjdp    case '_':
324233965Sjdp      /* GNU mangled name with more than 9 classes.  The count is preceded
324333965Sjdp	 by an underscore (to distinguish it from the <= 9 case) and followed
324433965Sjdp	 by an underscore.  */
324560484Sobrien      (*mangled)++;
324660484Sobrien      qualifiers = consume_count_with_underscores (mangled);
324760484Sobrien      if (qualifiers == -1)
324833965Sjdp	success = 0;
324933965Sjdp      break;
325033965Sjdp
325133965Sjdp    case '1':
325233965Sjdp    case '2':
325333965Sjdp    case '3':
325433965Sjdp    case '4':
325533965Sjdp    case '5':
325633965Sjdp    case '6':
325733965Sjdp    case '7':
325833965Sjdp    case '8':
325933965Sjdp    case '9':
326033965Sjdp      /* The count is in a single digit.  */
326133965Sjdp      num[0] = (*mangled)[1];
326233965Sjdp      num[1] = '\0';
326333965Sjdp      qualifiers = atoi (num);
326433965Sjdp
326533965Sjdp      /* If there is an underscore after the digit, skip it.  This is
326633965Sjdp	 said to be for ARM-qualified names, but the ARM makes no
326733965Sjdp	 mention of such an underscore.  Perhaps cfront uses one.  */
326833965Sjdp      if ((*mangled)[2] == '_')
326933965Sjdp	{
327033965Sjdp	  (*mangled)++;
327133965Sjdp	}
327233965Sjdp      (*mangled) += 2;
327333965Sjdp      break;
327433965Sjdp
327533965Sjdp    case '0':
327633965Sjdp    default:
327733965Sjdp      success = 0;
327833965Sjdp    }
327933965Sjdp
328033965Sjdp  if (!success)
328133965Sjdp    return success;
328233965Sjdp
328333965Sjdp  /* Pick off the names and collect them in the temp buffer in the order
328433965Sjdp     in which they are found, separated by '::'.  */
328533965Sjdp
328633965Sjdp  while (qualifiers-- > 0)
328733965Sjdp    {
328860484Sobrien      int remember_K = 1;
328960484Sobrien      string_clear (&last_name);
329060484Sobrien
329160484Sobrien      if (*mangled[0] == '_')
329260484Sobrien	(*mangled)++;
329360484Sobrien
329433965Sjdp      if (*mangled[0] == 't')
329533965Sjdp	{
329660484Sobrien	  /* Here we always append to TEMP since we will want to use
329760484Sobrien	     the template name without the template parameters as a
329860484Sobrien	     constructor or destructor name.  The appropriate
329960484Sobrien	     (parameter-less) value is returned by demangle_template
330060484Sobrien	     in LAST_NAME.  We do not remember the template type here,
330160484Sobrien	     in order to match the G++ mangling algorithm.  */
330260484Sobrien	  success = demangle_template(work, mangled, &temp,
330360484Sobrien				      &last_name, 1, 0);
330460484Sobrien	  if (!success)
330560484Sobrien	    break;
330633965Sjdp	}
330760484Sobrien      else if (*mangled[0] == 'K')
330838889Sjdp	{
330960484Sobrien          int idx;
331060484Sobrien          (*mangled)++;
331160484Sobrien          idx = consume_count_with_underscores (mangled);
331260484Sobrien          if (idx == -1 || idx >= work->numk)
331360484Sobrien            success = 0;
331460484Sobrien          else
331560484Sobrien            string_append (&temp, work->ktypevec[idx]);
331660484Sobrien          remember_K = 0;
331760484Sobrien
331838889Sjdp	  if (!success) break;
331938889Sjdp	}
332033965Sjdp      else
332160484Sobrien	{
332260484Sobrien	  if (EDG_DEMANGLING)
332360484Sobrien            {
332460484Sobrien	      int namelength;
332560484Sobrien 	      /* Now recursively demangle the qualifier
332660484Sobrien 	       * This is necessary to deal with templates in
332760484Sobrien 	       * mangling styles like EDG */
332860484Sobrien	      namelength = consume_count (mangled);
332960484Sobrien	      if (namelength == -1)
333060484Sobrien		{
333160484Sobrien		  success = 0;
333260484Sobrien		  break;
333360484Sobrien		}
333460484Sobrien 	      recursively_demangle(work, mangled, &temp, namelength);
333560484Sobrien            }
333660484Sobrien          else
333760484Sobrien            {
333860484Sobrien              success = do_type (work, mangled, &last_name);
333960484Sobrien              if (!success)
334060484Sobrien                break;
334160484Sobrien              string_appends (&temp, &last_name);
334260484Sobrien            }
334333965Sjdp	}
334460484Sobrien
334560484Sobrien      if (remember_K)
334660484Sobrien	remember_Ktype (work, temp.b, LEN_STRING (&temp));
334760484Sobrien
334833965Sjdp      if (qualifiers > 0)
334960484Sobrien	string_append (&temp, SCOPE_STRING (work));
335033965Sjdp    }
335133965Sjdp
335260484Sobrien  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
335360484Sobrien
335433965Sjdp  /* If we are using the result as a function name, we need to append
335533965Sjdp     the appropriate '::' separated constructor or destructor name.
335633965Sjdp     We do this here because this is the most convenient place, where
335733965Sjdp     we already have a pointer to the name and the length of the name.  */
335833965Sjdp
335960484Sobrien  if (isfuncname)
336033965Sjdp    {
336160484Sobrien      string_append (&temp, SCOPE_STRING (work));
336233965Sjdp      if (work -> destructor & 1)
336360484Sobrien	string_append (&temp, "~");
336460484Sobrien      string_appends (&temp, &last_name);
336533965Sjdp    }
336633965Sjdp
336760484Sobrien  /* Now either prepend the temp buffer to the result, or append it,
336833965Sjdp     depending upon the state of the append flag.  */
336933965Sjdp
337033965Sjdp  if (append)
337160484Sobrien    string_appends (result, &temp);
337233965Sjdp  else
337333965Sjdp    {
337433965Sjdp      if (!STRING_EMPTY (result))
337560484Sobrien	string_append (&temp, SCOPE_STRING (work));
337633965Sjdp      string_prepends (result, &temp);
337733965Sjdp    }
337833965Sjdp
337960484Sobrien  string_delete (&last_name);
338033965Sjdp  string_delete (&temp);
338133965Sjdp  return (success);
338233965Sjdp}
338333965Sjdp
338433965Sjdp/*
338533965Sjdp
338633965SjdpLOCAL FUNCTION
338733965Sjdp
338833965Sjdp	get_count -- convert an ascii count to integer, consuming tokens
338933965Sjdp
339033965SjdpSYNOPSIS
339133965Sjdp
339233965Sjdp	static int
339333965Sjdp	get_count (const char **type, int *count)
339433965Sjdp
339533965SjdpDESCRIPTION
339633965Sjdp
339760484Sobrien	Assume that *type points at a count in a mangled name; set
339860484Sobrien	*count to its value, and set *type to the next character after
339960484Sobrien	the count.  There are some weird rules in effect here.
340060484Sobrien
340160484Sobrien	If *type does not point at a string of digits, return zero.
340260484Sobrien
340360484Sobrien	If *type points at a string of digits followed by an
340460484Sobrien	underscore, set *count to their value as an integer, advance
340560484Sobrien	*type to point *after the underscore, and return 1.
340660484Sobrien
340760484Sobrien	If *type points at a string of digits not followed by an
340860484Sobrien	underscore, consume only the first digit.  Set *count to its
340960484Sobrien	value as an integer, leave *type pointing after that digit,
341060484Sobrien	and return 1.
341160484Sobrien
341260484Sobrien        The excuse for this odd behavior: in the ARM and HP demangling
341360484Sobrien        styles, a type can be followed by a repeat count of the form
341460484Sobrien        `Nxy', where:
341560484Sobrien
341660484Sobrien        `x' is a single digit specifying how many additional copies
341760484Sobrien            of the type to append to the argument list, and
341860484Sobrien
341960484Sobrien        `y' is one or more digits, specifying the zero-based index of
342060484Sobrien            the first repeated argument in the list.  Yes, as you're
342160484Sobrien            unmangling the name you can figure this out yourself, but
342260484Sobrien            it's there anyway.
342360484Sobrien
342460484Sobrien        So, for example, in `bar__3fooFPiN51', the first argument is a
342560484Sobrien        pointer to an integer (`Pi'), and then the next five arguments
342660484Sobrien        are the same (`N5'), and the first repeat is the function's
342760484Sobrien        second argument (`1').
342833965Sjdp*/
342933965Sjdp
343033965Sjdpstatic int
343133965Sjdpget_count (type, count)
343233965Sjdp     const char **type;
343333965Sjdp     int *count;
343433965Sjdp{
343533965Sjdp  const char *p;
343633965Sjdp  int n;
343733965Sjdp
343877298Sobrien  if (!ISDIGIT ((unsigned char)**type))
343960484Sobrien    return (0);
344033965Sjdp  else
344133965Sjdp    {
344233965Sjdp      *count = **type - '0';
344333965Sjdp      (*type)++;
344477298Sobrien      if (ISDIGIT ((unsigned char)**type))
344533965Sjdp	{
344633965Sjdp	  p = *type;
344733965Sjdp	  n = *count;
344860484Sobrien	  do
344933965Sjdp	    {
345033965Sjdp	      n *= 10;
345133965Sjdp	      n += *p - '0';
345233965Sjdp	      p++;
345360484Sobrien	    }
345477298Sobrien	  while (ISDIGIT ((unsigned char)*p));
345533965Sjdp	  if (*p == '_')
345633965Sjdp	    {
345733965Sjdp	      *type = p + 1;
345833965Sjdp	      *count = n;
345933965Sjdp	    }
346033965Sjdp	}
346133965Sjdp    }
346233965Sjdp  return (1);
346333965Sjdp}
346433965Sjdp
346560484Sobrien/* RESULT will be initialised here; it will be freed on failure.  The
346660484Sobrien   value returned is really a type_kind_t.  */
346733965Sjdp
346833965Sjdpstatic int
346933965Sjdpdo_type (work, mangled, result)
347033965Sjdp     struct work_stuff *work;
347133965Sjdp     const char **mangled;
347233965Sjdp     string *result;
347333965Sjdp{
347433965Sjdp  int n;
347533965Sjdp  int done;
347633965Sjdp  int success;
347733965Sjdp  string decl;
347833965Sjdp  const char *remembered_type;
347960484Sobrien  int type_quals;
348060484Sobrien  string btype;
348160484Sobrien  type_kind_t tk = tk_none;
348233965Sjdp
348360484Sobrien  string_init (&btype);
348433965Sjdp  string_init (&decl);
348533965Sjdp  string_init (result);
348633965Sjdp
348733965Sjdp  done = 0;
348833965Sjdp  success = 1;
348933965Sjdp  while (success && !done)
349033965Sjdp    {
349133965Sjdp      int member;
349233965Sjdp      switch (**mangled)
349333965Sjdp	{
349433965Sjdp
349533965Sjdp	  /* A pointer type */
349633965Sjdp	case 'P':
349733965Sjdp	case 'p':
349833965Sjdp	  (*mangled)++;
349938889Sjdp	  if (! (work -> options & DMGL_JAVA))
350038889Sjdp	    string_prepend (&decl, "*");
350160484Sobrien	  if (tk == tk_none)
350260484Sobrien	    tk = tk_pointer;
350333965Sjdp	  break;
350433965Sjdp
350533965Sjdp	  /* A reference type */
350633965Sjdp	case 'R':
350733965Sjdp	  (*mangled)++;
350833965Sjdp	  string_prepend (&decl, "&");
350960484Sobrien	  if (tk == tk_none)
351060484Sobrien	    tk = tk_reference;
351133965Sjdp	  break;
351233965Sjdp
351333965Sjdp	  /* An array */
351433965Sjdp	case 'A':
351533965Sjdp	  {
351660484Sobrien	    ++(*mangled);
351760484Sobrien	    if (!STRING_EMPTY (&decl)
351860484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
351933965Sjdp	      {
352060484Sobrien		string_prepend (&decl, "(");
352160484Sobrien		string_append (&decl, ")");
352233965Sjdp	      }
352360484Sobrien	    string_append (&decl, "[");
352460484Sobrien	    if (**mangled != '_')
352560484Sobrien	      success = demangle_template_value_parm (work, mangled, &decl,
352660484Sobrien						      tk_integral);
352760484Sobrien	    if (**mangled == '_')
352860484Sobrien	      ++(*mangled);
352960484Sobrien	    string_append (&decl, "]");
353033965Sjdp	    break;
353133965Sjdp	  }
353233965Sjdp
353333965Sjdp	/* A back reference to a previously seen type */
353433965Sjdp	case 'T':
353533965Sjdp	  (*mangled)++;
353633965Sjdp	  if (!get_count (mangled, &n) || n >= work -> ntypes)
353733965Sjdp	    {
353833965Sjdp	      success = 0;
353933965Sjdp	    }
354033965Sjdp	  else
354133965Sjdp	    {
354233965Sjdp	      remembered_type = work -> typevec[n];
354333965Sjdp	      mangled = &remembered_type;
354433965Sjdp	    }
354533965Sjdp	  break;
354633965Sjdp
354733965Sjdp	  /* A function */
354833965Sjdp	case 'F':
354933965Sjdp	  (*mangled)++;
355060484Sobrien	    if (!STRING_EMPTY (&decl)
355160484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
355233965Sjdp	    {
355333965Sjdp	      string_prepend (&decl, "(");
355433965Sjdp	      string_append (&decl, ")");
355533965Sjdp	    }
355633965Sjdp	  /* After picking off the function args, we expect to either find the
355733965Sjdp	     function return type (preceded by an '_') or the end of the
355833965Sjdp	     string.  */
355960484Sobrien	  if (!demangle_nested_args (work, mangled, &decl)
356033965Sjdp	      || (**mangled != '_' && **mangled != '\0'))
356133965Sjdp	    {
356233965Sjdp	      success = 0;
356360484Sobrien	      break;
356433965Sjdp	    }
356533965Sjdp	  if (success && (**mangled == '_'))
356660484Sobrien	    (*mangled)++;
356733965Sjdp	  break;
356833965Sjdp
356933965Sjdp	case 'M':
357033965Sjdp	case 'O':
357133965Sjdp	  {
357260484Sobrien	    type_quals = TYPE_UNQUALIFIED;
357333965Sjdp
357433965Sjdp	    member = **mangled == 'M';
357533965Sjdp	    (*mangled)++;
357633965Sjdp
357733965Sjdp	    string_append (&decl, ")");
357860484Sobrien
357960484Sobrien	    /* We don't need to prepend `::' for a qualified name;
358060484Sobrien	       demangle_qualified will do that for us.  */
358160484Sobrien	    if (**mangled != 'Q')
358260484Sobrien	      string_prepend (&decl, SCOPE_STRING (work));
358360484Sobrien
358477298Sobrien	    if (ISDIGIT ((unsigned char)**mangled))
358533965Sjdp	      {
358633965Sjdp		n = consume_count (mangled);
358760484Sobrien		if (n == -1
358860484Sobrien		    || (int) strlen (*mangled) < n)
358933965Sjdp		  {
359033965Sjdp		    success = 0;
359133965Sjdp		    break;
359233965Sjdp		  }
359333965Sjdp		string_prependn (&decl, *mangled, n);
359433965Sjdp		*mangled += n;
359533965Sjdp	      }
359660484Sobrien	    else if (**mangled == 'X' || **mangled == 'Y')
359733965Sjdp	      {
359833965Sjdp		string temp;
359960484Sobrien		do_type (work, mangled, &temp);
360060484Sobrien		string_prepends (&decl, &temp);
360160484Sobrien	      }
360260484Sobrien	    else if (**mangled == 't')
360360484Sobrien	      {
360460484Sobrien		string temp;
360533965Sjdp		string_init (&temp);
360660484Sobrien		success = demangle_template (work, mangled, &temp,
360760484Sobrien					     NULL, 1, 1);
360833965Sjdp		if (success)
360933965Sjdp		  {
361033965Sjdp		    string_prependn (&decl, temp.b, temp.p - temp.b);
361133965Sjdp		    string_clear (&temp);
361233965Sjdp		  }
361333965Sjdp		else
361433965Sjdp		  break;
361533965Sjdp	      }
361660484Sobrien	    else if (**mangled == 'Q')
361760484Sobrien	      {
361860484Sobrien		success = demangle_qualified (work, mangled, &decl,
361960484Sobrien					      /*isfuncnam=*/0,
362060484Sobrien					      /*append=*/0);
362160484Sobrien		if (!success)
362260484Sobrien		  break;
362360484Sobrien	      }
362460484Sobrien	    else
362560484Sobrien	      {
362660484Sobrien		success = 0;
362760484Sobrien		break;
362860484Sobrien	      }
362960484Sobrien
363033965Sjdp	    string_prepend (&decl, "(");
363133965Sjdp	    if (member)
363233965Sjdp	      {
363360484Sobrien		switch (**mangled)
363433965Sjdp		  {
363560484Sobrien		  case 'C':
363660484Sobrien		  case 'V':
363760484Sobrien		  case 'u':
363860484Sobrien		    type_quals |= code_for_qualifier (**mangled);
363933965Sjdp		    (*mangled)++;
364060484Sobrien		    break;
364160484Sobrien
364260484Sobrien		  default:
364360484Sobrien		    break;
364433965Sjdp		  }
364560484Sobrien
364633965Sjdp		if (*(*mangled)++ != 'F')
364733965Sjdp		  {
364833965Sjdp		    success = 0;
364933965Sjdp		    break;
365033965Sjdp		  }
365133965Sjdp	      }
365260484Sobrien	    if ((member && !demangle_nested_args (work, mangled, &decl))
365333965Sjdp		|| **mangled != '_')
365433965Sjdp	      {
365533965Sjdp		success = 0;
365633965Sjdp		break;
365733965Sjdp	      }
365833965Sjdp	    (*mangled)++;
365933965Sjdp	    if (! PRINT_ANSI_QUALIFIERS)
366033965Sjdp	      {
366133965Sjdp		break;
366233965Sjdp	      }
366360484Sobrien	    if (type_quals != TYPE_UNQUALIFIED)
366433965Sjdp	      {
366533965Sjdp		APPEND_BLANK (&decl);
366660484Sobrien		string_append (&decl, qualifier_string (type_quals));
366733965Sjdp	      }
366833965Sjdp	    break;
366933965Sjdp	  }
367033965Sjdp        case 'G':
367133965Sjdp	  (*mangled)++;
367233965Sjdp	  break;
367333965Sjdp
367433965Sjdp	case 'C':
367560484Sobrien	case 'V':
367660484Sobrien	case 'u':
367733965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
367833965Sjdp	    {
367933965Sjdp	      if (!STRING_EMPTY (&decl))
368060484Sobrien		string_prepend (&decl, " ");
368160484Sobrien
368260484Sobrien	      string_prepend (&decl, demangle_qualifier (**mangled));
368333965Sjdp	    }
368460484Sobrien	  (*mangled)++;
368533965Sjdp	  break;
368633965Sjdp	  /*
368733965Sjdp	    }
368833965Sjdp	    */
368933965Sjdp
369033965Sjdp	  /* fall through */
369133965Sjdp	default:
369233965Sjdp	  done = 1;
369333965Sjdp	  break;
369433965Sjdp	}
369533965Sjdp    }
369633965Sjdp
369760484Sobrien  if (success) switch (**mangled)
369833965Sjdp    {
369933965Sjdp      /* A qualified name, such as "Outer::Inner".  */
370033965Sjdp    case 'Q':
370160484Sobrien    case 'K':
370260484Sobrien      {
370360484Sobrien        success = demangle_qualified (work, mangled, result, 0, 1);
370460484Sobrien        break;
370560484Sobrien      }
370660484Sobrien
370760484Sobrien    /* A back reference to a previously seen squangled type */
370860484Sobrien    case 'B':
370960484Sobrien      (*mangled)++;
371060484Sobrien      if (!get_count (mangled, &n) || n >= work -> numb)
371160484Sobrien	success = 0;
371260484Sobrien      else
371360484Sobrien	string_append (result, work->btypevec[n]);
371433965Sjdp      break;
371533965Sjdp
371638889Sjdp    case 'X':
371738889Sjdp    case 'Y':
371838889Sjdp      /* A template parm.  We substitute the corresponding argument. */
371938889Sjdp      {
372038889Sjdp	int idx;
372138889Sjdp
372238889Sjdp	(*mangled)++;
372338889Sjdp	idx = consume_count_with_underscores (mangled);
372438889Sjdp
372560484Sobrien	if (idx == -1
372638889Sjdp	    || (work->tmpl_argvec && idx >= work->ntmpl_args)
372738889Sjdp	    || consume_count_with_underscores (mangled) == -1)
372838889Sjdp	  {
372938889Sjdp	    success = 0;
373038889Sjdp	    break;
373138889Sjdp	  }
373238889Sjdp
373338889Sjdp	if (work->tmpl_argvec)
373438889Sjdp	  string_append (result, work->tmpl_argvec[idx]);
373538889Sjdp	else
373660484Sobrien	  string_append_template_idx (result, idx);
373738889Sjdp
373838889Sjdp	success = 1;
373938889Sjdp      }
374038889Sjdp    break;
374138889Sjdp
374233965Sjdp    default:
374333965Sjdp      success = demangle_fund_type (work, mangled, result);
374460484Sobrien      if (tk == tk_none)
374560484Sobrien	tk = (type_kind_t) success;
374633965Sjdp      break;
374733965Sjdp    }
374833965Sjdp
374933965Sjdp  if (success)
375033965Sjdp    {
375133965Sjdp      if (!STRING_EMPTY (&decl))
375233965Sjdp	{
375333965Sjdp	  string_append (result, " ");
375433965Sjdp	  string_appends (result, &decl);
375533965Sjdp	}
375633965Sjdp    }
375733965Sjdp  else
375860484Sobrien    string_delete (result);
375933965Sjdp  string_delete (&decl);
376060484Sobrien
376160484Sobrien  if (success)
376260484Sobrien    /* Assume an integral type, if we're not sure.  */
376360484Sobrien    return (int) ((tk == tk_none) ? tk_integral : tk);
376460484Sobrien  else
376560484Sobrien    return 0;
376633965Sjdp}
376733965Sjdp
376833965Sjdp/* Given a pointer to a type string that represents a fundamental type
376933965Sjdp   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
377033965Sjdp   string in which the demangled output is being built in RESULT, and
377133965Sjdp   the WORK structure, decode the types and add them to the result.
377233965Sjdp
377333965Sjdp   For example:
377433965Sjdp
377533965Sjdp   	"Ci"	=>	"const int"
377633965Sjdp	"Sl"	=>	"signed long"
377733965Sjdp	"CUs"	=>	"const unsigned short"
377833965Sjdp
377960484Sobrien   The value returned is really a type_kind_t.  */
378033965Sjdp
378133965Sjdpstatic int
378233965Sjdpdemangle_fund_type (work, mangled, result)
378333965Sjdp     struct work_stuff *work;
378433965Sjdp     const char **mangled;
378533965Sjdp     string *result;
378633965Sjdp{
378733965Sjdp  int done = 0;
378833965Sjdp  int success = 1;
378960484Sobrien  char buf[10];
379068765Sobrien  unsigned int dec = 0;
379160484Sobrien  string btype;
379260484Sobrien  type_kind_t tk = tk_integral;
379333965Sjdp
379460484Sobrien  string_init (&btype);
379560484Sobrien
379633965Sjdp  /* First pick off any type qualifiers.  There can be more than one.  */
379733965Sjdp
379833965Sjdp  while (!done)
379933965Sjdp    {
380033965Sjdp      switch (**mangled)
380133965Sjdp	{
380233965Sjdp	case 'C':
380360484Sobrien	case 'V':
380460484Sobrien	case 'u':
380533965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
380633965Sjdp	    {
380760484Sobrien              if (!STRING_EMPTY (result))
380860484Sobrien                string_prepend (result, " ");
380960484Sobrien	      string_prepend (result, demangle_qualifier (**mangled));
381033965Sjdp	    }
381160484Sobrien	  (*mangled)++;
381233965Sjdp	  break;
381333965Sjdp	case 'U':
381433965Sjdp	  (*mangled)++;
381533965Sjdp	  APPEND_BLANK (result);
381633965Sjdp	  string_append (result, "unsigned");
381733965Sjdp	  break;
381833965Sjdp	case 'S': /* signed char only */
381933965Sjdp	  (*mangled)++;
382033965Sjdp	  APPEND_BLANK (result);
382133965Sjdp	  string_append (result, "signed");
382233965Sjdp	  break;
382338889Sjdp	case 'J':
382438889Sjdp	  (*mangled)++;
382538889Sjdp	  APPEND_BLANK (result);
382638889Sjdp	  string_append (result, "__complex");
382738889Sjdp	  break;
382833965Sjdp	default:
382933965Sjdp	  done = 1;
383033965Sjdp	  break;
383133965Sjdp	}
383233965Sjdp    }
383333965Sjdp
383433965Sjdp  /* Now pick off the fundamental type.  There can be only one.  */
383533965Sjdp
383633965Sjdp  switch (**mangled)
383733965Sjdp    {
383833965Sjdp    case '\0':
383933965Sjdp    case '_':
384033965Sjdp      break;
384133965Sjdp    case 'v':
384233965Sjdp      (*mangled)++;
384333965Sjdp      APPEND_BLANK (result);
384433965Sjdp      string_append (result, "void");
384533965Sjdp      break;
384633965Sjdp    case 'x':
384733965Sjdp      (*mangled)++;
384833965Sjdp      APPEND_BLANK (result);
384933965Sjdp      string_append (result, "long long");
385033965Sjdp      break;
385133965Sjdp    case 'l':
385233965Sjdp      (*mangled)++;
385333965Sjdp      APPEND_BLANK (result);
385433965Sjdp      string_append (result, "long");
385533965Sjdp      break;
385633965Sjdp    case 'i':
385733965Sjdp      (*mangled)++;
385833965Sjdp      APPEND_BLANK (result);
385933965Sjdp      string_append (result, "int");
386033965Sjdp      break;
386133965Sjdp    case 's':
386233965Sjdp      (*mangled)++;
386333965Sjdp      APPEND_BLANK (result);
386433965Sjdp      string_append (result, "short");
386533965Sjdp      break;
386633965Sjdp    case 'b':
386733965Sjdp      (*mangled)++;
386833965Sjdp      APPEND_BLANK (result);
386933965Sjdp      string_append (result, "bool");
387060484Sobrien      tk = tk_bool;
387133965Sjdp      break;
387233965Sjdp    case 'c':
387333965Sjdp      (*mangled)++;
387433965Sjdp      APPEND_BLANK (result);
387533965Sjdp      string_append (result, "char");
387660484Sobrien      tk = tk_char;
387733965Sjdp      break;
387833965Sjdp    case 'w':
387933965Sjdp      (*mangled)++;
388033965Sjdp      APPEND_BLANK (result);
388133965Sjdp      string_append (result, "wchar_t");
388260484Sobrien      tk = tk_char;
388333965Sjdp      break;
388433965Sjdp    case 'r':
388533965Sjdp      (*mangled)++;
388633965Sjdp      APPEND_BLANK (result);
388733965Sjdp      string_append (result, "long double");
388860484Sobrien      tk = tk_real;
388933965Sjdp      break;
389033965Sjdp    case 'd':
389133965Sjdp      (*mangled)++;
389233965Sjdp      APPEND_BLANK (result);
389333965Sjdp      string_append (result, "double");
389460484Sobrien      tk = tk_real;
389533965Sjdp      break;
389633965Sjdp    case 'f':
389733965Sjdp      (*mangled)++;
389833965Sjdp      APPEND_BLANK (result);
389933965Sjdp      string_append (result, "float");
390060484Sobrien      tk = tk_real;
390133965Sjdp      break;
390233965Sjdp    case 'G':
390333965Sjdp      (*mangled)++;
390477298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
390533965Sjdp	{
390633965Sjdp	  success = 0;
390733965Sjdp	  break;
390833965Sjdp	}
390960484Sobrien    case 'I':
391060484Sobrien      (*mangled)++;
391160484Sobrien      if (**mangled == '_')
391260484Sobrien	{
391360484Sobrien	  int i;
391460484Sobrien	  (*mangled)++;
391560484Sobrien	  for (i = 0;
391660484Sobrien	       i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
391760484Sobrien	       (*mangled)++, i++)
391860484Sobrien	    buf[i] = **mangled;
391960484Sobrien	  if (**mangled != '_')
392060484Sobrien	    {
392160484Sobrien	      success = 0;
392260484Sobrien	      break;
392360484Sobrien	    }
392460484Sobrien	  buf[i] = '\0';
392560484Sobrien	  (*mangled)++;
392660484Sobrien	}
392760484Sobrien      else
392860484Sobrien	{
392960484Sobrien	  strncpy (buf, *mangled, 2);
393060484Sobrien	  buf[2] = '\0';
393160484Sobrien	  *mangled += min (strlen (*mangled), 2);
393260484Sobrien	}
393360484Sobrien      sscanf (buf, "%x", &dec);
393468765Sobrien      sprintf (buf, "int%u_t", dec);
393560484Sobrien      APPEND_BLANK (result);
393660484Sobrien      string_append (result, buf);
393760484Sobrien      break;
393860484Sobrien
393933965Sjdp      /* fall through */
394033965Sjdp      /* An explicit type, such as "6mytype" or "7integer" */
394133965Sjdp    case '0':
394233965Sjdp    case '1':
394333965Sjdp    case '2':
394433965Sjdp    case '3':
394533965Sjdp    case '4':
394633965Sjdp    case '5':
394733965Sjdp    case '6':
394833965Sjdp    case '7':
394933965Sjdp    case '8':
395033965Sjdp    case '9':
395160484Sobrien      {
395260484Sobrien        int bindex = register_Btype (work);
395360484Sobrien        string btype;
395460484Sobrien        string_init (&btype);
395560484Sobrien        if (demangle_class_name (work, mangled, &btype)) {
395660484Sobrien          remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
395760484Sobrien          APPEND_BLANK (result);
395860484Sobrien          string_appends (result, &btype);
395960484Sobrien        }
396060484Sobrien        else
396160484Sobrien          success = 0;
396260484Sobrien        string_delete (&btype);
396360484Sobrien        break;
396433965Sjdp      }
396533965Sjdp    case 't':
396660484Sobrien      {
396760484Sobrien        success = demangle_template (work, mangled, &btype, 0, 1, 1);
396860484Sobrien        string_appends (result, &btype);
396960484Sobrien        break;
397060484Sobrien      }
397133965Sjdp    default:
397233965Sjdp      success = 0;
397333965Sjdp      break;
397433965Sjdp    }
397533965Sjdp
397660484Sobrien  return success ? ((int) tk) : 0;
397733965Sjdp}
397833965Sjdp
397933965Sjdp
398060484Sobrien/* Handle a template's value parameter for HP aCC (extension from ARM)
398160484Sobrien   **mangled points to 'S' or 'U' */
398260484Sobrien
398333965Sjdpstatic int
398460484Sobriendo_hpacc_template_const_value (work, mangled, result)
398560484Sobrien     struct work_stuff *work ATTRIBUTE_UNUSED;
398660484Sobrien     const char **mangled;
398760484Sobrien     string *result;
398860484Sobrien{
398960484Sobrien  int unsigned_const;
399060484Sobrien
399160484Sobrien  if (**mangled != 'U' && **mangled != 'S')
399260484Sobrien    return 0;
399360484Sobrien
399460484Sobrien  unsigned_const = (**mangled == 'U');
399560484Sobrien
399660484Sobrien  (*mangled)++;
399760484Sobrien
399860484Sobrien  switch (**mangled)
399960484Sobrien    {
400060484Sobrien      case 'N':
400160484Sobrien        string_append (result, "-");
400260484Sobrien        /* fall through */
400360484Sobrien      case 'P':
400460484Sobrien        (*mangled)++;
400560484Sobrien        break;
400660484Sobrien      case 'M':
400760484Sobrien        /* special case for -2^31 */
400860484Sobrien        string_append (result, "-2147483648");
400960484Sobrien        (*mangled)++;
401060484Sobrien        return 1;
401160484Sobrien      default:
401260484Sobrien        return 0;
401360484Sobrien    }
401460484Sobrien
401560484Sobrien  /* We have to be looking at an integer now */
401677298Sobrien  if (!(ISDIGIT ((unsigned char)**mangled)))
401760484Sobrien    return 0;
401860484Sobrien
401960484Sobrien  /* We only deal with integral values for template
402060484Sobrien     parameters -- so it's OK to look only for digits */
402177298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
402260484Sobrien    {
402360484Sobrien      char_str[0] = **mangled;
402460484Sobrien      string_append (result, char_str);
402560484Sobrien      (*mangled)++;
402660484Sobrien    }
402760484Sobrien
402860484Sobrien  if (unsigned_const)
402960484Sobrien    string_append (result, "U");
403060484Sobrien
403160484Sobrien  /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
403260484Sobrien     with L or LL suffixes. pai/1997-09-03 */
403360484Sobrien
403460484Sobrien  return 1; /* success */
403560484Sobrien}
403660484Sobrien
403760484Sobrien/* Handle a template's literal parameter for HP aCC (extension from ARM)
403860484Sobrien   **mangled is pointing to the 'A' */
403960484Sobrien
404060484Sobrienstatic int
404160484Sobriendo_hpacc_template_literal (work, mangled, result)
404260484Sobrien     struct work_stuff *work;
404360484Sobrien     const char **mangled;
404460484Sobrien     string *result;
404560484Sobrien{
404660484Sobrien  int literal_len = 0;
404760484Sobrien  char * recurse;
404860484Sobrien  char * recurse_dem;
404960484Sobrien
405060484Sobrien  if (**mangled != 'A')
405160484Sobrien    return 0;
405260484Sobrien
405360484Sobrien  (*mangled)++;
405460484Sobrien
405560484Sobrien  literal_len = consume_count (mangled);
405660484Sobrien
405760484Sobrien  if (literal_len <= 0)
405860484Sobrien    return 0;
405960484Sobrien
406060484Sobrien  /* Literal parameters are names of arrays, functions, etc.  and the
406160484Sobrien     canonical representation uses the address operator */
406260484Sobrien  string_append (result, "&");
406360484Sobrien
406460484Sobrien  /* Now recursively demangle the literal name */
406560484Sobrien  recurse = (char *) xmalloc (literal_len + 1);
406660484Sobrien  memcpy (recurse, *mangled, literal_len);
406760484Sobrien  recurse[literal_len] = '\000';
406860484Sobrien
406960484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
407060484Sobrien
407160484Sobrien  if (recurse_dem)
407260484Sobrien    {
407360484Sobrien      string_append (result, recurse_dem);
407460484Sobrien      free (recurse_dem);
407560484Sobrien    }
407660484Sobrien  else
407760484Sobrien    {
407860484Sobrien      string_appendn (result, *mangled, literal_len);
407960484Sobrien    }
408060484Sobrien  (*mangled) += literal_len;
408160484Sobrien  free (recurse);
408260484Sobrien
408360484Sobrien  return 1;
408460484Sobrien}
408560484Sobrien
408660484Sobrienstatic int
408760484Sobriensnarf_numeric_literal (args, arg)
408860484Sobrien     const char ** args;
408960484Sobrien     string * arg;
409060484Sobrien{
409160484Sobrien  if (**args == '-')
409260484Sobrien    {
409360484Sobrien      char_str[0] = '-';
409460484Sobrien      string_append (arg, char_str);
409560484Sobrien      (*args)++;
409660484Sobrien    }
409760484Sobrien  else if (**args == '+')
409860484Sobrien    (*args)++;
409960484Sobrien
410077298Sobrien  if (!ISDIGIT ((unsigned char)**args))
410160484Sobrien    return 0;
410260484Sobrien
410377298Sobrien  while (ISDIGIT ((unsigned char)**args))
410460484Sobrien    {
410560484Sobrien      char_str[0] = **args;
410660484Sobrien      string_append (arg, char_str);
410760484Sobrien      (*args)++;
410860484Sobrien    }
410960484Sobrien
411060484Sobrien  return 1;
411160484Sobrien}
411260484Sobrien
411360484Sobrien/* Demangle the next argument, given by MANGLED into RESULT, which
411460484Sobrien   *should be an uninitialized* string.  It will be initialized here,
411560484Sobrien   and free'd should anything go wrong.  */
411660484Sobrien
411760484Sobrienstatic int
411833965Sjdpdo_arg (work, mangled, result)
411933965Sjdp     struct work_stuff *work;
412033965Sjdp     const char **mangled;
412133965Sjdp     string *result;
412233965Sjdp{
412360484Sobrien  /* Remember where we started so that we can record the type, for
412460484Sobrien     non-squangling type remembering.  */
412533965Sjdp  const char *start = *mangled;
412633965Sjdp
412760484Sobrien  string_init (result);
412860484Sobrien
412960484Sobrien  if (work->nrepeats > 0)
413033965Sjdp    {
413160484Sobrien      --work->nrepeats;
413260484Sobrien
413360484Sobrien      if (work->previous_argument == 0)
413460484Sobrien	return 0;
413560484Sobrien
413660484Sobrien      /* We want to reissue the previous type in this argument list.  */
413760484Sobrien      string_appends (result, work->previous_argument);
413860484Sobrien      return 1;
413933965Sjdp    }
414060484Sobrien
414160484Sobrien  if (**mangled == 'n')
414260484Sobrien    {
414360484Sobrien      /* A squangling-style repeat.  */
414460484Sobrien      (*mangled)++;
414560484Sobrien      work->nrepeats = consume_count(mangled);
414660484Sobrien
414760484Sobrien      if (work->nrepeats <= 0)
414860484Sobrien	/* This was not a repeat count after all.  */
414960484Sobrien	return 0;
415060484Sobrien
415160484Sobrien      if (work->nrepeats > 9)
415260484Sobrien	{
415360484Sobrien	  if (**mangled != '_')
415460484Sobrien	    /* The repeat count should be followed by an '_' in this
415560484Sobrien	       case.  */
415660484Sobrien	    return 0;
415760484Sobrien	  else
415860484Sobrien	    (*mangled)++;
415960484Sobrien	}
416060484Sobrien
416160484Sobrien      /* Now, the repeat is all set up.  */
416260484Sobrien      return do_arg (work, mangled, result);
416360484Sobrien    }
416460484Sobrien
416560484Sobrien  /* Save the result in WORK->previous_argument so that we can find it
416660484Sobrien     if it's repeated.  Note that saving START is not good enough: we
416760484Sobrien     do not want to add additional types to the back-referenceable
416860484Sobrien     type vector when processing a repeated type.  */
416960484Sobrien  if (work->previous_argument)
417060484Sobrien    string_clear (work->previous_argument);
417133965Sjdp  else
417233965Sjdp    {
417360484Sobrien      work->previous_argument = (string*) xmalloc (sizeof (string));
417460484Sobrien      string_init (work->previous_argument);
417533965Sjdp    }
417660484Sobrien
417760484Sobrien  if (!do_type (work, mangled, work->previous_argument))
417860484Sobrien    return 0;
417960484Sobrien
418060484Sobrien  string_appends (result, work->previous_argument);
418160484Sobrien
418260484Sobrien  remember_type (work, start, *mangled - start);
418360484Sobrien  return 1;
418433965Sjdp}
418533965Sjdp
418633965Sjdpstatic void
418733965Sjdpremember_type (work, start, len)
418833965Sjdp     struct work_stuff *work;
418933965Sjdp     const char *start;
419033965Sjdp     int len;
419133965Sjdp{
419233965Sjdp  char *tem;
419333965Sjdp
419460484Sobrien  if (work->forgetting_types)
419560484Sobrien    return;
419660484Sobrien
419733965Sjdp  if (work -> ntypes >= work -> typevec_size)
419833965Sjdp    {
419933965Sjdp      if (work -> typevec_size == 0)
420033965Sjdp	{
420133965Sjdp	  work -> typevec_size = 3;
420238889Sjdp	  work -> typevec
420338889Sjdp	    = (char **) xmalloc (sizeof (char *) * work -> typevec_size);
420433965Sjdp	}
420533965Sjdp      else
420633965Sjdp	{
420733965Sjdp	  work -> typevec_size *= 2;
420838889Sjdp	  work -> typevec
420938889Sjdp	    = (char **) xrealloc ((char *)work -> typevec,
421038889Sjdp				  sizeof (char *) * work -> typevec_size);
421133965Sjdp	}
421233965Sjdp    }
421333965Sjdp  tem = xmalloc (len + 1);
421433965Sjdp  memcpy (tem, start, len);
421533965Sjdp  tem[len] = '\0';
421633965Sjdp  work -> typevec[work -> ntypes++] = tem;
421733965Sjdp}
421833965Sjdp
421960484Sobrien
422060484Sobrien/* Remember a K type class qualifier. */
422160484Sobrienstatic void
422260484Sobrienremember_Ktype (work, start, len)
422360484Sobrien     struct work_stuff *work;
422460484Sobrien     const char *start;
422560484Sobrien     int len;
422660484Sobrien{
422760484Sobrien  char *tem;
422860484Sobrien
422960484Sobrien  if (work -> numk >= work -> ksize)
423060484Sobrien    {
423160484Sobrien      if (work -> ksize == 0)
423260484Sobrien	{
423360484Sobrien	  work -> ksize = 5;
423460484Sobrien	  work -> ktypevec
423560484Sobrien	    = (char **) xmalloc (sizeof (char *) * work -> ksize);
423660484Sobrien	}
423760484Sobrien      else
423860484Sobrien	{
423960484Sobrien	  work -> ksize *= 2;
424060484Sobrien	  work -> ktypevec
424160484Sobrien	    = (char **) xrealloc ((char *)work -> ktypevec,
424260484Sobrien				  sizeof (char *) * work -> ksize);
424360484Sobrien	}
424460484Sobrien    }
424560484Sobrien  tem = xmalloc (len + 1);
424660484Sobrien  memcpy (tem, start, len);
424760484Sobrien  tem[len] = '\0';
424860484Sobrien  work -> ktypevec[work -> numk++] = tem;
424960484Sobrien}
425060484Sobrien
425160484Sobrien/* Register a B code, and get an index for it. B codes are registered
425260484Sobrien   as they are seen, rather than as they are completed, so map<temp<char> >
425360484Sobrien   registers map<temp<char> > as B0, and temp<char> as B1 */
425460484Sobrien
425560484Sobrienstatic int
425660484Sobrienregister_Btype (work)
425760484Sobrien     struct work_stuff *work;
425860484Sobrien{
425960484Sobrien  int ret;
426060484Sobrien
426160484Sobrien  if (work -> numb >= work -> bsize)
426260484Sobrien    {
426360484Sobrien      if (work -> bsize == 0)
426460484Sobrien	{
426560484Sobrien	  work -> bsize = 5;
426660484Sobrien	  work -> btypevec
426760484Sobrien	    = (char **) xmalloc (sizeof (char *) * work -> bsize);
426860484Sobrien	}
426960484Sobrien      else
427060484Sobrien	{
427160484Sobrien	  work -> bsize *= 2;
427260484Sobrien	  work -> btypevec
427360484Sobrien	    = (char **) xrealloc ((char *)work -> btypevec,
427460484Sobrien				  sizeof (char *) * work -> bsize);
427560484Sobrien	}
427660484Sobrien    }
427760484Sobrien  ret = work -> numb++;
427860484Sobrien  work -> btypevec[ret] = NULL;
427960484Sobrien  return(ret);
428060484Sobrien}
428160484Sobrien
428260484Sobrien/* Store a value into a previously registered B code type. */
428360484Sobrien
428460484Sobrienstatic void
428560484Sobrienremember_Btype (work, start, len, index)
428660484Sobrien     struct work_stuff *work;
428760484Sobrien     const char *start;
428860484Sobrien     int len, index;
428960484Sobrien{
429060484Sobrien  char *tem;
429160484Sobrien
429260484Sobrien  tem = xmalloc (len + 1);
429360484Sobrien  memcpy (tem, start, len);
429460484Sobrien  tem[len] = '\0';
429560484Sobrien  work -> btypevec[index] = tem;
429660484Sobrien}
429760484Sobrien
429860484Sobrien/* Lose all the info related to B and K type codes. */
429960484Sobrienstatic void
430060484Sobrienforget_B_and_K_types (work)
430160484Sobrien     struct work_stuff *work;
430260484Sobrien{
430360484Sobrien  int i;
430460484Sobrien
430560484Sobrien  while (work -> numk > 0)
430660484Sobrien    {
430760484Sobrien      i = --(work -> numk);
430860484Sobrien      if (work -> ktypevec[i] != NULL)
430960484Sobrien	{
431060484Sobrien	  free (work -> ktypevec[i]);
431160484Sobrien	  work -> ktypevec[i] = NULL;
431260484Sobrien	}
431360484Sobrien    }
431460484Sobrien
431560484Sobrien  while (work -> numb > 0)
431660484Sobrien    {
431760484Sobrien      i = --(work -> numb);
431860484Sobrien      if (work -> btypevec[i] != NULL)
431960484Sobrien	{
432060484Sobrien	  free (work -> btypevec[i]);
432160484Sobrien	  work -> btypevec[i] = NULL;
432260484Sobrien	}
432360484Sobrien    }
432460484Sobrien}
432533965Sjdp/* Forget the remembered types, but not the type vector itself.  */
432633965Sjdp
432733965Sjdpstatic void
432833965Sjdpforget_types (work)
432933965Sjdp     struct work_stuff *work;
433033965Sjdp{
433133965Sjdp  int i;
433233965Sjdp
433333965Sjdp  while (work -> ntypes > 0)
433433965Sjdp    {
433533965Sjdp      i = --(work -> ntypes);
433633965Sjdp      if (work -> typevec[i] != NULL)
433733965Sjdp	{
433833965Sjdp	  free (work -> typevec[i]);
433933965Sjdp	  work -> typevec[i] = NULL;
434033965Sjdp	}
434133965Sjdp    }
434233965Sjdp}
434333965Sjdp
434433965Sjdp/* Process the argument list part of the signature, after any class spec
434533965Sjdp   has been consumed, as well as the first 'F' character (if any).  For
434633965Sjdp   example:
434733965Sjdp
434833965Sjdp   "__als__3fooRT0"		=>	process "RT0"
434933965Sjdp   "complexfunc5__FPFPc_PFl_i"	=>	process "PFPc_PFl_i"
435033965Sjdp
435133965Sjdp   DECLP must be already initialised, usually non-empty.  It won't be freed
435233965Sjdp   on failure.
435333965Sjdp
435433965Sjdp   Note that g++ differs significantly from ARM and lucid style mangling
435533965Sjdp   with regards to references to previously seen types.  For example, given
435633965Sjdp   the source fragment:
435733965Sjdp
435833965Sjdp     class foo {
435933965Sjdp       public:
436033965Sjdp       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
436133965Sjdp     };
436233965Sjdp
436333965Sjdp     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
436433965Sjdp     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
436533965Sjdp
436633965Sjdp   g++ produces the names:
436733965Sjdp
436833965Sjdp     __3fooiRT0iT2iT2
436933965Sjdp     foo__FiR3fooiT1iT1
437033965Sjdp
437133965Sjdp   while lcc (and presumably other ARM style compilers as well) produces:
437233965Sjdp
437333965Sjdp     foo__FiR3fooT1T2T1T2
437433965Sjdp     __ct__3fooFiR3fooT1T2T1T2
437533965Sjdp
437660484Sobrien   Note that g++ bases its type numbers starting at zero and counts all
437760484Sobrien   previously seen types, while lucid/ARM bases its type numbers starting
437833965Sjdp   at one and only considers types after it has seen the 'F' character
437933965Sjdp   indicating the start of the function args.  For lucid/ARM style, we
438033965Sjdp   account for this difference by discarding any previously seen types when
438133965Sjdp   we see the 'F' character, and subtracting one from the type number
438233965Sjdp   reference.
438333965Sjdp
438433965Sjdp */
438533965Sjdp
438633965Sjdpstatic int
438733965Sjdpdemangle_args (work, mangled, declp)
438833965Sjdp     struct work_stuff *work;
438933965Sjdp     const char **mangled;
439033965Sjdp     string *declp;
439133965Sjdp{
439233965Sjdp  string arg;
439333965Sjdp  int need_comma = 0;
439433965Sjdp  int r;
439533965Sjdp  int t;
439633965Sjdp  const char *tem;
439733965Sjdp  char temptype;
439833965Sjdp
439933965Sjdp  if (PRINT_ARG_TYPES)
440033965Sjdp    {
440133965Sjdp      string_append (declp, "(");
440233965Sjdp      if (**mangled == '\0')
440333965Sjdp	{
440433965Sjdp	  string_append (declp, "void");
440533965Sjdp	}
440633965Sjdp    }
440733965Sjdp
440860484Sobrien  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
440960484Sobrien	 || work->nrepeats > 0)
441033965Sjdp    {
441133965Sjdp      if ((**mangled == 'N') || (**mangled == 'T'))
441233965Sjdp	{
441333965Sjdp	  temptype = *(*mangled)++;
441460484Sobrien
441533965Sjdp	  if (temptype == 'N')
441633965Sjdp	    {
441733965Sjdp	      if (!get_count (mangled, &r))
441833965Sjdp		{
441933965Sjdp		  return (0);
442033965Sjdp		}
442133965Sjdp	    }
442233965Sjdp	  else
442333965Sjdp	    {
442433965Sjdp	      r = 1;
442533965Sjdp	    }
442660484Sobrien          if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
442733965Sjdp            {
442833965Sjdp              /* If we have 10 or more types we might have more than a 1 digit
442933965Sjdp                 index so we'll have to consume the whole count here. This
443033965Sjdp                 will lose if the next thing is a type name preceded by a
443133965Sjdp                 count but it's impossible to demangle that case properly
443233965Sjdp                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
443333965Sjdp                 Pc, ...)"  or "(..., type12, char *, ...)" */
443460484Sobrien              if ((t = consume_count(mangled)) <= 0)
443533965Sjdp                {
443633965Sjdp                  return (0);
443733965Sjdp                }
443833965Sjdp            }
443933965Sjdp          else
444033965Sjdp	    {
444133965Sjdp	      if (!get_count (mangled, &t))
444233965Sjdp	    	{
444333965Sjdp	          return (0);
444433965Sjdp	    	}
444533965Sjdp	    }
444660484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
444733965Sjdp	    {
444833965Sjdp	      t--;
444933965Sjdp	    }
445033965Sjdp	  /* Validate the type index.  Protect against illegal indices from
445133965Sjdp	     malformed type strings.  */
445233965Sjdp	  if ((t < 0) || (t >= work -> ntypes))
445333965Sjdp	    {
445433965Sjdp	      return (0);
445533965Sjdp	    }
445660484Sobrien	  while (work->nrepeats > 0 || --r >= 0)
445733965Sjdp	    {
445833965Sjdp	      tem = work -> typevec[t];
445933965Sjdp	      if (need_comma && PRINT_ARG_TYPES)
446033965Sjdp		{
446133965Sjdp		  string_append (declp, ", ");
446233965Sjdp		}
446333965Sjdp	      if (!do_arg (work, &tem, &arg))
446433965Sjdp		{
446533965Sjdp		  return (0);
446633965Sjdp		}
446733965Sjdp	      if (PRINT_ARG_TYPES)
446833965Sjdp		{
446933965Sjdp		  string_appends (declp, &arg);
447033965Sjdp		}
447133965Sjdp	      string_delete (&arg);
447233965Sjdp	      need_comma = 1;
447333965Sjdp	    }
447433965Sjdp	}
447533965Sjdp      else
447633965Sjdp	{
447760484Sobrien	  if (need_comma && PRINT_ARG_TYPES)
447860484Sobrien	    string_append (declp, ", ");
447933965Sjdp	  if (!do_arg (work, mangled, &arg))
448060484Sobrien	    return (0);
448133965Sjdp	  if (PRINT_ARG_TYPES)
448260484Sobrien	    string_appends (declp, &arg);
448333965Sjdp	  string_delete (&arg);
448433965Sjdp	  need_comma = 1;
448533965Sjdp	}
448633965Sjdp    }
448733965Sjdp
448833965Sjdp  if (**mangled == 'e')
448933965Sjdp    {
449033965Sjdp      (*mangled)++;
449133965Sjdp      if (PRINT_ARG_TYPES)
449233965Sjdp	{
449333965Sjdp	  if (need_comma)
449433965Sjdp	    {
449533965Sjdp	      string_append (declp, ",");
449633965Sjdp	    }
449733965Sjdp	  string_append (declp, "...");
449833965Sjdp	}
449933965Sjdp    }
450033965Sjdp
450133965Sjdp  if (PRINT_ARG_TYPES)
450233965Sjdp    {
450333965Sjdp      string_append (declp, ")");
450433965Sjdp    }
450533965Sjdp  return (1);
450633965Sjdp}
450733965Sjdp
450860484Sobrien/* Like demangle_args, but for demangling the argument lists of function
450960484Sobrien   and method pointers or references, not top-level declarations.  */
451060484Sobrien
451160484Sobrienstatic int
451260484Sobriendemangle_nested_args (work, mangled, declp)
451360484Sobrien     struct work_stuff *work;
451460484Sobrien     const char **mangled;
451560484Sobrien     string *declp;
451660484Sobrien{
451760484Sobrien  string* saved_previous_argument;
451860484Sobrien  int result;
451960484Sobrien  int saved_nrepeats;
452060484Sobrien
452160484Sobrien  /* The G++ name-mangling algorithm does not remember types on nested
452260484Sobrien     argument lists, unless -fsquangling is used, and in that case the
452360484Sobrien     type vector updated by remember_type is not used.  So, we turn
452460484Sobrien     off remembering of types here.  */
452560484Sobrien  ++work->forgetting_types;
452660484Sobrien
452760484Sobrien  /* For the repeat codes used with -fsquangling, we must keep track of
452860484Sobrien     the last argument.  */
452960484Sobrien  saved_previous_argument = work->previous_argument;
453060484Sobrien  saved_nrepeats = work->nrepeats;
453160484Sobrien  work->previous_argument = 0;
453260484Sobrien  work->nrepeats = 0;
453360484Sobrien
453460484Sobrien  /* Actually demangle the arguments.  */
453560484Sobrien  result = demangle_args (work, mangled, declp);
453660484Sobrien
453760484Sobrien  /* Restore the previous_argument field.  */
453860484Sobrien  if (work->previous_argument)
453960484Sobrien    string_delete (work->previous_argument);
454060484Sobrien  work->previous_argument = saved_previous_argument;
454160484Sobrien  --work->forgetting_types;
454260484Sobrien  work->nrepeats = saved_nrepeats;
454360484Sobrien
454460484Sobrien  return result;
454560484Sobrien}
454660484Sobrien
454733965Sjdpstatic void
454833965Sjdpdemangle_function_name (work, mangled, declp, scan)
454933965Sjdp     struct work_stuff *work;
455033965Sjdp     const char **mangled;
455133965Sjdp     string *declp;
455233965Sjdp     const char *scan;
455333965Sjdp{
455460484Sobrien  size_t i;
455533965Sjdp  string type;
455633965Sjdp  const char *tem;
455733965Sjdp
455833965Sjdp  string_appendn (declp, (*mangled), scan - (*mangled));
455933965Sjdp  string_need (declp, 1);
456033965Sjdp  *(declp -> p) = '\0';
456133965Sjdp
456233965Sjdp  /* Consume the function name, including the "__" separating the name
456333965Sjdp     from the signature.  We are guaranteed that SCAN points to the
456433965Sjdp     separator.  */
456533965Sjdp
456633965Sjdp  (*mangled) = scan + 2;
456760484Sobrien  /* We may be looking at an instantiation of a template function:
456860484Sobrien     foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
456960484Sobrien     following _F marks the start of the function arguments.  Handle
457060484Sobrien     the template arguments first. */
457133965Sjdp
457260484Sobrien  if (HP_DEMANGLING && (**mangled == 'X'))
457333965Sjdp    {
457460484Sobrien      demangle_arm_hp_template (work, mangled, 0, declp);
457560484Sobrien      /* This leaves MANGLED pointing to the 'F' marking func args */
457660484Sobrien    }
457733965Sjdp
457860484Sobrien  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
457960484Sobrien    {
458060484Sobrien
458133965Sjdp      /* See if we have an ARM style constructor or destructor operator.
458233965Sjdp	 If so, then just record it, clear the decl, and return.
458333965Sjdp	 We can't build the actual constructor/destructor decl until later,
458433965Sjdp	 when we recover the class name from the signature.  */
458533965Sjdp
458633965Sjdp      if (strcmp (declp -> b, "__ct") == 0)
458733965Sjdp	{
458833965Sjdp	  work -> constructor += 1;
458933965Sjdp	  string_clear (declp);
459033965Sjdp	  return;
459133965Sjdp	}
459233965Sjdp      else if (strcmp (declp -> b, "__dt") == 0)
459333965Sjdp	{
459433965Sjdp	  work -> destructor += 1;
459533965Sjdp	  string_clear (declp);
459633965Sjdp	  return;
459733965Sjdp	}
459833965Sjdp    }
459933965Sjdp
460060484Sobrien  if (declp->p - declp->b >= 3
460133965Sjdp      && declp->b[0] == 'o'
460233965Sjdp      && declp->b[1] == 'p'
460333965Sjdp      && strchr (cplus_markers, declp->b[2]) != NULL)
460433965Sjdp    {
460533965Sjdp      /* see if it's an assignment expression */
460633965Sjdp      if (declp->p - declp->b >= 10 /* op$assign_ */
460733965Sjdp	  && memcmp (declp->b + 3, "assign_", 7) == 0)
460833965Sjdp	{
460977298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
461033965Sjdp	    {
461160484Sobrien	      int len = declp->p - declp->b - 10;
461260484Sobrien	      if ((int) strlen (optable[i].in) == len
461333965Sjdp		  && memcmp (optable[i].in, declp->b + 10, len) == 0)
461433965Sjdp		{
461533965Sjdp		  string_clear (declp);
461633965Sjdp		  string_append (declp, "operator");
461733965Sjdp		  string_append (declp, optable[i].out);
461833965Sjdp		  string_append (declp, "=");
461933965Sjdp		  break;
462033965Sjdp		}
462133965Sjdp	    }
462233965Sjdp	}
462333965Sjdp      else
462433965Sjdp	{
462577298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
462633965Sjdp	    {
462733965Sjdp	      int len = declp->p - declp->b - 3;
462860484Sobrien	      if ((int) strlen (optable[i].in) == len
462933965Sjdp		  && memcmp (optable[i].in, declp->b + 3, len) == 0)
463033965Sjdp		{
463133965Sjdp		  string_clear (declp);
463233965Sjdp		  string_append (declp, "operator");
463333965Sjdp		  string_append (declp, optable[i].out);
463433965Sjdp		  break;
463533965Sjdp		}
463633965Sjdp	    }
463733965Sjdp	}
463833965Sjdp    }
463933965Sjdp  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
464033965Sjdp	   && strchr (cplus_markers, declp->b[4]) != NULL)
464133965Sjdp    {
464233965Sjdp      /* type conversion operator */
464333965Sjdp      tem = declp->b + 5;
464433965Sjdp      if (do_type (work, &tem, &type))
464533965Sjdp	{
464633965Sjdp	  string_clear (declp);
464733965Sjdp	  string_append (declp, "operator ");
464833965Sjdp	  string_appends (declp, &type);
464933965Sjdp	  string_delete (&type);
465033965Sjdp	}
465133965Sjdp    }
465233965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
465333965Sjdp	   && declp->b[2] == 'o' && declp->b[3] == 'p')
465433965Sjdp    {
465533965Sjdp      /* ANSI.  */
465633965Sjdp      /* type conversion operator.  */
465733965Sjdp      tem = declp->b + 4;
465833965Sjdp      if (do_type (work, &tem, &type))
465933965Sjdp	{
466033965Sjdp	  string_clear (declp);
466133965Sjdp	  string_append (declp, "operator ");
466233965Sjdp	  string_appends (declp, &type);
466333965Sjdp	  string_delete (&type);
466433965Sjdp	}
466533965Sjdp    }
466633965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
466777298Sobrien	   && ISLOWER((unsigned char)declp->b[2])
466877298Sobrien	   && ISLOWER((unsigned char)declp->b[3]))
466933965Sjdp    {
467033965Sjdp      if (declp->b[4] == '\0')
467133965Sjdp	{
467233965Sjdp	  /* Operator.  */
467377298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
467433965Sjdp	    {
467533965Sjdp	      if (strlen (optable[i].in) == 2
467633965Sjdp		  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
467733965Sjdp		{
467833965Sjdp		  string_clear (declp);
467933965Sjdp		  string_append (declp, "operator");
468033965Sjdp		  string_append (declp, optable[i].out);
468133965Sjdp		  break;
468233965Sjdp		}
468333965Sjdp	    }
468433965Sjdp	}
468533965Sjdp      else
468633965Sjdp	{
468733965Sjdp	  if (declp->b[2] == 'a' && declp->b[5] == '\0')
468833965Sjdp	    {
468933965Sjdp	      /* Assignment.  */
469077298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
469133965Sjdp		{
469233965Sjdp		  if (strlen (optable[i].in) == 3
469333965Sjdp		      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
469433965Sjdp		    {
469533965Sjdp		      string_clear (declp);
469633965Sjdp		      string_append (declp, "operator");
469733965Sjdp		      string_append (declp, optable[i].out);
469833965Sjdp		      break;
469960484Sobrien		    }
470033965Sjdp		}
470133965Sjdp	    }
470233965Sjdp	}
470333965Sjdp    }
470433965Sjdp}
470533965Sjdp
470633965Sjdp/* a mini string-handling package */
470733965Sjdp
470833965Sjdpstatic void
470933965Sjdpstring_need (s, n)
471033965Sjdp     string *s;
471133965Sjdp     int n;
471233965Sjdp{
471333965Sjdp  int tem;
471433965Sjdp
471533965Sjdp  if (s->b == NULL)
471633965Sjdp    {
471733965Sjdp      if (n < 32)
471833965Sjdp	{
471933965Sjdp	  n = 32;
472033965Sjdp	}
472133965Sjdp      s->p = s->b = xmalloc (n);
472233965Sjdp      s->e = s->b + n;
472333965Sjdp    }
472433965Sjdp  else if (s->e - s->p < n)
472533965Sjdp    {
472633965Sjdp      tem = s->p - s->b;
472733965Sjdp      n += tem;
472833965Sjdp      n *= 2;
472933965Sjdp      s->b = xrealloc (s->b, n);
473033965Sjdp      s->p = s->b + tem;
473133965Sjdp      s->e = s->b + n;
473233965Sjdp    }
473333965Sjdp}
473433965Sjdp
473533965Sjdpstatic void
473633965Sjdpstring_delete (s)
473733965Sjdp     string *s;
473833965Sjdp{
473933965Sjdp  if (s->b != NULL)
474033965Sjdp    {
474133965Sjdp      free (s->b);
474233965Sjdp      s->b = s->e = s->p = NULL;
474333965Sjdp    }
474433965Sjdp}
474533965Sjdp
474633965Sjdpstatic void
474733965Sjdpstring_init (s)
474833965Sjdp     string *s;
474933965Sjdp{
475033965Sjdp  s->b = s->p = s->e = NULL;
475133965Sjdp}
475233965Sjdp
475360484Sobrienstatic void
475433965Sjdpstring_clear (s)
475533965Sjdp     string *s;
475633965Sjdp{
475733965Sjdp  s->p = s->b;
475833965Sjdp}
475933965Sjdp
476033965Sjdp#if 0
476133965Sjdp
476233965Sjdpstatic int
476333965Sjdpstring_empty (s)
476433965Sjdp     string *s;
476533965Sjdp{
476633965Sjdp  return (s->b == s->p);
476733965Sjdp}
476833965Sjdp
476933965Sjdp#endif
477033965Sjdp
477133965Sjdpstatic void
477233965Sjdpstring_append (p, s)
477333965Sjdp     string *p;
477433965Sjdp     const char *s;
477533965Sjdp{
477633965Sjdp  int n;
477733965Sjdp  if (s == NULL || *s == '\0')
477833965Sjdp    return;
477933965Sjdp  n = strlen (s);
478033965Sjdp  string_need (p, n);
478133965Sjdp  memcpy (p->p, s, n);
478233965Sjdp  p->p += n;
478333965Sjdp}
478433965Sjdp
478533965Sjdpstatic void
478633965Sjdpstring_appends (p, s)
478733965Sjdp     string *p, *s;
478833965Sjdp{
478933965Sjdp  int n;
479033965Sjdp
479133965Sjdp  if (s->b != s->p)
479233965Sjdp    {
479333965Sjdp      n = s->p - s->b;
479433965Sjdp      string_need (p, n);
479533965Sjdp      memcpy (p->p, s->b, n);
479633965Sjdp      p->p += n;
479733965Sjdp    }
479833965Sjdp}
479933965Sjdp
480033965Sjdpstatic void
480133965Sjdpstring_appendn (p, s, n)
480233965Sjdp     string *p;
480333965Sjdp     const char *s;
480433965Sjdp     int n;
480533965Sjdp{
480633965Sjdp  if (n != 0)
480733965Sjdp    {
480833965Sjdp      string_need (p, n);
480933965Sjdp      memcpy (p->p, s, n);
481033965Sjdp      p->p += n;
481133965Sjdp    }
481233965Sjdp}
481333965Sjdp
481433965Sjdpstatic void
481533965Sjdpstring_prepend (p, s)
481633965Sjdp     string *p;
481733965Sjdp     const char *s;
481833965Sjdp{
481933965Sjdp  if (s != NULL && *s != '\0')
482033965Sjdp    {
482133965Sjdp      string_prependn (p, s, strlen (s));
482233965Sjdp    }
482333965Sjdp}
482433965Sjdp
482533965Sjdpstatic void
482633965Sjdpstring_prepends (p, s)
482733965Sjdp     string *p, *s;
482833965Sjdp{
482933965Sjdp  if (s->b != s->p)
483033965Sjdp    {
483133965Sjdp      string_prependn (p, s->b, s->p - s->b);
483233965Sjdp    }
483333965Sjdp}
483433965Sjdp
483533965Sjdpstatic void
483633965Sjdpstring_prependn (p, s, n)
483733965Sjdp     string *p;
483833965Sjdp     const char *s;
483933965Sjdp     int n;
484033965Sjdp{
484133965Sjdp  char *q;
484233965Sjdp
484333965Sjdp  if (n != 0)
484433965Sjdp    {
484533965Sjdp      string_need (p, n);
484633965Sjdp      for (q = p->p - 1; q >= p->b; q--)
484733965Sjdp	{
484833965Sjdp	  q[n] = q[0];
484933965Sjdp	}
485033965Sjdp      memcpy (p->b, s, n);
485133965Sjdp      p->p += n;
485233965Sjdp    }
485333965Sjdp}
485433965Sjdp
485560484Sobrienstatic void
485660484Sobrienstring_append_template_idx (s, idx)
485760484Sobrien     string *s;
485860484Sobrien     int idx;
485960484Sobrien{
486060484Sobrien  char buf[INTBUF_SIZE + 1 /* 'T' */];
486160484Sobrien  sprintf(buf, "T%d", idx);
486260484Sobrien  string_append (s, buf);
486360484Sobrien}
486460484Sobrien
486533965Sjdp/* To generate a standalone demangler program for testing purposes,
486633965Sjdp   just compile and link this file with -DMAIN and libiberty.a.  When
486733965Sjdp   run, it demangles each command line arg, or each stdin string, and
486833965Sjdp   prints the result on stdout.  */
486933965Sjdp
487033965Sjdp#ifdef MAIN
487133965Sjdp
487238889Sjdp#include "getopt.h"
487338889Sjdp
487460484Sobrienstatic const char *program_name;
487560484Sobrienstatic const char *program_version = VERSION;
487638889Sjdpstatic int flags = DMGL_PARAMS | DMGL_ANSI;
487738889Sjdp
487833965Sjdpstatic void demangle_it PARAMS ((char *));
487960484Sobrienstatic void usage PARAMS ((FILE *, int)) ATTRIBUTE_NORETURN;
488060484Sobrienstatic void fatal PARAMS ((const char *)) ATTRIBUTE_NORETURN;
488168765Sobrienstatic void print_demangler_list PARAMS ((FILE *));
488233965Sjdp
488333965Sjdpstatic void
488433965Sjdpdemangle_it (mangled_name)
488533965Sjdp     char *mangled_name;
488633965Sjdp{
488733965Sjdp  char *result;
488833965Sjdp
488938889Sjdp  result = cplus_demangle (mangled_name, flags);
489033965Sjdp  if (result == NULL)
489133965Sjdp    {
489233965Sjdp      printf ("%s\n", mangled_name);
489333965Sjdp    }
489433965Sjdp  else
489533965Sjdp    {
489633965Sjdp      printf ("%s\n", result);
489733965Sjdp      free (result);
489833965Sjdp    }
489933965Sjdp}
490033965Sjdp
490168765Sobrienstatic void
490268765Sobrienprint_demangler_list (stream)
490368765Sobrien     FILE *stream;
490468765Sobrien{
490568765Sobrien  struct demangler_engine *demangler;
490668765Sobrien
490768765Sobrien  fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
490868765Sobrien
490968765Sobrien  for (demangler = libiberty_demanglers + 1;
491068765Sobrien       demangler->demangling_style != unknown_demangling;
491168765Sobrien       ++demangler)
491268765Sobrien    fprintf (stream, ",%s", demangler->demangling_style_name);
491368765Sobrien
491468765Sobrien  fprintf (stream, "}");
491568765Sobrien}
491668765Sobrien
491733965Sjdpstatic void
491833965Sjdpusage (stream, status)
491933965Sjdp     FILE *stream;
492033965Sjdp     int status;
492160484Sobrien{
492233965Sjdp  fprintf (stream, "\
492368765SobrienUsage: %s [-_] [-n] [--strip-underscores] [--no-strip-underscores] \n",
492433965Sjdp	   program_name);
492568765Sobrien
492668765Sobrien  fprintf (stream, "\
492768765Sobrien       [-s ");
492868765Sobrien  print_demangler_list (stream);
492968765Sobrien  fprintf (stream, "]\n");
493068765Sobrien
493168765Sobrien  fprintf (stream, "\
493268765Sobrien       [--format ");
493368765Sobrien  print_demangler_list (stream);
493468765Sobrien  fprintf (stream, "]\n");
493568765Sobrien
493668765Sobrien  fprintf (stream, "\
493768765Sobrien       [--help] [--version] [arg...]\n");
493833965Sjdp  exit (status);
493933965Sjdp}
494033965Sjdp
494160484Sobrien#define MBUF_SIZE 32767
494233965Sjdpchar mbuffer[MBUF_SIZE];
494333965Sjdp
494433965Sjdp/* Defined in the automatically-generated underscore.c.  */
494533965Sjdpextern int prepends_underscore;
494633965Sjdp
494733965Sjdpint strip_underscore = 0;
494833965Sjdp
494933965Sjdpstatic struct option long_options[] = {
495033965Sjdp  {"strip-underscores", no_argument, 0, '_'},
495133965Sjdp  {"format", required_argument, 0, 's'},
495233965Sjdp  {"help", no_argument, 0, 'h'},
495338889Sjdp  {"java", no_argument, 0, 'j'},
495433965Sjdp  {"no-strip-underscores", no_argument, 0, 'n'},
495533965Sjdp  {"version", no_argument, 0, 'v'},
495633965Sjdp  {0, no_argument, 0, 0}
495733965Sjdp};
495833965Sjdp
495960484Sobrien/* More 'friendly' abort that prints the line and file.
496060484Sobrien   config.h can #define abort fancy_abort if you like that sort of thing.  */
496160484Sobrien
496260484Sobrienvoid
496360484Sobrienfancy_abort ()
496460484Sobrien{
496560484Sobrien  fatal ("Internal gcc abort.");
496660484Sobrien}
496760484Sobrien
496860484Sobrien
496960484Sobrienstatic const char *
497060484Sobrienstandard_symbol_characters PARAMS ((void));
497160484Sobrien
497260484Sobrienstatic const char *
497360484Sobrienhp_symbol_characters PARAMS ((void));
497460484Sobrien
497568765Sobrienstatic const char *
497677298Sobriengnu_v3_symbol_characters PARAMS ((void));
497768765Sobrien
497860484Sobrien/* Return the string of non-alnum characters that may occur
497960484Sobrien   as a valid symbol component, in the standard assembler symbol
498060484Sobrien   syntax.  */
498160484Sobrien
498260484Sobrienstatic const char *
498360484Sobrienstandard_symbol_characters ()
498460484Sobrien{
498560484Sobrien  return "_$.";
498660484Sobrien}
498760484Sobrien
498860484Sobrien
498960484Sobrien/* Return the string of non-alnum characters that may occur
499060484Sobrien   as a valid symbol name component in an HP object file.
499160484Sobrien
499260484Sobrien   Note that, since HP's compiler generates object code straight from
499360484Sobrien   C++ source, without going through an assembler, its mangled
499460484Sobrien   identifiers can use all sorts of characters that no assembler would
499560484Sobrien   tolerate, so the alphabet this function creates is a little odd.
499660484Sobrien   Here are some sample mangled identifiers offered by HP:
499760484Sobrien
499860484Sobrien	typeid*__XT24AddressIndExpClassMember_
499960484Sobrien	[Vftptr]key:__dt__32OrdinaryCompareIndExpClassMemberFv
500060484Sobrien	__ct__Q2_9Elf64_Dyn18{unnamed.union.#1}Fv
500160484Sobrien
500260484Sobrien   This still seems really weird to me, since nowhere else in this
500360484Sobrien   file is there anything to recognize curly brackets, parens, etc.
500460484Sobrien   I've talked with Srikanth <srikanth@cup.hp.com>, and he assures me
500560484Sobrien   this is right, but I still strongly suspect that there's a
500660484Sobrien   misunderstanding here.
500760484Sobrien
500860484Sobrien   If we decide it's better for c++filt to use HP's assembler syntax
500960484Sobrien   to scrape identifiers out of its input, here's the definition of
501060484Sobrien   the symbol name syntax from the HP assembler manual:
501160484Sobrien
501260484Sobrien       Symbols are composed of uppercase and lowercase letters, decimal
501360484Sobrien       digits, dollar symbol, period (.), ampersand (&), pound sign(#) and
501460484Sobrien       underscore (_). A symbol can begin with a letter, digit underscore or
501560484Sobrien       dollar sign. If a symbol begins with a digit, it must contain a
501660484Sobrien       non-digit character.
501760484Sobrien
501860484Sobrien   So have fun.  */
501960484Sobrienstatic const char *
502060484Sobrienhp_symbol_characters ()
502160484Sobrien{
502260484Sobrien  return "_$.<>#,*&[]:(){}";
502360484Sobrien}
502460484Sobrien
502560484Sobrien
502668765Sobrien/* Return the string of non-alnum characters that may occur
502777298Sobrien   as a valid symbol component in the GNU C++ V3 ABI mangling
502868765Sobrien   scheme.  */
502968765Sobrien
503068765Sobrienstatic const char *
503177298Sobriengnu_v3_symbol_characters ()
503268765Sobrien{
503377298Sobrien  return "_$.";
503468765Sobrien}
503568765Sobrien
503668765Sobrien
503760484Sobrienextern int main PARAMS ((int, char **));
503860484Sobrien
503933965Sjdpint
504033965Sjdpmain (argc, argv)
504133965Sjdp     int argc;
504233965Sjdp     char **argv;
504333965Sjdp{
504433965Sjdp  char *result;
504533965Sjdp  int c;
504660484Sobrien  const char *valid_symbols;
504733965Sjdp
504833965Sjdp  program_name = argv[0];
504933965Sjdp
505033965Sjdp  strip_underscore = prepends_underscore;
505133965Sjdp
505238889Sjdp  while ((c = getopt_long (argc, argv, "_ns:j", long_options, (int *) 0)) != EOF)
505333965Sjdp    {
505433965Sjdp      switch (c)
505533965Sjdp	{
505633965Sjdp	case '?':
505733965Sjdp	  usage (stderr, 1);
505833965Sjdp	  break;
505933965Sjdp	case 'h':
506033965Sjdp	  usage (stdout, 0);
506133965Sjdp	case 'n':
506233965Sjdp	  strip_underscore = 0;
506333965Sjdp	  break;
506433965Sjdp	case 'v':
506560484Sobrien	  printf ("GNU %s (C++ demangler), version %s\n", program_name, program_version);
506660484Sobrien	  return (0);
506733965Sjdp	case '_':
506833965Sjdp	  strip_underscore = 1;
506933965Sjdp	  break;
507038889Sjdp	case 'j':
507138889Sjdp	  flags |= DMGL_JAVA;
507238889Sjdp	  break;
507333965Sjdp	case 's':
507468765Sobrien	  {
507568765Sobrien	    enum demangling_styles style;
507668765Sobrien
507768765Sobrien	    style = cplus_demangle_name_to_style (optarg);
507868765Sobrien	    if (style == unknown_demangling)
507968765Sobrien	      {
508068765Sobrien		fprintf (stderr, "%s: unknown demangling style `%s'\n",
508168765Sobrien			 program_name, optarg);
508268765Sobrien		return (1);
508368765Sobrien	      }
508468765Sobrien	    else
508568765Sobrien	      cplus_demangle_set_style (style);
508668765Sobrien	  }
508733965Sjdp	  break;
508833965Sjdp	}
508933965Sjdp    }
509033965Sjdp
509133965Sjdp  if (optind < argc)
509233965Sjdp    {
509333965Sjdp      for ( ; optind < argc; optind++)
509433965Sjdp	{
509533965Sjdp	  demangle_it (argv[optind]);
509633965Sjdp	}
509733965Sjdp    }
509833965Sjdp  else
509933965Sjdp    {
510060484Sobrien      switch (current_demangling_style)
510160484Sobrien	{
510260484Sobrien	case gnu_demangling:
510360484Sobrien	case lucid_demangling:
510460484Sobrien	case arm_demangling:
510577298Sobrien	case java_demangling:
510660484Sobrien	case edg_demangling:
510777298Sobrien	case gnat_demangling:
510877298Sobrien	case auto_demangling:
510960484Sobrien	  valid_symbols = standard_symbol_characters ();
511060484Sobrien	  break;
511160484Sobrien	case hp_demangling:
511260484Sobrien	  valid_symbols = hp_symbol_characters ();
511360484Sobrien	  break;
511477298Sobrien	case gnu_v3_demangling:
511577298Sobrien	  valid_symbols = gnu_v3_symbol_characters ();
511668765Sobrien	  break;
511760484Sobrien	default:
511860484Sobrien	  /* Folks should explicitly indicate the appropriate alphabet for
511960484Sobrien	     each demangling.  Providing a default would allow the
512060484Sobrien	     question to go unconsidered.  */
512160484Sobrien	  abort ();
512260484Sobrien	}
512360484Sobrien
512433965Sjdp      for (;;)
512533965Sjdp	{
512633965Sjdp	  int i = 0;
512733965Sjdp	  c = getchar ();
512833965Sjdp	  /* Try to read a label.  */
512977298Sobrien	  while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
513033965Sjdp	    {
513133965Sjdp	      if (i >= MBUF_SIZE-1)
513233965Sjdp		break;
513333965Sjdp	      mbuffer[i++] = c;
513433965Sjdp	      c = getchar ();
513533965Sjdp	    }
513633965Sjdp	  if (i > 0)
513733965Sjdp	    {
513833965Sjdp	      int skip_first = 0;
513933965Sjdp
514033965Sjdp	      if (mbuffer[0] == '.')
514133965Sjdp		++skip_first;
514233965Sjdp	      if (strip_underscore && mbuffer[skip_first] == '_')
514333965Sjdp		++skip_first;
514433965Sjdp
514533965Sjdp	      if (skip_first > i)
514633965Sjdp		skip_first = i;
514733965Sjdp
514833965Sjdp	      mbuffer[i] = 0;
514960484Sobrien
515038889Sjdp	      result = cplus_demangle (mbuffer + skip_first, flags);
515133965Sjdp	      if (result)
515233965Sjdp		{
515333965Sjdp		  if (mbuffer[0] == '.')
515433965Sjdp		    putc ('.', stdout);
515533965Sjdp		  fputs (result, stdout);
515633965Sjdp		  free (result);
515733965Sjdp		}
515833965Sjdp	      else
515933965Sjdp		fputs (mbuffer, stdout);
516033965Sjdp
516133965Sjdp	      fflush (stdout);
516233965Sjdp	    }
516333965Sjdp	  if (c == EOF)
516433965Sjdp	    break;
516533965Sjdp	  putchar (c);
516668765Sobrien	  fflush (stdout);
516733965Sjdp	}
516833965Sjdp    }
516933965Sjdp
517060484Sobrien  return (0);
517133965Sjdp}
517233965Sjdp
517333965Sjdpstatic void
517433965Sjdpfatal (str)
517560484Sobrien     const char *str;
517633965Sjdp{
517733965Sjdp  fprintf (stderr, "%s: %s\n", program_name, str);
517833965Sjdp  exit (1);
517933965Sjdp}
518033965Sjdp
518160484SobrienPTR
518233965Sjdpxmalloc (size)
518360484Sobrien  size_t size;
518433965Sjdp{
518560484Sobrien  register PTR value = (PTR) malloc (size);
518633965Sjdp  if (value == 0)
518733965Sjdp    fatal ("virtual memory exhausted");
518833965Sjdp  return value;
518933965Sjdp}
519033965Sjdp
519160484SobrienPTR
519233965Sjdpxrealloc (ptr, size)
519360484Sobrien  PTR ptr;
519460484Sobrien  size_t size;
519533965Sjdp{
519660484Sobrien  register PTR value = (PTR) realloc (ptr, size);
519733965Sjdp  if (value == 0)
519833965Sjdp    fatal ("virtual memory exhausted");
519933965Sjdp  return value;
520033965Sjdp}
520133965Sjdp#endif	/* main */
5202