cplus-dem.c revision 91041
160484Sobrien/* Demangler for GNU C++
277298Sobrien   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
389857Sobrien   2000, 2001 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
6633965Sjdp/* In order to allow a single demangler executable to demangle strings
6733965Sjdp   using various common values of CPLUS_MARKER, as well as any specific
6833965Sjdp   one set at compile time, we maintain a string containing all the
6933965Sjdp   commonly used ones, and check to see if the marker we are looking for
7033965Sjdp   is in that string.  CPLUS_MARKER is usually '$' on systems where the
7133965Sjdp   assembler can deal with that.  Where the assembler can't, it's usually
7233965Sjdp   '.' (but on many systems '.' is used for other things).  We put the
7333965Sjdp   current defined CPLUS_MARKER first (which defaults to '$'), followed
7433965Sjdp   by the next most common value, followed by an explicit '$' in case
7533965Sjdp   the value of CPLUS_MARKER is not '$'.
7633965Sjdp
7733965Sjdp   We could avoid this if we could just get g++ to tell us what the actual
7833965Sjdp   cplus marker character is as part of the debug information, perhaps by
7933965Sjdp   ensuring that it is the character that terminates the gcc<n>_compiled
8033965Sjdp   marker symbol (FIXME).  */
8133965Sjdp
8233965Sjdp#if !defined (CPLUS_MARKER)
8333965Sjdp#define CPLUS_MARKER '$'
8433965Sjdp#endif
8533965Sjdp
8677298Sobrienenum demangling_styles current_demangling_style = auto_demangling;
8733965Sjdp
8833965Sjdpstatic char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
8933965Sjdp
9060484Sobrienstatic char char_str[2] = { '\000', '\000' };
9160484Sobrien
9233965Sjdpvoid
9333965Sjdpset_cplus_marker_for_demangling (ch)
9433965Sjdp     int ch;
9533965Sjdp{
9633965Sjdp  cplus_markers[0] = ch;
9733965Sjdp}
9833965Sjdp
9960484Sobrientypedef struct string		/* Beware: these aren't required to be */
10060484Sobrien{				/*  '\0' terminated.  */
10160484Sobrien  char *b;			/* pointer to start of string */
10260484Sobrien  char *p;			/* pointer after last character */
10360484Sobrien  char *e;			/* pointer after end of allocated space */
10460484Sobrien} string;
10560484Sobrien
10633965Sjdp/* Stuff that is shared between sub-routines.
10733965Sjdp   Using a shared structure allows cplus_demangle to be reentrant.  */
10833965Sjdp
10933965Sjdpstruct work_stuff
11033965Sjdp{
11133965Sjdp  int options;
11233965Sjdp  char **typevec;
11360484Sobrien  char **ktypevec;
11460484Sobrien  char **btypevec;
11560484Sobrien  int numk;
11660484Sobrien  int numb;
11760484Sobrien  int ksize;
11860484Sobrien  int bsize;
11933965Sjdp  int ntypes;
12033965Sjdp  int typevec_size;
12133965Sjdp  int constructor;
12233965Sjdp  int destructor;
12333965Sjdp  int static_type;	/* A static member function */
12460484Sobrien  int temp_start;       /* index in demangled to start of template args */
12560484Sobrien  int type_quals;       /* The type qualifiers.  */
12660484Sobrien  int dllimported;	/* Symbol imported from a PE DLL */
12738889Sjdp  char **tmpl_argvec;   /* Template function arguments. */
12838889Sjdp  int ntmpl_args;       /* The number of template function arguments. */
12960484Sobrien  int forgetting_types; /* Nonzero if we are not remembering the types
13060484Sobrien			   we see.  */
13160484Sobrien  string* previous_argument; /* The last function argument demangled.  */
13260484Sobrien  int nrepeats;         /* The number of times to repeat the previous
13360484Sobrien			   argument.  */
13433965Sjdp};
13533965Sjdp
13633965Sjdp#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
13733965Sjdp#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
13833965Sjdp
13933965Sjdpstatic const struct optable
14033965Sjdp{
14189857Sobrien  const char *const in;
14289857Sobrien  const char *const out;
14389857Sobrien  const int flags;
14433965Sjdp} optable[] = {
14533965Sjdp  {"nw",	  " new",	DMGL_ANSI},	/* new (1.92,	 ansi) */
14633965Sjdp  {"dl",	  " delete",	DMGL_ANSI},	/* new (1.92,	 ansi) */
14733965Sjdp  {"new",	  " new",	0},		/* old (1.91,	 and 1.x) */
14833965Sjdp  {"delete",	  " delete",	0},		/* old (1.91,	 and 1.x) */
14933965Sjdp  {"vn",	  " new []",	DMGL_ANSI},	/* GNU, pending ansi */
15033965Sjdp  {"vd",	  " delete []",	DMGL_ANSI},	/* GNU, pending ansi */
15133965Sjdp  {"as",	  "=",		DMGL_ANSI},	/* ansi */
15233965Sjdp  {"ne",	  "!=",		DMGL_ANSI},	/* old, ansi */
15333965Sjdp  {"eq",	  "==",		DMGL_ANSI},	/* old,	ansi */
15433965Sjdp  {"ge",	  ">=",		DMGL_ANSI},	/* old,	ansi */
15533965Sjdp  {"gt",	  ">",		DMGL_ANSI},	/* old,	ansi */
15633965Sjdp  {"le",	  "<=",		DMGL_ANSI},	/* old,	ansi */
15733965Sjdp  {"lt",	  "<",		DMGL_ANSI},	/* old,	ansi */
15833965Sjdp  {"plus",	  "+",		0},		/* old */
15933965Sjdp  {"pl",	  "+",		DMGL_ANSI},	/* ansi */
16033965Sjdp  {"apl",	  "+=",		DMGL_ANSI},	/* ansi */
16133965Sjdp  {"minus",	  "-",		0},		/* old */
16233965Sjdp  {"mi",	  "-",		DMGL_ANSI},	/* ansi */
16333965Sjdp  {"ami",	  "-=",		DMGL_ANSI},	/* ansi */
16433965Sjdp  {"mult",	  "*",		0},		/* old */
16533965Sjdp  {"ml",	  "*",		DMGL_ANSI},	/* ansi */
16633965Sjdp  {"amu",	  "*=",		DMGL_ANSI},	/* ansi (ARM/Lucid) */
16733965Sjdp  {"aml",	  "*=",		DMGL_ANSI},	/* ansi (GNU/g++) */
16833965Sjdp  {"convert",	  "+",		0},		/* old (unary +) */
16933965Sjdp  {"negate",	  "-",		0},		/* old (unary -) */
17033965Sjdp  {"trunc_mod",	  "%",		0},		/* old */
17133965Sjdp  {"md",	  "%",		DMGL_ANSI},	/* ansi */
17233965Sjdp  {"amd",	  "%=",		DMGL_ANSI},	/* ansi */
17333965Sjdp  {"trunc_div",	  "/",		0},		/* old */
17433965Sjdp  {"dv",	  "/",		DMGL_ANSI},	/* ansi */
17533965Sjdp  {"adv",	  "/=",		DMGL_ANSI},	/* ansi */
17633965Sjdp  {"truth_andif", "&&",		0},		/* old */
17733965Sjdp  {"aa",	  "&&",		DMGL_ANSI},	/* ansi */
17833965Sjdp  {"truth_orif",  "||",		0},		/* old */
17933965Sjdp  {"oo",	  "||",		DMGL_ANSI},	/* ansi */
18033965Sjdp  {"truth_not",	  "!",		0},		/* old */
18133965Sjdp  {"nt",	  "!",		DMGL_ANSI},	/* ansi */
18233965Sjdp  {"postincrement","++",	0},		/* old */
18333965Sjdp  {"pp",	  "++",		DMGL_ANSI},	/* ansi */
18433965Sjdp  {"postdecrement","--",	0},		/* old */
18533965Sjdp  {"mm",	  "--",		DMGL_ANSI},	/* ansi */
18633965Sjdp  {"bit_ior",	  "|",		0},		/* old */
18733965Sjdp  {"or",	  "|",		DMGL_ANSI},	/* ansi */
18833965Sjdp  {"aor",	  "|=",		DMGL_ANSI},	/* ansi */
18933965Sjdp  {"bit_xor",	  "^",		0},		/* old */
19033965Sjdp  {"er",	  "^",		DMGL_ANSI},	/* ansi */
19133965Sjdp  {"aer",	  "^=",		DMGL_ANSI},	/* ansi */
19233965Sjdp  {"bit_and",	  "&",		0},		/* old */
19333965Sjdp  {"ad",	  "&",		DMGL_ANSI},	/* ansi */
19433965Sjdp  {"aad",	  "&=",		DMGL_ANSI},	/* ansi */
19533965Sjdp  {"bit_not",	  "~",		0},		/* old */
19633965Sjdp  {"co",	  "~",		DMGL_ANSI},	/* ansi */
19733965Sjdp  {"call",	  "()",		0},		/* old */
19833965Sjdp  {"cl",	  "()",		DMGL_ANSI},	/* ansi */
19933965Sjdp  {"alshift",	  "<<",		0},		/* old */
20033965Sjdp  {"ls",	  "<<",		DMGL_ANSI},	/* ansi */
20133965Sjdp  {"als",	  "<<=",	DMGL_ANSI},	/* ansi */
20233965Sjdp  {"arshift",	  ">>",		0},		/* old */
20333965Sjdp  {"rs",	  ">>",		DMGL_ANSI},	/* ansi */
20433965Sjdp  {"ars",	  ">>=",	DMGL_ANSI},	/* ansi */
20533965Sjdp  {"component",	  "->",		0},		/* old */
20633965Sjdp  {"pt",	  "->",		DMGL_ANSI},	/* ansi; Lucid C++ form */
20733965Sjdp  {"rf",	  "->",		DMGL_ANSI},	/* ansi; ARM/GNU form */
20833965Sjdp  {"indirect",	  "*",		0},		/* old */
20933965Sjdp  {"method_call",  "->()",	0},		/* old */
21033965Sjdp  {"addr",	  "&",		0},		/* old (unary &) */
21133965Sjdp  {"array",	  "[]",		0},		/* old */
21233965Sjdp  {"vc",	  "[]",		DMGL_ANSI},	/* ansi */
21333965Sjdp  {"compound",	  ", ",		0},		/* old */
21433965Sjdp  {"cm",	  ", ",		DMGL_ANSI},	/* ansi */
21533965Sjdp  {"cond",	  "?:",		0},		/* old */
21633965Sjdp  {"cn",	  "?:",		DMGL_ANSI},	/* pseudo-ansi */
21733965Sjdp  {"max",	  ">?",		0},		/* old */
21833965Sjdp  {"mx",	  ">?",		DMGL_ANSI},	/* pseudo-ansi */
21933965Sjdp  {"min",	  "<?",		0},		/* old */
22033965Sjdp  {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
22133965Sjdp  {"nop",	  "",		0},		/* old (for operator=) */
22260484Sobrien  {"rm",	  "->*",	DMGL_ANSI},	/* ansi */
22360484Sobrien  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
22433965Sjdp};
22533965Sjdp
22660484Sobrien/* These values are used to indicate the various type varieties.
22760484Sobrien   They are all non-zero so that they can be used as `success'
22860484Sobrien   values.  */
22960484Sobrientypedef enum type_kind_t
23060484Sobrien{
23160484Sobrien  tk_none,
23260484Sobrien  tk_pointer,
23360484Sobrien  tk_reference,
23460484Sobrien  tk_integral,
23560484Sobrien  tk_bool,
23660484Sobrien  tk_char,
23760484Sobrien  tk_real
23860484Sobrien} type_kind_t;
23933965Sjdp
24089857Sobrienconst struct demangler_engine libiberty_demanglers[] =
24168765Sobrien{
24268765Sobrien  {
24389857Sobrien    NO_DEMANGLING_STYLE_STRING,
24489857Sobrien    no_demangling,
24589857Sobrien    "Demangling disabled"
24689857Sobrien  }
24789857Sobrien  ,
24889857Sobrien  {
24968765Sobrien    AUTO_DEMANGLING_STYLE_STRING,
25068765Sobrien      auto_demangling,
25168765Sobrien      "Automatic selection based on executable"
25268765Sobrien  }
25368765Sobrien  ,
25468765Sobrien  {
25568765Sobrien    GNU_DEMANGLING_STYLE_STRING,
25668765Sobrien      gnu_demangling,
25768765Sobrien      "GNU (g++) style demangling"
25868765Sobrien  }
25968765Sobrien  ,
26068765Sobrien  {
26168765Sobrien    LUCID_DEMANGLING_STYLE_STRING,
26268765Sobrien      lucid_demangling,
26368765Sobrien      "Lucid (lcc) style demangling"
26468765Sobrien  }
26568765Sobrien  ,
26668765Sobrien  {
26768765Sobrien    ARM_DEMANGLING_STYLE_STRING,
26868765Sobrien      arm_demangling,
26968765Sobrien      "ARM style demangling"
27068765Sobrien  }
27168765Sobrien  ,
27268765Sobrien  {
27368765Sobrien    HP_DEMANGLING_STYLE_STRING,
27468765Sobrien      hp_demangling,
27568765Sobrien      "HP (aCC) style demangling"
27668765Sobrien  }
27768765Sobrien  ,
27868765Sobrien  {
27968765Sobrien    EDG_DEMANGLING_STYLE_STRING,
28068765Sobrien      edg_demangling,
28168765Sobrien      "EDG style demangling"
28268765Sobrien  }
28368765Sobrien  ,
28468765Sobrien  {
28577298Sobrien    GNU_V3_DEMANGLING_STYLE_STRING,
28677298Sobrien    gnu_v3_demangling,
28777298Sobrien    "GNU (g++) V3 ABI-style demangling"
28868765Sobrien  }
28968765Sobrien  ,
29068765Sobrien  {
29177298Sobrien    JAVA_DEMANGLING_STYLE_STRING,
29277298Sobrien    java_demangling,
29377298Sobrien    "Java style demangling"
29477298Sobrien  }
29577298Sobrien  ,
29677298Sobrien  {
29777298Sobrien    GNAT_DEMANGLING_STYLE_STRING,
29877298Sobrien    gnat_demangling,
29977298Sobrien    "GNAT style demangling"
30077298Sobrien  }
30177298Sobrien  ,
30277298Sobrien  {
30368765Sobrien    NULL, unknown_demangling, NULL
30468765Sobrien  }
30568765Sobrien};
30668765Sobrien
30733965Sjdp#define STRING_EMPTY(str)	((str) -> b == (str) -> p)
30833965Sjdp#define PREPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
30933965Sjdp    string_prepend(str, " ");}
31033965Sjdp#define APPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
31133965Sjdp    string_append(str, " ");}
31260484Sobrien#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
31333965Sjdp
31460484Sobrien/* The scope separator appropriate for the language being demangled.  */
31560484Sobrien
31660484Sobrien#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
31760484Sobrien
31833965Sjdp#define ARM_VTABLE_STRING "__vtbl__"	/* Lucid/ARM virtual table prefix */
31933965Sjdp#define ARM_VTABLE_STRLEN 8		/* strlen (ARM_VTABLE_STRING) */
32033965Sjdp
32133965Sjdp/* Prototypes for local functions */
32233965Sjdp
32368765Sobrienstatic void
32468765Sobriendelete_work_stuff PARAMS ((struct work_stuff *));
32568765Sobrien
32668765Sobrienstatic void
32768765Sobriendelete_non_B_K_work_stuff PARAMS ((struct work_stuff *));
32868765Sobrien
32933965Sjdpstatic char *
33033965Sjdpmop_up PARAMS ((struct work_stuff *, string *, int));
33133965Sjdp
33260484Sobrienstatic void
33360484Sobriensquangle_mop_up PARAMS ((struct work_stuff *));
33460484Sobrien
33568765Sobrienstatic void
33668765Sobrienwork_stuff_copy_to_from PARAMS ((struct work_stuff *, struct work_stuff *));
33768765Sobrien
33833965Sjdp#if 0
33933965Sjdpstatic int
34060484Sobriendemangle_method_args PARAMS ((struct work_stuff *, const char **, string *));
34133965Sjdp#endif
34233965Sjdp
34360484Sobrienstatic char *
34460484Sobrieninternal_cplus_demangle PARAMS ((struct work_stuff *, const char *));
34560484Sobrien
34633965Sjdpstatic int
34760484Sobriendemangle_template_template_parm PARAMS ((struct work_stuff *work,
34860484Sobrien					 const char **, string *));
34960484Sobrien
35060484Sobrienstatic int
35133965Sjdpdemangle_template PARAMS ((struct work_stuff *work, const char **, string *,
35260484Sobrien			   string *, int, int));
35333965Sjdp
35433965Sjdpstatic int
35533965Sjdparm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
35633965Sjdp		const char **));
35733965Sjdp
35833965Sjdpstatic int
35933965Sjdpdemangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
36033965Sjdp
36133965Sjdpstatic int
36233965Sjdpdemangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
36333965Sjdp			    int, int));
36433965Sjdp
36533965Sjdpstatic int
36633965Sjdpdemangle_class PARAMS ((struct work_stuff *, const char **, string *));
36733965Sjdp
36833965Sjdpstatic int
36933965Sjdpdemangle_fund_type PARAMS ((struct work_stuff *, const char **, string *));
37033965Sjdp
37133965Sjdpstatic int
37233965Sjdpdemangle_signature PARAMS ((struct work_stuff *, const char **, string *));
37333965Sjdp
37433965Sjdpstatic int
37533965Sjdpdemangle_prefix PARAMS ((struct work_stuff *, const char **, string *));
37633965Sjdp
37733965Sjdpstatic int
37833965Sjdpgnu_special PARAMS ((struct work_stuff *, const char **, string *));
37933965Sjdp
38033965Sjdpstatic int
38160484Sobrienarm_special PARAMS ((const char **, string *));
38233965Sjdp
38333965Sjdpstatic void
38433965Sjdpstring_need PARAMS ((string *, int));
38533965Sjdp
38633965Sjdpstatic void
38733965Sjdpstring_delete PARAMS ((string *));
38833965Sjdp
38933965Sjdpstatic void
39033965Sjdpstring_init PARAMS ((string *));
39133965Sjdp
39233965Sjdpstatic void
39333965Sjdpstring_clear PARAMS ((string *));
39433965Sjdp
39533965Sjdp#if 0
39633965Sjdpstatic int
39733965Sjdpstring_empty PARAMS ((string *));
39833965Sjdp#endif
39933965Sjdp
40033965Sjdpstatic void
40133965Sjdpstring_append PARAMS ((string *, const char *));
40233965Sjdp
40333965Sjdpstatic void
40433965Sjdpstring_appends PARAMS ((string *, string *));
40533965Sjdp
40633965Sjdpstatic void
40733965Sjdpstring_appendn PARAMS ((string *, const char *, int));
40833965Sjdp
40933965Sjdpstatic void
41033965Sjdpstring_prepend PARAMS ((string *, const char *));
41133965Sjdp
41233965Sjdpstatic void
41333965Sjdpstring_prependn PARAMS ((string *, const char *, int));
41433965Sjdp
41560484Sobrienstatic void
41660484Sobrienstring_append_template_idx PARAMS ((string *, int));
41760484Sobrien
41833965Sjdpstatic int
41933965Sjdpget_count PARAMS ((const char **, int *));
42033965Sjdp
42133965Sjdpstatic int
42233965Sjdpconsume_count PARAMS ((const char **));
42333965Sjdp
42460484Sobrienstatic int
42538889Sjdpconsume_count_with_underscores PARAMS ((const char**));
42638889Sjdp
42733965Sjdpstatic int
42833965Sjdpdemangle_args PARAMS ((struct work_stuff *, const char **, string *));
42933965Sjdp
43033965Sjdpstatic int
43160484Sobriendemangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
43260484Sobrien
43360484Sobrienstatic int
43433965Sjdpdo_type PARAMS ((struct work_stuff *, const char **, string *));
43533965Sjdp
43633965Sjdpstatic int
43733965Sjdpdo_arg PARAMS ((struct work_stuff *, const char **, string *));
43833965Sjdp
43933965Sjdpstatic void
44033965Sjdpdemangle_function_name PARAMS ((struct work_stuff *, const char **, string *,
44133965Sjdp				const char *));
44233965Sjdp
44368765Sobrienstatic int
44468765Sobrieniterate_demangle_function PARAMS ((struct work_stuff *,
44568765Sobrien				   const char **, string *, const char *));
44668765Sobrien
44733965Sjdpstatic void
44833965Sjdpremember_type PARAMS ((struct work_stuff *, const char *, int));
44933965Sjdp
45033965Sjdpstatic void
45160484Sobrienremember_Btype PARAMS ((struct work_stuff *, const char *, int, int));
45260484Sobrien
45360484Sobrienstatic int
45460484Sobrienregister_Btype PARAMS ((struct work_stuff *));
45560484Sobrien
45660484Sobrienstatic void
45760484Sobrienremember_Ktype PARAMS ((struct work_stuff *, const char *, int));
45860484Sobrien
45960484Sobrienstatic void
46033965Sjdpforget_types PARAMS ((struct work_stuff *));
46133965Sjdp
46233965Sjdpstatic void
46360484Sobrienforget_B_and_K_types PARAMS ((struct work_stuff *));
46460484Sobrien
46560484Sobrienstatic void
46633965Sjdpstring_prepends PARAMS ((string *, string *));
46733965Sjdp
46860484Sobrienstatic int
46960484Sobriendemangle_template_value_parm PARAMS ((struct work_stuff*, const char**,
47060484Sobrien				      string*, type_kind_t));
47133965Sjdp
47233965Sjdpstatic int
47360484Sobriendo_hpacc_template_const_value PARAMS ((struct work_stuff *, const char **, string *));
47460484Sobrien
47560484Sobrienstatic int
47660484Sobriendo_hpacc_template_literal PARAMS ((struct work_stuff *, const char **, string *));
47760484Sobrien
47860484Sobrienstatic int
47960484Sobriensnarf_numeric_literal PARAMS ((const char **, string *));
48060484Sobrien
48160484Sobrien/* There is a TYPE_QUAL value for each type qualifier.  They can be
48260484Sobrien   combined by bitwise-or to form the complete set of qualifiers for a
48360484Sobrien   type.  */
48460484Sobrien
48560484Sobrien#define TYPE_UNQUALIFIED   0x0
48660484Sobrien#define TYPE_QUAL_CONST    0x1
48760484Sobrien#define TYPE_QUAL_VOLATILE 0x2
48860484Sobrien#define TYPE_QUAL_RESTRICT 0x4
48960484Sobrien
49060484Sobrienstatic int
49160484Sobriencode_for_qualifier PARAMS ((int));
49260484Sobrien
49360484Sobrienstatic const char*
49460484Sobrienqualifier_string PARAMS ((int));
49560484Sobrien
49660484Sobrienstatic const char*
49760484Sobriendemangle_qualifier PARAMS ((int));
49860484Sobrien
49960484Sobrienstatic int
50060484Sobriendemangle_expression PARAMS ((struct work_stuff *, const char **, string *,
50160484Sobrien			     type_kind_t));
50260484Sobrien
50360484Sobrienstatic int
50460484Sobriendemangle_integral_value PARAMS ((struct work_stuff *, const char **,
50560484Sobrien				 string *));
50660484Sobrien
50760484Sobrienstatic int
50860484Sobriendemangle_real_value PARAMS ((struct work_stuff *, const char **, string *));
50960484Sobrien
51060484Sobrienstatic void
51160484Sobriendemangle_arm_hp_template PARAMS ((struct work_stuff *, const char **, int,
51260484Sobrien				  string *));
51360484Sobrien
51460484Sobrienstatic void
51560484Sobrienrecursively_demangle PARAMS ((struct work_stuff *, const char **, string *,
51660484Sobrien			      int));
51760484Sobrien
51877298Sobrienstatic void
51977298Sobriengrow_vect PARAMS ((void **, size_t *, size_t, int));
52077298Sobrien
52160484Sobrien/* Translate count to integer, consuming tokens in the process.
52260484Sobrien   Conversion terminates on the first non-digit character.
52360484Sobrien
52460484Sobrien   Trying to consume something that isn't a count results in no
52560484Sobrien   consumption of input and a return of -1.
52660484Sobrien
52760484Sobrien   Overflow consumes the rest of the digits, and returns -1.  */
52860484Sobrien
52960484Sobrienstatic int
53033965Sjdpconsume_count (type)
53133965Sjdp     const char **type;
53233965Sjdp{
53333965Sjdp  int count = 0;
53433965Sjdp
53577298Sobrien  if (! ISDIGIT ((unsigned char)**type))
53660484Sobrien    return -1;
53760484Sobrien
53877298Sobrien  while (ISDIGIT ((unsigned char)**type))
53933965Sjdp    {
54033965Sjdp      count *= 10;
54160484Sobrien
54260484Sobrien      /* Check for overflow.
54360484Sobrien	 We assume that count is represented using two's-complement;
54460484Sobrien	 no power of two is divisible by ten, so if an overflow occurs
54560484Sobrien	 when multiplying by ten, the result will not be a multiple of
54660484Sobrien	 ten.  */
54760484Sobrien      if ((count % 10) != 0)
54860484Sobrien	{
54977298Sobrien	  while (ISDIGIT ((unsigned char) **type))
55060484Sobrien	    (*type)++;
55160484Sobrien	  return -1;
55260484Sobrien	}
55360484Sobrien
55433965Sjdp      count += **type - '0';
55533965Sjdp      (*type)++;
55633965Sjdp    }
55760484Sobrien
55889857Sobrien  if (count < 0)
55989857Sobrien    count = -1;
56089857Sobrien
56133965Sjdp  return (count);
56233965Sjdp}
56333965Sjdp
56438889Sjdp
56560484Sobrien/* Like consume_count, but for counts that are preceded and followed
56638889Sjdp   by '_' if they are greater than 10.  Also, -1 is returned for
56738889Sjdp   failure, since 0 can be a valid value.  */
56838889Sjdp
56938889Sjdpstatic int
57038889Sjdpconsume_count_with_underscores (mangled)
57138889Sjdp     const char **mangled;
57238889Sjdp{
57338889Sjdp  int idx;
57438889Sjdp
57538889Sjdp  if (**mangled == '_')
57638889Sjdp    {
57738889Sjdp      (*mangled)++;
57877298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
57938889Sjdp	return -1;
58038889Sjdp
58138889Sjdp      idx = consume_count (mangled);
58238889Sjdp      if (**mangled != '_')
58338889Sjdp	/* The trailing underscore was missing. */
58438889Sjdp	return -1;
58560484Sobrien
58638889Sjdp      (*mangled)++;
58738889Sjdp    }
58838889Sjdp  else
58938889Sjdp    {
59038889Sjdp      if (**mangled < '0' || **mangled > '9')
59138889Sjdp	return -1;
59260484Sobrien
59338889Sjdp      idx = **mangled - '0';
59438889Sjdp      (*mangled)++;
59538889Sjdp    }
59638889Sjdp
59738889Sjdp  return idx;
59838889Sjdp}
59938889Sjdp
60060484Sobrien/* C is the code for a type-qualifier.  Return the TYPE_QUAL
60160484Sobrien   corresponding to this qualifier.  */
60260484Sobrien
60360484Sobrienstatic int
60460484Sobriencode_for_qualifier (c)
60560484Sobrien  int c;
60660484Sobrien{
60760484Sobrien  switch (c)
60860484Sobrien    {
60960484Sobrien    case 'C':
61060484Sobrien      return TYPE_QUAL_CONST;
61160484Sobrien
61260484Sobrien    case 'V':
61360484Sobrien      return TYPE_QUAL_VOLATILE;
61460484Sobrien
61560484Sobrien    case 'u':
61660484Sobrien      return TYPE_QUAL_RESTRICT;
61760484Sobrien
61860484Sobrien    default:
61960484Sobrien      break;
62060484Sobrien    }
62160484Sobrien
62260484Sobrien  /* C was an invalid qualifier.  */
62360484Sobrien  abort ();
62460484Sobrien}
62560484Sobrien
62660484Sobrien/* Return the string corresponding to the qualifiers given by
62760484Sobrien   TYPE_QUALS.  */
62860484Sobrien
62960484Sobrienstatic const char*
63060484Sobrienqualifier_string (type_quals)
63160484Sobrien     int type_quals;
63260484Sobrien{
63360484Sobrien  switch (type_quals)
63460484Sobrien    {
63560484Sobrien    case TYPE_UNQUALIFIED:
63660484Sobrien      return "";
63760484Sobrien
63860484Sobrien    case TYPE_QUAL_CONST:
63960484Sobrien      return "const";
64060484Sobrien
64160484Sobrien    case TYPE_QUAL_VOLATILE:
64260484Sobrien      return "volatile";
64360484Sobrien
64460484Sobrien    case TYPE_QUAL_RESTRICT:
64560484Sobrien      return "__restrict";
64660484Sobrien
64760484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
64860484Sobrien      return "const volatile";
64960484Sobrien
65060484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
65160484Sobrien      return "const __restrict";
65260484Sobrien
65360484Sobrien    case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
65460484Sobrien      return "volatile __restrict";
65560484Sobrien
65660484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
65760484Sobrien      return "const volatile __restrict";
65860484Sobrien
65960484Sobrien    default:
66060484Sobrien      break;
66160484Sobrien    }
66260484Sobrien
66360484Sobrien  /* TYPE_QUALS was an invalid qualifier set.  */
66460484Sobrien  abort ();
66560484Sobrien}
66660484Sobrien
66760484Sobrien/* C is the code for a type-qualifier.  Return the string
66860484Sobrien   corresponding to this qualifier.  This function should only be
66960484Sobrien   called with a valid qualifier code.  */
67060484Sobrien
67160484Sobrienstatic const char*
67260484Sobriendemangle_qualifier (c)
67360484Sobrien  int c;
67460484Sobrien{
67560484Sobrien  return qualifier_string (code_for_qualifier (c));
67660484Sobrien}
67760484Sobrien
67833965Sjdpint
67933965Sjdpcplus_demangle_opname (opname, result, options)
68033965Sjdp     const char *opname;
68133965Sjdp     char *result;
68233965Sjdp     int options;
68333965Sjdp{
68460484Sobrien  int len, len1, ret;
68533965Sjdp  string type;
68633965Sjdp  struct work_stuff work[1];
68733965Sjdp  const char *tem;
68833965Sjdp
68933965Sjdp  len = strlen(opname);
69033965Sjdp  result[0] = '\0';
69133965Sjdp  ret = 0;
69260484Sobrien  memset ((char *) work, 0, sizeof (work));
69333965Sjdp  work->options = options;
69460484Sobrien
69533965Sjdp  if (opname[0] == '_' && opname[1] == '_'
69633965Sjdp      && opname[2] == 'o' && opname[3] == 'p')
69733965Sjdp    {
69833965Sjdp      /* ANSI.  */
69933965Sjdp      /* type conversion operator.  */
70033965Sjdp      tem = opname + 4;
70133965Sjdp      if (do_type (work, &tem, &type))
70233965Sjdp	{
70333965Sjdp	  strcat (result, "operator ");
70433965Sjdp	  strncat (result, type.b, type.p - type.b);
70533965Sjdp	  string_delete (&type);
70633965Sjdp	  ret = 1;
70733965Sjdp	}
70833965Sjdp    }
70933965Sjdp  else if (opname[0] == '_' && opname[1] == '_'
71077298Sobrien	   && ISLOWER((unsigned char)opname[2])
71177298Sobrien	   && ISLOWER((unsigned char)opname[3]))
71233965Sjdp    {
71333965Sjdp      if (opname[4] == '\0')
71433965Sjdp	{
71533965Sjdp	  /* Operator.  */
71660484Sobrien	  size_t i;
71777298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
71833965Sjdp	    {
71933965Sjdp	      if (strlen (optable[i].in) == 2
72033965Sjdp		  && memcmp (optable[i].in, opname + 2, 2) == 0)
72133965Sjdp		{
72233965Sjdp		  strcat (result, "operator");
72333965Sjdp		  strcat (result, optable[i].out);
72433965Sjdp		  ret = 1;
72533965Sjdp		  break;
72633965Sjdp		}
72733965Sjdp	    }
72833965Sjdp	}
72933965Sjdp      else
73033965Sjdp	{
73133965Sjdp	  if (opname[2] == 'a' && opname[5] == '\0')
73233965Sjdp	    {
73333965Sjdp	      /* Assignment.  */
73460484Sobrien	      size_t i;
73577298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
73633965Sjdp		{
73733965Sjdp		  if (strlen (optable[i].in) == 3
73833965Sjdp		      && memcmp (optable[i].in, opname + 2, 3) == 0)
73933965Sjdp		    {
74033965Sjdp		      strcat (result, "operator");
74133965Sjdp		      strcat (result, optable[i].out);
74233965Sjdp		      ret = 1;
74333965Sjdp		      break;
74460484Sobrien		    }
74533965Sjdp		}
74633965Sjdp	    }
74733965Sjdp	}
74833965Sjdp    }
74960484Sobrien  else if (len >= 3
75033965Sjdp	   && opname[0] == 'o'
75133965Sjdp	   && opname[1] == 'p'
75233965Sjdp	   && strchr (cplus_markers, opname[2]) != NULL)
75333965Sjdp    {
75433965Sjdp      /* see if it's an assignment expression */
75533965Sjdp      if (len >= 10 /* op$assign_ */
75633965Sjdp	  && memcmp (opname + 3, "assign_", 7) == 0)
75733965Sjdp	{
75860484Sobrien	  size_t i;
75977298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
76033965Sjdp	    {
76133965Sjdp	      len1 = len - 10;
76260484Sobrien	      if ((int) strlen (optable[i].in) == len1
76333965Sjdp		  && memcmp (optable[i].in, opname + 10, len1) == 0)
76433965Sjdp		{
76533965Sjdp		  strcat (result, "operator");
76633965Sjdp		  strcat (result, optable[i].out);
76733965Sjdp		  strcat (result, "=");
76833965Sjdp		  ret = 1;
76933965Sjdp		  break;
77033965Sjdp		}
77133965Sjdp	    }
77233965Sjdp	}
77333965Sjdp      else
77433965Sjdp	{
77560484Sobrien	  size_t i;
77677298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
77733965Sjdp	    {
77833965Sjdp	      len1 = len - 3;
77960484Sobrien	      if ((int) strlen (optable[i].in) == len1
78033965Sjdp		  && memcmp (optable[i].in, opname + 3, len1) == 0)
78133965Sjdp		{
78233965Sjdp		  strcat (result, "operator");
78333965Sjdp		  strcat (result, optable[i].out);
78433965Sjdp		  ret = 1;
78533965Sjdp		  break;
78633965Sjdp		}
78733965Sjdp	    }
78833965Sjdp	}
78933965Sjdp    }
79033965Sjdp  else if (len >= 5 && memcmp (opname, "type", 4) == 0
79133965Sjdp	   && strchr (cplus_markers, opname[4]) != NULL)
79233965Sjdp    {
79333965Sjdp      /* type conversion operator */
79433965Sjdp      tem = opname + 5;
79533965Sjdp      if (do_type (work, &tem, &type))
79633965Sjdp	{
79733965Sjdp	  strcat (result, "operator ");
79833965Sjdp	  strncat (result, type.b, type.p - type.b);
79933965Sjdp	  string_delete (&type);
80033965Sjdp	  ret = 1;
80133965Sjdp	}
80233965Sjdp    }
80360484Sobrien  squangle_mop_up (work);
80433965Sjdp  return ret;
80533965Sjdp
80633965Sjdp}
80768765Sobrien
80833965Sjdp/* Takes operator name as e.g. "++" and returns mangled
80933965Sjdp   operator name (e.g. "postincrement_expr"), or NULL if not found.
81033965Sjdp
81133965Sjdp   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
81233965Sjdp   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
81333965Sjdp
81433965Sjdpconst char *
81533965Sjdpcplus_mangle_opname (opname, options)
81633965Sjdp     const char *opname;
81733965Sjdp     int options;
81833965Sjdp{
81960484Sobrien  size_t i;
82033965Sjdp  int len;
82133965Sjdp
82233965Sjdp  len = strlen (opname);
82377298Sobrien  for (i = 0; i < ARRAY_SIZE (optable); i++)
82433965Sjdp    {
82560484Sobrien      if ((int) strlen (optable[i].out) == len
82633965Sjdp	  && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
82733965Sjdp	  && memcmp (optable[i].out, opname, len) == 0)
82833965Sjdp	return optable[i].in;
82933965Sjdp    }
83033965Sjdp  return (0);
83133965Sjdp}
83233965Sjdp
83368765Sobrien/* Add a routine to set the demangling style to be sure it is valid and
83468765Sobrien   allow for any demangler initialization that maybe necessary. */
83568765Sobrien
83668765Sobrienenum demangling_styles
83768765Sobriencplus_demangle_set_style (style)
83868765Sobrien     enum demangling_styles style;
83968765Sobrien{
84089857Sobrien  const struct demangler_engine *demangler = libiberty_demanglers;
84168765Sobrien
84268765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
84368765Sobrien    if (style == demangler->demangling_style)
84468765Sobrien      {
84568765Sobrien	current_demangling_style = style;
84668765Sobrien	return current_demangling_style;
84768765Sobrien      }
84868765Sobrien
84968765Sobrien  return unknown_demangling;
85068765Sobrien}
85168765Sobrien
85268765Sobrien/* Do string name to style translation */
85368765Sobrien
85468765Sobrienenum demangling_styles
85568765Sobriencplus_demangle_name_to_style (name)
85668765Sobrien     const char *name;
85768765Sobrien{
85889857Sobrien  const struct demangler_engine *demangler = libiberty_demanglers;
85968765Sobrien
86068765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
86168765Sobrien    if (strcmp (name, demangler->demangling_style_name) == 0)
86268765Sobrien      return demangler->demangling_style;
86368765Sobrien
86468765Sobrien  return unknown_demangling;
86568765Sobrien}
86668765Sobrien
86733965Sjdp/* char *cplus_demangle (const char *mangled, int options)
86833965Sjdp
86933965Sjdp   If MANGLED is a mangled function name produced by GNU C++, then
87089857Sobrien   a pointer to a @code{malloc}ed string giving a C++ representation
87133965Sjdp   of the name will be returned; otherwise NULL will be returned.
87233965Sjdp   It is the caller's responsibility to free the string which
87333965Sjdp   is returned.
87433965Sjdp
87533965Sjdp   The OPTIONS arg may contain one or more of the following bits:
87633965Sjdp
87733965Sjdp   	DMGL_ANSI	ANSI qualifiers such as `const' and `void' are
87833965Sjdp			included.
87933965Sjdp	DMGL_PARAMS	Function parameters are included.
88033965Sjdp
88133965Sjdp   For example,
88260484Sobrien
88333965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS)		=> "A::foo(int)"
88433965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)	=> "A::foo(int)"
88533965Sjdp   cplus_demangle ("foo__1Ai", 0)			=> "A::foo"
88633965Sjdp
88733965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS)		=> "A::foo(float,...)"
88833965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
88933965Sjdp   cplus_demangle ("foo__1Afe", 0)			=> "A::foo"
89033965Sjdp
89133965Sjdp   Note that any leading underscores, or other such characters prepended by
89233965Sjdp   the compilation system, are presumed to have already been stripped from
89333965Sjdp   MANGLED.  */
89433965Sjdp
89533965Sjdpchar *
89633965Sjdpcplus_demangle (mangled, options)
89733965Sjdp     const char *mangled;
89833965Sjdp     int options;
89933965Sjdp{
90060484Sobrien  char *ret;
90160484Sobrien  struct work_stuff work[1];
90289857Sobrien
90389857Sobrien  if (current_demangling_style == no_demangling)
90489857Sobrien    return xstrdup (mangled);
90589857Sobrien
90660484Sobrien  memset ((char *) work, 0, sizeof (work));
90777298Sobrien  work->options = options;
90877298Sobrien  if ((work->options & DMGL_STYLE_MASK) == 0)
90977298Sobrien    work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
91060484Sobrien
91177298Sobrien  /* The V3 ABI demangling is implemented elsewhere.  */
91277298Sobrien  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
91377298Sobrien    {
91491041Sobrien      ret = cplus_demangle_v3 (mangled, work->options);
91577298Sobrien      if (ret || GNU_V3_DEMANGLING)
91677298Sobrien	return ret;
91777298Sobrien    }
91868765Sobrien
91989857Sobrien  if (JAVA_DEMANGLING)
92089857Sobrien    {
92189857Sobrien      ret = java_demangle_v3 (mangled);
92289857Sobrien      if (ret)
92389857Sobrien        return ret;
92489857Sobrien    }
92589857Sobrien
92677298Sobrien  if (GNAT_DEMANGLING)
92777298Sobrien    return ada_demangle(mangled,options);
92877298Sobrien
92960484Sobrien  ret = internal_cplus_demangle (work, mangled);
93060484Sobrien  squangle_mop_up (work);
93160484Sobrien  return (ret);
93260484Sobrien}
93360484Sobrien
93460484Sobrien
93577298Sobrien/* Assuming *OLD_VECT points to an array of *SIZE objects of size
93677298Sobrien   ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
93777298Sobrien   updating *OLD_VECT and *SIZE as necessary.  */
93877298Sobrien
93977298Sobrienstatic void
94077298Sobriengrow_vect (old_vect, size, min_size, element_size)
94177298Sobrien     void **old_vect;
94277298Sobrien     size_t *size;
94377298Sobrien     size_t min_size;
94477298Sobrien     int element_size;
94577298Sobrien{
94677298Sobrien  if (*size < min_size)
94777298Sobrien    {
94877298Sobrien      *size *= 2;
94977298Sobrien      if (*size < min_size)
95077298Sobrien	*size = min_size;
95177298Sobrien      *old_vect = xrealloc (*old_vect, *size * element_size);
95277298Sobrien    }
95377298Sobrien}
95477298Sobrien
95577298Sobrien/* Demangle ada names:
95677298Sobrien   1. Discard final __{DIGIT}+ or ${DIGIT}+
95777298Sobrien   2. Convert other instances of embedded "__" to `.'.
95877298Sobrien   3. Discard leading _ada_.
95977298Sobrien   4. Remove everything after first ___ if it is followed by 'X'.
96077298Sobrien   5. Put symbols that should be suppressed in <...> brackets.
96177298Sobrien   The resulting string is valid until the next call of ada_demangle.  */
96277298Sobrien
96377298Sobrienstatic char *
96477298Sobrienada_demangle (mangled, option)
96577298Sobrien     const char *mangled;
96677298Sobrien     int option ATTRIBUTE_UNUSED;
96777298Sobrien{
96877298Sobrien  int i, j;
96977298Sobrien  int len0;
97077298Sobrien  const char* p;
97177298Sobrien  char *demangled = NULL;
97277298Sobrien  int at_start_name;
97377298Sobrien  int changed;
97477298Sobrien  char *demangling_buffer = NULL;
97577298Sobrien  size_t demangling_buffer_size = 0;
97677298Sobrien
97777298Sobrien  changed = 0;
97877298Sobrien
97977298Sobrien  if (strncmp (mangled, "_ada_", 5) == 0)
98077298Sobrien    {
98177298Sobrien      mangled += 5;
98277298Sobrien      changed = 1;
98377298Sobrien    }
98477298Sobrien
98577298Sobrien  if (mangled[0] == '_' || mangled[0] == '<')
98677298Sobrien    goto Suppress;
98777298Sobrien
98877298Sobrien  p = strstr (mangled, "___");
98977298Sobrien  if (p == NULL)
99077298Sobrien    len0 = strlen (mangled);
99177298Sobrien  else
99277298Sobrien    {
99377298Sobrien      if (p[3] == 'X')
99477298Sobrien	{
99577298Sobrien	  len0 = p - mangled;
99677298Sobrien	  changed = 1;
99777298Sobrien	}
99877298Sobrien      else
99977298Sobrien	goto Suppress;
100077298Sobrien    }
100177298Sobrien
100277298Sobrien  /* Make demangled big enough for possible expansion by operator name.  */
100377298Sobrien  grow_vect ((void **) &(demangling_buffer),
100477298Sobrien	     &demangling_buffer_size,  2 * len0 + 1,
100577298Sobrien	     sizeof (char));
100677298Sobrien  demangled = demangling_buffer;
100777298Sobrien
100877298Sobrien  if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
100977298Sobrien    for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
101077298Sobrien      ;
101177298Sobrien    if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
101277298Sobrien      {
101377298Sobrien	len0 = i - 1;
101477298Sobrien	changed = 1;
101577298Sobrien      }
101677298Sobrien    else if (mangled[i] == '$')
101777298Sobrien      {
101877298Sobrien	len0 = i;
101977298Sobrien	changed = 1;
102077298Sobrien      }
102177298Sobrien  }
102277298Sobrien
102377298Sobrien  for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
102477298Sobrien       i += 1, j += 1)
102577298Sobrien    demangled[j] = mangled[i];
102677298Sobrien
102777298Sobrien  at_start_name = 1;
102877298Sobrien  while (i < len0)
102977298Sobrien    {
103077298Sobrien      at_start_name = 0;
103177298Sobrien
103277298Sobrien      if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
103377298Sobrien	{
103477298Sobrien	  demangled[j] = '.';
103577298Sobrien	  changed = at_start_name = 1;
103677298Sobrien	  i += 2; j += 1;
103777298Sobrien	}
103877298Sobrien      else
103977298Sobrien	{
104077298Sobrien	  demangled[j] = mangled[i];
104177298Sobrien	  i += 1;  j += 1;
104277298Sobrien	}
104377298Sobrien    }
104477298Sobrien  demangled[j] = '\000';
104577298Sobrien
104677298Sobrien  for (i = 0; demangled[i] != '\0'; i += 1)
104777298Sobrien    if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
104877298Sobrien      goto Suppress;
104977298Sobrien
105077298Sobrien  if (! changed)
105177298Sobrien    return NULL;
105277298Sobrien  else
105377298Sobrien    return demangled;
105477298Sobrien
105577298Sobrien Suppress:
105677298Sobrien  grow_vect ((void **) &(demangling_buffer),
105777298Sobrien	     &demangling_buffer_size,  strlen (mangled) + 3,
105877298Sobrien	     sizeof (char));
105977298Sobrien  demangled = demangling_buffer;
106077298Sobrien  if (mangled[0] == '<')
106177298Sobrien     strcpy (demangled, mangled);
106277298Sobrien  else
106377298Sobrien    sprintf (demangled, "<%s>", mangled);
106477298Sobrien
106577298Sobrien  return demangled;
106677298Sobrien}
106777298Sobrien
106860484Sobrien/* This function performs most of what cplus_demangle use to do, but
106960484Sobrien   to be able to demangle a name with a B, K or n code, we need to
107060484Sobrien   have a longer term memory of what types have been seen. The original
107160484Sobrien   now intializes and cleans up the squangle code info, while internal
107260484Sobrien   calls go directly to this routine to avoid resetting that info. */
107360484Sobrien
107460484Sobrienstatic char *
107560484Sobrieninternal_cplus_demangle (work, mangled)
107660484Sobrien     struct work_stuff *work;
107760484Sobrien     const char *mangled;
107860484Sobrien{
107960484Sobrien
108033965Sjdp  string decl;
108133965Sjdp  int success = 0;
108233965Sjdp  char *demangled = NULL;
108377298Sobrien  int s1, s2, s3, s4;
108460484Sobrien  s1 = work->constructor;
108560484Sobrien  s2 = work->destructor;
108660484Sobrien  s3 = work->static_type;
108760484Sobrien  s4 = work->type_quals;
108860484Sobrien  work->constructor = work->destructor = 0;
108960484Sobrien  work->type_quals = TYPE_UNQUALIFIED;
109060484Sobrien  work->dllimported = 0;
109133965Sjdp
109233965Sjdp  if ((mangled != NULL) && (*mangled != '\0'))
109333965Sjdp    {
109433965Sjdp      string_init (&decl);
109533965Sjdp
109633965Sjdp      /* First check to see if gnu style demangling is active and if the
109733965Sjdp	 string to be demangled contains a CPLUS_MARKER.  If so, attempt to
109833965Sjdp	 recognize one of the gnu special forms rather than looking for a
109933965Sjdp	 standard prefix.  In particular, don't worry about whether there
110033965Sjdp	 is a "__" string in the mangled string.  Consider "_$_5__foo" for
110133965Sjdp	 example.  */
110233965Sjdp
110333965Sjdp      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
110433965Sjdp	{
110533965Sjdp	  success = gnu_special (work, &mangled, &decl);
110633965Sjdp	}
110733965Sjdp      if (!success)
110833965Sjdp	{
110933965Sjdp	  success = demangle_prefix (work, &mangled, &decl);
111033965Sjdp	}
111133965Sjdp      if (success && (*mangled != '\0'))
111233965Sjdp	{
111333965Sjdp	  success = demangle_signature (work, &mangled, &decl);
111433965Sjdp	}
111533965Sjdp      if (work->constructor == 2)
111633965Sjdp        {
111760484Sobrien          string_prepend (&decl, "global constructors keyed to ");
111833965Sjdp          work->constructor = 0;
111933965Sjdp        }
112033965Sjdp      else if (work->destructor == 2)
112133965Sjdp        {
112260484Sobrien          string_prepend (&decl, "global destructors keyed to ");
112333965Sjdp          work->destructor = 0;
112433965Sjdp        }
112560484Sobrien      else if (work->dllimported == 1)
112660484Sobrien        {
112760484Sobrien          string_prepend (&decl, "import stub for ");
112860484Sobrien          work->dllimported = 0;
112960484Sobrien        }
113033965Sjdp      demangled = mop_up (work, &decl, success);
113133965Sjdp    }
113260484Sobrien  work->constructor = s1;
113360484Sobrien  work->destructor = s2;
113460484Sobrien  work->static_type = s3;
113560484Sobrien  work->type_quals = s4;
113677298Sobrien  return demangled;
113733965Sjdp}
113833965Sjdp
113960484Sobrien
114060484Sobrien/* Clear out and squangling related storage */
114160484Sobrienstatic void
114260484Sobriensquangle_mop_up (work)
114360484Sobrien     struct work_stuff *work;
114460484Sobrien{
114560484Sobrien  /* clean up the B and K type mangling types. */
114660484Sobrien  forget_B_and_K_types (work);
114760484Sobrien  if (work -> btypevec != NULL)
114860484Sobrien    {
114960484Sobrien      free ((char *) work -> btypevec);
115060484Sobrien    }
115160484Sobrien  if (work -> ktypevec != NULL)
115260484Sobrien    {
115360484Sobrien      free ((char *) work -> ktypevec);
115460484Sobrien    }
115560484Sobrien}
115660484Sobrien
115760484Sobrien
115868765Sobrien/* Copy the work state and storage.  */
115968765Sobrien
116068765Sobrienstatic void
116168765Sobrienwork_stuff_copy_to_from (to, from)
116268765Sobrien     struct work_stuff *to;
116368765Sobrien     struct work_stuff *from;
116468765Sobrien{
116568765Sobrien  int i;
116668765Sobrien
116768765Sobrien  delete_work_stuff (to);
116868765Sobrien
116968765Sobrien  /* Shallow-copy scalars.  */
117068765Sobrien  memcpy (to, from, sizeof (*to));
117168765Sobrien
117268765Sobrien  /* Deep-copy dynamic storage.  */
117368765Sobrien  if (from->typevec_size)
117468765Sobrien    to->typevec
117568765Sobrien      = (char **) xmalloc (from->typevec_size * sizeof (to->typevec[0]));
117668765Sobrien
117768765Sobrien  for (i = 0; i < from->ntypes; i++)
117868765Sobrien    {
117968765Sobrien      int len = strlen (from->typevec[i]) + 1;
118068765Sobrien
118168765Sobrien      to->typevec[i] = xmalloc (len);
118268765Sobrien      memcpy (to->typevec[i], from->typevec[i], len);
118368765Sobrien    }
118468765Sobrien
118568765Sobrien  if (from->ksize)
118668765Sobrien    to->ktypevec
118768765Sobrien      = (char **) xmalloc (from->ksize * sizeof (to->ktypevec[0]));
118868765Sobrien
118968765Sobrien  for (i = 0; i < from->numk; i++)
119068765Sobrien    {
119168765Sobrien      int len = strlen (from->ktypevec[i]) + 1;
119268765Sobrien
119368765Sobrien      to->ktypevec[i] = xmalloc (len);
119468765Sobrien      memcpy (to->ktypevec[i], from->ktypevec[i], len);
119568765Sobrien    }
119668765Sobrien
119768765Sobrien  if (from->bsize)
119868765Sobrien    to->btypevec
119968765Sobrien      = (char **) xmalloc (from->bsize * sizeof (to->btypevec[0]));
120068765Sobrien
120168765Sobrien  for (i = 0; i < from->numb; i++)
120268765Sobrien    {
120368765Sobrien      int len = strlen (from->btypevec[i]) + 1;
120468765Sobrien
120568765Sobrien      to->btypevec[i] = xmalloc (len);
120668765Sobrien      memcpy (to->btypevec[i], from->btypevec[i], len);
120768765Sobrien    }
120868765Sobrien
120968765Sobrien  if (from->ntmpl_args)
121068765Sobrien    to->tmpl_argvec
121168765Sobrien      = xmalloc (from->ntmpl_args * sizeof (to->tmpl_argvec[0]));
121268765Sobrien
121368765Sobrien  for (i = 0; i < from->ntmpl_args; i++)
121468765Sobrien    {
121568765Sobrien      int len = strlen (from->tmpl_argvec[i]) + 1;
121668765Sobrien
121768765Sobrien      to->tmpl_argvec[i] = xmalloc (len);
121868765Sobrien      memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
121968765Sobrien    }
122068765Sobrien
122168765Sobrien  if (from->previous_argument)
122268765Sobrien    {
122368765Sobrien      to->previous_argument = (string*) xmalloc (sizeof (string));
122468765Sobrien      string_init (to->previous_argument);
122568765Sobrien      string_appends (to->previous_argument, from->previous_argument);
122668765Sobrien    }
122768765Sobrien}
122868765Sobrien
122968765Sobrien
123068765Sobrien/* Delete dynamic stuff in work_stuff that is not to be re-used.  */
123168765Sobrien
123268765Sobrienstatic void
123368765Sobriendelete_non_B_K_work_stuff (work)
123433965Sjdp     struct work_stuff *work;
123533965Sjdp{
123633965Sjdp  /* Discard the remembered types, if any.  */
123760484Sobrien
123833965Sjdp  forget_types (work);
123933965Sjdp  if (work -> typevec != NULL)
124033965Sjdp    {
124133965Sjdp      free ((char *) work -> typevec);
124260484Sobrien      work -> typevec = NULL;
124360484Sobrien      work -> typevec_size = 0;
124433965Sjdp    }
124538889Sjdp  if (work->tmpl_argvec)
124638889Sjdp    {
124738889Sjdp      int i;
124838889Sjdp
124938889Sjdp      for (i = 0; i < work->ntmpl_args; i++)
125038889Sjdp	if (work->tmpl_argvec[i])
125138889Sjdp	  free ((char*) work->tmpl_argvec[i]);
125260484Sobrien
125338889Sjdp      free ((char*) work->tmpl_argvec);
125460484Sobrien      work->tmpl_argvec = NULL;
125538889Sjdp    }
125660484Sobrien  if (work->previous_argument)
125760484Sobrien    {
125860484Sobrien      string_delete (work->previous_argument);
125960484Sobrien      free ((char*) work->previous_argument);
126060484Sobrien      work->previous_argument = NULL;
126160484Sobrien    }
126268765Sobrien}
126338889Sjdp
126468765Sobrien
126568765Sobrien/* Delete all dynamic storage in work_stuff.  */
126668765Sobrienstatic void
126768765Sobriendelete_work_stuff (work)
126868765Sobrien     struct work_stuff *work;
126968765Sobrien{
127068765Sobrien  delete_non_B_K_work_stuff (work);
127168765Sobrien  squangle_mop_up (work);
127268765Sobrien}
127368765Sobrien
127468765Sobrien
127568765Sobrien/* Clear out any mangled storage */
127668765Sobrien
127768765Sobrienstatic char *
127868765Sobrienmop_up (work, declp, success)
127968765Sobrien     struct work_stuff *work;
128068765Sobrien     string *declp;
128168765Sobrien     int success;
128268765Sobrien{
128368765Sobrien  char *demangled = NULL;
128468765Sobrien
128568765Sobrien  delete_non_B_K_work_stuff (work);
128668765Sobrien
128733965Sjdp  /* If demangling was successful, ensure that the demangled string is null
128833965Sjdp     terminated and return it.  Otherwise, free the demangling decl.  */
128960484Sobrien
129033965Sjdp  if (!success)
129133965Sjdp    {
129233965Sjdp      string_delete (declp);
129333965Sjdp    }
129433965Sjdp  else
129533965Sjdp    {
129633965Sjdp      string_appendn (declp, "", 1);
129777298Sobrien      demangled = declp->b;
129833965Sjdp    }
129933965Sjdp  return (demangled);
130033965Sjdp}
130133965Sjdp
130233965Sjdp/*
130333965Sjdp
130433965SjdpLOCAL FUNCTION
130533965Sjdp
130633965Sjdp	demangle_signature -- demangle the signature part of a mangled name
130733965Sjdp
130833965SjdpSYNOPSIS
130933965Sjdp
131033965Sjdp	static int
131133965Sjdp	demangle_signature (struct work_stuff *work, const char **mangled,
131233965Sjdp			    string *declp);
131333965Sjdp
131433965SjdpDESCRIPTION
131533965Sjdp
131633965Sjdp	Consume and demangle the signature portion of the mangled name.
131733965Sjdp
131833965Sjdp	DECLP is the string where demangled output is being built.  At
131933965Sjdp	entry it contains the demangled root name from the mangled name
132033965Sjdp	prefix.  I.E. either a demangled operator name or the root function
132133965Sjdp	name.  In some special cases, it may contain nothing.
132233965Sjdp
132333965Sjdp	*MANGLED points to the current unconsumed location in the mangled
132433965Sjdp	name.  As tokens are consumed and demangling is performed, the
132533965Sjdp	pointer is updated to continuously point at the next token to
132633965Sjdp	be consumed.
132733965Sjdp
132833965Sjdp	Demangling GNU style mangled names is nasty because there is no
132933965Sjdp	explicit token that marks the start of the outermost function
133033965Sjdp	argument list.  */
133133965Sjdp
133233965Sjdpstatic int
133333965Sjdpdemangle_signature (work, mangled, declp)
133433965Sjdp     struct work_stuff *work;
133533965Sjdp     const char **mangled;
133633965Sjdp     string *declp;
133733965Sjdp{
133833965Sjdp  int success = 1;
133933965Sjdp  int func_done = 0;
134033965Sjdp  int expect_func = 0;
134138889Sjdp  int expect_return_type = 0;
134233965Sjdp  const char *oldmangled = NULL;
134333965Sjdp  string trawname;
134433965Sjdp  string tname;
134533965Sjdp
134633965Sjdp  while (success && (**mangled != '\0'))
134733965Sjdp    {
134833965Sjdp      switch (**mangled)
134933965Sjdp	{
135033965Sjdp	case 'Q':
135133965Sjdp	  oldmangled = *mangled;
135233965Sjdp	  success = demangle_qualified (work, mangled, declp, 1, 0);
135333965Sjdp	  if (success)
135460484Sobrien	    remember_type (work, oldmangled, *mangled - oldmangled);
135533965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
135660484Sobrien	    expect_func = 1;
135760484Sobrien	  oldmangled = NULL;
135860484Sobrien	  break;
135960484Sobrien
136060484Sobrien        case 'K':
136160484Sobrien	  oldmangled = *mangled;
136260484Sobrien	  success = demangle_qualified (work, mangled, declp, 1, 0);
136360484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
136433965Sjdp	    {
136533965Sjdp	      expect_func = 1;
136633965Sjdp	    }
136733965Sjdp	  oldmangled = NULL;
136833965Sjdp	  break;
136960484Sobrien
137033965Sjdp	case 'S':
137133965Sjdp	  /* Static member function */
137233965Sjdp	  if (oldmangled == NULL)
137333965Sjdp	    {
137433965Sjdp	      oldmangled = *mangled;
137533965Sjdp	    }
137633965Sjdp	  (*mangled)++;
137733965Sjdp	  work -> static_type = 1;
137833965Sjdp	  break;
137933965Sjdp
138033965Sjdp	case 'C':
138160484Sobrien	case 'V':
138260484Sobrien	case 'u':
138360484Sobrien	  work->type_quals |= code_for_qualifier (**mangled);
138460484Sobrien
138560484Sobrien	  /* a qualified member function */
138633965Sjdp	  if (oldmangled == NULL)
138760484Sobrien	    oldmangled = *mangled;
138860484Sobrien	  (*mangled)++;
138960484Sobrien	  break;
139060484Sobrien
139160484Sobrien	case 'L':
139260484Sobrien	  /* Local class name follows after "Lnnn_" */
139360484Sobrien	  if (HP_DEMANGLING)
139433965Sjdp	    {
139560484Sobrien	      while (**mangled && (**mangled != '_'))
139660484Sobrien		(*mangled)++;
139760484Sobrien	      if (!**mangled)
139860484Sobrien		success = 0;
139960484Sobrien	      else
140060484Sobrien		(*mangled)++;
140133965Sjdp	    }
140260484Sobrien	  else
140360484Sobrien	    success = 0;
140433965Sjdp	  break;
140560484Sobrien
140633965Sjdp	case '0': case '1': case '2': case '3': case '4':
140733965Sjdp	case '5': case '6': case '7': case '8': case '9':
140833965Sjdp	  if (oldmangled == NULL)
140933965Sjdp	    {
141033965Sjdp	      oldmangled = *mangled;
141133965Sjdp	    }
141260484Sobrien          work->temp_start = -1; /* uppermost call to demangle_class */
141333965Sjdp	  success = demangle_class (work, mangled, declp);
141433965Sjdp	  if (success)
141533965Sjdp	    {
141633965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
141733965Sjdp	    }
141860484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
141933965Sjdp	    {
142060484Sobrien              /* EDG and others will have the "F", so we let the loop cycle
142160484Sobrien                 if we are looking at one. */
142260484Sobrien              if (**mangled != 'F')
142360484Sobrien                 expect_func = 1;
142433965Sjdp	    }
142533965Sjdp	  oldmangled = NULL;
142633965Sjdp	  break;
142760484Sobrien
142860484Sobrien	case 'B':
142960484Sobrien	  {
143060484Sobrien	    string s;
143160484Sobrien	    success = do_type (work, mangled, &s);
143260484Sobrien	    if (success)
143360484Sobrien	      {
143460484Sobrien		string_append (&s, SCOPE_STRING (work));
143560484Sobrien		string_prepends (declp, &s);
143660484Sobrien	      }
143760484Sobrien	    oldmangled = NULL;
143860484Sobrien	    expect_func = 1;
143960484Sobrien	  }
144060484Sobrien	  break;
144160484Sobrien
144233965Sjdp	case 'F':
144333965Sjdp	  /* Function */
144460484Sobrien	  /* ARM/HP style demangling includes a specific 'F' character after
144533965Sjdp	     the class name.  For GNU style, it is just implied.  So we can
144633965Sjdp	     safely just consume any 'F' at this point and be compatible
144733965Sjdp	     with either style.  */
144833965Sjdp
144933965Sjdp	  oldmangled = NULL;
145033965Sjdp	  func_done = 1;
145133965Sjdp	  (*mangled)++;
145233965Sjdp
145360484Sobrien	  /* For lucid/ARM/HP style we have to forget any types we might
145433965Sjdp	     have remembered up to this point, since they were not argument
145533965Sjdp	     types.  GNU style considers all types seen as available for
145633965Sjdp	     back references.  See comment in demangle_args() */
145733965Sjdp
145860484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
145933965Sjdp	    {
146033965Sjdp	      forget_types (work);
146133965Sjdp	    }
146233965Sjdp	  success = demangle_args (work, mangled, declp);
146360484Sobrien	  /* After picking off the function args, we expect to either
146460484Sobrien	     find the function return type (preceded by an '_') or the
146560484Sobrien	     end of the string. */
146660484Sobrien	  if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
146760484Sobrien	    {
146860484Sobrien	      ++(*mangled);
146960484Sobrien              /* At this level, we do not care about the return type. */
147060484Sobrien              success = do_type (work, mangled, &tname);
147160484Sobrien              string_delete (&tname);
147260484Sobrien            }
147360484Sobrien
147433965Sjdp	  break;
147560484Sobrien
147633965Sjdp	case 't':
147733965Sjdp	  /* G++ Template */
147860484Sobrien	  string_init(&trawname);
147933965Sjdp	  string_init(&tname);
148033965Sjdp	  if (oldmangled == NULL)
148133965Sjdp	    {
148233965Sjdp	      oldmangled = *mangled;
148333965Sjdp	    }
148460484Sobrien	  success = demangle_template (work, mangled, &tname,
148560484Sobrien				       &trawname, 1, 1);
148633965Sjdp	  if (success)
148733965Sjdp	    {
148833965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
148933965Sjdp	    }
149060484Sobrien	  string_append (&tname, SCOPE_STRING (work));
149160484Sobrien
149233965Sjdp	  string_prepends(declp, &tname);
149333965Sjdp	  if (work -> destructor & 1)
149433965Sjdp	    {
149533965Sjdp	      string_prepend (&trawname, "~");
149633965Sjdp	      string_appends (declp, &trawname);
149733965Sjdp	      work->destructor -= 1;
149833965Sjdp	    }
149933965Sjdp	  if ((work->constructor & 1) || (work->destructor & 1))
150033965Sjdp	    {
150133965Sjdp	      string_appends (declp, &trawname);
150233965Sjdp	      work->constructor -= 1;
150333965Sjdp	    }
150433965Sjdp	  string_delete(&trawname);
150533965Sjdp	  string_delete(&tname);
150633965Sjdp	  oldmangled = NULL;
150733965Sjdp	  expect_func = 1;
150833965Sjdp	  break;
150933965Sjdp
151033965Sjdp	case '_':
151168765Sobrien	  if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
151238889Sjdp	    {
151338889Sjdp	      /* Read the return type. */
151438889Sjdp	      string return_type;
151538889Sjdp	      string_init (&return_type);
151638889Sjdp
151738889Sjdp	      (*mangled)++;
151838889Sjdp	      success = do_type (work, mangled, &return_type);
151938889Sjdp	      APPEND_BLANK (&return_type);
152038889Sjdp
152138889Sjdp	      string_prepends (declp, &return_type);
152238889Sjdp	      string_delete (&return_type);
152338889Sjdp	      break;
152438889Sjdp	    }
152538889Sjdp	  else
152638889Sjdp	    /* At the outermost level, we cannot have a return type specified,
152738889Sjdp	       so if we run into another '_' at this point we are dealing with
152838889Sjdp	       a mangled name that is either bogus, or has been mangled by
152938889Sjdp	       some algorithm we don't know how to deal with.  So just
153038889Sjdp	       reject the entire demangling.  */
153160484Sobrien            /* However, "_nnn" is an expected suffix for alternate entry point
153260484Sobrien               numbered nnn for a function, with HP aCC, so skip over that
153360484Sobrien               without reporting failure. pai/1997-09-04 */
153460484Sobrien            if (HP_DEMANGLING)
153560484Sobrien              {
153660484Sobrien                (*mangled)++;
153777298Sobrien                while (**mangled && ISDIGIT ((unsigned char)**mangled))
153860484Sobrien                  (*mangled)++;
153960484Sobrien              }
154060484Sobrien            else
154160484Sobrien	      success = 0;
154233965Sjdp	  break;
154333965Sjdp
154438889Sjdp	case 'H':
154568765Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
154638889Sjdp	    {
154738889Sjdp	      /* A G++ template function.  Read the template arguments. */
154860484Sobrien	      success = demangle_template (work, mangled, declp, 0, 0,
154960484Sobrien					   0);
155038889Sjdp	      if (!(work->constructor & 1))
155138889Sjdp		expect_return_type = 1;
155238889Sjdp	      (*mangled)++;
155338889Sjdp	      break;
155438889Sjdp	    }
155538889Sjdp	  else
155638889Sjdp	    /* fall through */
155760484Sobrien	    {;}
155838889Sjdp
155933965Sjdp	default:
156033965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
156133965Sjdp	    {
156233965Sjdp	      /* Assume we have stumbled onto the first outermost function
156333965Sjdp		 argument token, and start processing args.  */
156433965Sjdp	      func_done = 1;
156533965Sjdp	      success = demangle_args (work, mangled, declp);
156633965Sjdp	    }
156733965Sjdp	  else
156833965Sjdp	    {
156933965Sjdp	      /* Non-GNU demanglers use a specific token to mark the start
157033965Sjdp		 of the outermost function argument tokens.  Typically 'F',
157160484Sobrien		 for ARM/HP-demangling, for example.  So if we find something
157233965Sjdp		 we are not prepared for, it must be an error.  */
157333965Sjdp	      success = 0;
157433965Sjdp	    }
157533965Sjdp	  break;
157633965Sjdp	}
157733965Sjdp      /*
157833965Sjdp	if (AUTO_DEMANGLING || GNU_DEMANGLING)
157933965Sjdp	*/
158033965Sjdp      {
158133965Sjdp	if (success && expect_func)
158233965Sjdp	  {
158333965Sjdp	    func_done = 1;
158460484Sobrien              if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
158560484Sobrien                {
158660484Sobrien                  forget_types (work);
158760484Sobrien                }
158833965Sjdp	    success = demangle_args (work, mangled, declp);
158938889Sjdp	    /* Since template include the mangling of their return types,
159038889Sjdp	       we must set expect_func to 0 so that we don't try do
159138889Sjdp	       demangle more arguments the next time we get here.  */
159238889Sjdp	    expect_func = 0;
159333965Sjdp	  }
159433965Sjdp      }
159533965Sjdp    }
159633965Sjdp  if (success && !func_done)
159733965Sjdp    {
159833965Sjdp      if (AUTO_DEMANGLING || GNU_DEMANGLING)
159933965Sjdp	{
160033965Sjdp	  /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
160133965Sjdp	     bar__3fooi is 'foo::bar(int)'.  We get here when we find the
160233965Sjdp	     first case, and need to ensure that the '(void)' gets added to
160360484Sobrien	     the current declp.  Note that with ARM/HP, the first case
160433965Sjdp	     represents the name of a static data member 'foo::bar',
160533965Sjdp	     which is in the current declp, so we leave it alone.  */
160633965Sjdp	  success = demangle_args (work, mangled, declp);
160733965Sjdp	}
160833965Sjdp    }
160960484Sobrien  if (success && PRINT_ARG_TYPES)
161033965Sjdp    {
161160484Sobrien      if (work->static_type)
161260484Sobrien	string_append (declp, " static");
161360484Sobrien      if (work->type_quals != TYPE_UNQUALIFIED)
161460484Sobrien	{
161560484Sobrien	  APPEND_BLANK (declp);
161660484Sobrien	  string_append (declp, qualifier_string (work->type_quals));
161760484Sobrien	}
161833965Sjdp    }
161960484Sobrien
162033965Sjdp  return (success);
162133965Sjdp}
162233965Sjdp
162333965Sjdp#if 0
162433965Sjdp
162533965Sjdpstatic int
162633965Sjdpdemangle_method_args (work, mangled, declp)
162733965Sjdp     struct work_stuff *work;
162833965Sjdp     const char **mangled;
162933965Sjdp     string *declp;
163033965Sjdp{
163133965Sjdp  int success = 0;
163233965Sjdp
163333965Sjdp  if (work -> static_type)
163433965Sjdp    {
163533965Sjdp      string_append (declp, *mangled + 1);
163633965Sjdp      *mangled += strlen (*mangled);
163733965Sjdp      success = 1;
163833965Sjdp    }
163933965Sjdp  else
164033965Sjdp    {
164133965Sjdp      success = demangle_args (work, mangled, declp);
164233965Sjdp    }
164333965Sjdp  return (success);
164433965Sjdp}
164533965Sjdp
164633965Sjdp#endif
164733965Sjdp
164833965Sjdpstatic int
164960484Sobriendemangle_template_template_parm (work, mangled, tname)
165033965Sjdp     struct work_stuff *work;
165133965Sjdp     const char **mangled;
165233965Sjdp     string *tname;
165360484Sobrien{
165460484Sobrien  int i;
165560484Sobrien  int r;
165660484Sobrien  int need_comma = 0;
165760484Sobrien  int success = 1;
165860484Sobrien  string temp;
165960484Sobrien
166060484Sobrien  string_append (tname, "template <");
166160484Sobrien  /* get size of template parameter list */
166260484Sobrien  if (get_count (mangled, &r))
166360484Sobrien    {
166460484Sobrien      for (i = 0; i < r; i++)
166560484Sobrien	{
166660484Sobrien	  if (need_comma)
166760484Sobrien	    {
166860484Sobrien	      string_append (tname, ", ");
166960484Sobrien	    }
167060484Sobrien
167160484Sobrien	    /* Z for type parameters */
167260484Sobrien	    if (**mangled == 'Z')
167360484Sobrien	      {
167460484Sobrien		(*mangled)++;
167560484Sobrien		string_append (tname, "class");
167660484Sobrien	      }
167760484Sobrien	      /* z for template parameters */
167860484Sobrien	    else if (**mangled == 'z')
167960484Sobrien	      {
168060484Sobrien		(*mangled)++;
168160484Sobrien		success =
168260484Sobrien		  demangle_template_template_parm (work, mangled, tname);
168360484Sobrien		if (!success)
168460484Sobrien		  {
168560484Sobrien		    break;
168660484Sobrien		  }
168760484Sobrien	      }
168860484Sobrien	    else
168960484Sobrien	      {
169060484Sobrien		/* temp is initialized in do_type */
169160484Sobrien		success = do_type (work, mangled, &temp);
169260484Sobrien		if (success)
169360484Sobrien		  {
169460484Sobrien		    string_appends (tname, &temp);
169560484Sobrien		  }
169660484Sobrien		string_delete(&temp);
169760484Sobrien		if (!success)
169860484Sobrien		  {
169960484Sobrien		    break;
170060484Sobrien		  }
170160484Sobrien	      }
170260484Sobrien	  need_comma = 1;
170360484Sobrien	}
170460484Sobrien
170560484Sobrien    }
170660484Sobrien  if (tname->p[-1] == '>')
170760484Sobrien    string_append (tname, " ");
170860484Sobrien  string_append (tname, "> class");
170960484Sobrien  return (success);
171060484Sobrien}
171160484Sobrien
171260484Sobrienstatic int
171360484Sobriendemangle_expression (work, mangled, s, tk)
171460484Sobrien     struct work_stuff *work;
171560484Sobrien     const char** mangled;
171660484Sobrien     string* s;
171760484Sobrien     type_kind_t tk;
171860484Sobrien{
171960484Sobrien  int need_operator = 0;
172060484Sobrien  int success;
172160484Sobrien
172260484Sobrien  success = 1;
172360484Sobrien  string_appendn (s, "(", 1);
172460484Sobrien  (*mangled)++;
172560484Sobrien  while (success && **mangled != 'W' && **mangled != '\0')
172660484Sobrien    {
172760484Sobrien      if (need_operator)
172860484Sobrien	{
172960484Sobrien	  size_t i;
173060484Sobrien	  size_t len;
173160484Sobrien
173260484Sobrien	  success = 0;
173360484Sobrien
173460484Sobrien	  len = strlen (*mangled);
173560484Sobrien
173677298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); ++i)
173760484Sobrien	    {
173860484Sobrien	      size_t l = strlen (optable[i].in);
173960484Sobrien
174060484Sobrien	      if (l <= len
174160484Sobrien		  && memcmp (optable[i].in, *mangled, l) == 0)
174260484Sobrien		{
174360484Sobrien		  string_appendn (s, " ", 1);
174460484Sobrien		  string_append (s, optable[i].out);
174560484Sobrien		  string_appendn (s, " ", 1);
174660484Sobrien		  success = 1;
174760484Sobrien		  (*mangled) += l;
174860484Sobrien		  break;
174960484Sobrien		}
175060484Sobrien	    }
175160484Sobrien
175260484Sobrien	  if (!success)
175360484Sobrien	    break;
175460484Sobrien	}
175560484Sobrien      else
175660484Sobrien	need_operator = 1;
175760484Sobrien
175860484Sobrien      success = demangle_template_value_parm (work, mangled, s, tk);
175960484Sobrien    }
176060484Sobrien
176160484Sobrien  if (**mangled != 'W')
176260484Sobrien    success = 0;
176360484Sobrien  else
176460484Sobrien    {
176560484Sobrien      string_appendn (s, ")", 1);
176660484Sobrien      (*mangled)++;
176760484Sobrien    }
176860484Sobrien
176960484Sobrien  return success;
177060484Sobrien}
177160484Sobrien
177260484Sobrienstatic int
177360484Sobriendemangle_integral_value (work, mangled, s)
177460484Sobrien     struct work_stuff *work;
177560484Sobrien     const char** mangled;
177660484Sobrien     string* s;
177760484Sobrien{
177860484Sobrien  int success;
177960484Sobrien
178060484Sobrien  if (**mangled == 'E')
178160484Sobrien    success = demangle_expression (work, mangled, s, tk_integral);
178260484Sobrien  else if (**mangled == 'Q' || **mangled == 'K')
178360484Sobrien    success = demangle_qualified (work, mangled, s, 0, 1);
178460484Sobrien  else
178560484Sobrien    {
178660484Sobrien      int value;
178760484Sobrien
178868765Sobrien      /* By default, we let the number decide whether we shall consume an
178968765Sobrien	 underscore.  */
179068765Sobrien      int consume_following_underscore = 0;
179168765Sobrien      int leave_following_underscore = 0;
179268765Sobrien
179360484Sobrien      success = 0;
179460484Sobrien
179560484Sobrien      /* Negative numbers are indicated with a leading `m'.  */
179660484Sobrien      if (**mangled == 'm')
179760484Sobrien	{
179860484Sobrien	  string_appendn (s, "-", 1);
179960484Sobrien	  (*mangled)++;
180060484Sobrien	}
180168765Sobrien      else if (mangled[0][0] == '_' && mangled[0][1] == 'm')
180268765Sobrien	{
180368765Sobrien	  /* Since consume_count_with_underscores does not handle the
180468765Sobrien	     `m'-prefix we must do it here, using consume_count and
180568765Sobrien	     adjusting underscores: we have to consume the underscore
180668765Sobrien	     matching the prepended one.  */
180768765Sobrien	  consume_following_underscore = 1;
180868765Sobrien	  string_appendn (s, "-", 1);
180968765Sobrien	  (*mangled) += 2;
181068765Sobrien	}
181168765Sobrien      else if (**mangled == '_')
181268765Sobrien	{
181368765Sobrien	  /* Do not consume a following underscore;
181468765Sobrien	     consume_following_underscore will consume what should be
181568765Sobrien	     consumed.  */
181668765Sobrien	  leave_following_underscore = 1;
181768765Sobrien	}
181860484Sobrien
181968765Sobrien      /* We must call consume_count if we expect to remove a trailing
182068765Sobrien	 underscore, since consume_count_with_underscores expects
182168765Sobrien	 the leading underscore (that we consumed) if it is to handle
182268765Sobrien	 multi-digit numbers.  */
182368765Sobrien      if (consume_following_underscore)
182468765Sobrien	value = consume_count (mangled);
182568765Sobrien      else
182668765Sobrien	value = consume_count_with_underscores (mangled);
182768765Sobrien
182860484Sobrien      if (value != -1)
182960484Sobrien	{
183060484Sobrien	  char buf[INTBUF_SIZE];
183160484Sobrien	  sprintf (buf, "%d", value);
183260484Sobrien	  string_append (s, buf);
183360484Sobrien
183468765Sobrien	  /* Numbers not otherwise delimited, might have an underscore
183568765Sobrien	     appended as a delimeter, which we should skip.
183668765Sobrien
183768765Sobrien	     ??? This used to always remove a following underscore, which
183868765Sobrien	     is wrong.  If other (arbitrary) cases are followed by an
183968765Sobrien	     underscore, we need to do something more radical.  */
184068765Sobrien
184168765Sobrien	  if ((value > 9 || consume_following_underscore)
184268765Sobrien	      && ! leave_following_underscore
184368765Sobrien	      && **mangled == '_')
184460484Sobrien	    (*mangled)++;
184560484Sobrien
184660484Sobrien	  /* All is well.  */
184760484Sobrien	  success = 1;
184860484Sobrien	}
184960484Sobrien    }
185060484Sobrien
185160484Sobrien  return success;
185260484Sobrien}
185360484Sobrien
185460484Sobrien/* Demangle the real value in MANGLED.  */
185560484Sobrien
185660484Sobrienstatic int
185760484Sobriendemangle_real_value (work, mangled, s)
185860484Sobrien     struct work_stuff *work;
185960484Sobrien     const char **mangled;
186060484Sobrien     string* s;
186160484Sobrien{
186260484Sobrien  if (**mangled == 'E')
186360484Sobrien    return demangle_expression (work, mangled, s, tk_real);
186460484Sobrien
186560484Sobrien  if (**mangled == 'm')
186660484Sobrien    {
186760484Sobrien      string_appendn (s, "-", 1);
186860484Sobrien      (*mangled)++;
186960484Sobrien    }
187077298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
187160484Sobrien    {
187260484Sobrien      string_appendn (s, *mangled, 1);
187360484Sobrien      (*mangled)++;
187460484Sobrien    }
187560484Sobrien  if (**mangled == '.') /* fraction */
187660484Sobrien    {
187760484Sobrien      string_appendn (s, ".", 1);
187860484Sobrien      (*mangled)++;
187977298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
188060484Sobrien	{
188160484Sobrien	  string_appendn (s, *mangled, 1);
188260484Sobrien	  (*mangled)++;
188360484Sobrien	}
188460484Sobrien    }
188560484Sobrien  if (**mangled == 'e') /* exponent */
188660484Sobrien    {
188760484Sobrien      string_appendn (s, "e", 1);
188860484Sobrien      (*mangled)++;
188977298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
189060484Sobrien	{
189160484Sobrien	  string_appendn (s, *mangled, 1);
189260484Sobrien	  (*mangled)++;
189360484Sobrien	}
189460484Sobrien    }
189560484Sobrien
189660484Sobrien  return 1;
189760484Sobrien}
189860484Sobrien
189960484Sobrienstatic int
190060484Sobriendemangle_template_value_parm (work, mangled, s, tk)
190160484Sobrien     struct work_stuff *work;
190260484Sobrien     const char **mangled;
190360484Sobrien     string* s;
190460484Sobrien     type_kind_t tk;
190560484Sobrien{
190660484Sobrien  int success = 1;
190760484Sobrien
190860484Sobrien  if (**mangled == 'Y')
190960484Sobrien    {
191060484Sobrien      /* The next argument is a template parameter. */
191160484Sobrien      int idx;
191260484Sobrien
191360484Sobrien      (*mangled)++;
191460484Sobrien      idx = consume_count_with_underscores (mangled);
191560484Sobrien      if (idx == -1
191660484Sobrien	  || (work->tmpl_argvec && idx >= work->ntmpl_args)
191760484Sobrien	  || consume_count_with_underscores (mangled) == -1)
191860484Sobrien	return -1;
191960484Sobrien      if (work->tmpl_argvec)
192060484Sobrien	string_append (s, work->tmpl_argvec[idx]);
192160484Sobrien      else
192260484Sobrien	string_append_template_idx (s, idx);
192360484Sobrien    }
192460484Sobrien  else if (tk == tk_integral)
192560484Sobrien    success = demangle_integral_value (work, mangled, s);
192660484Sobrien  else if (tk == tk_char)
192760484Sobrien    {
192860484Sobrien      char tmp[2];
192960484Sobrien      int val;
193060484Sobrien      if (**mangled == 'm')
193160484Sobrien	{
193260484Sobrien	  string_appendn (s, "-", 1);
193360484Sobrien	  (*mangled)++;
193460484Sobrien	}
193560484Sobrien      string_appendn (s, "'", 1);
193660484Sobrien      val = consume_count(mangled);
193760484Sobrien      if (val <= 0)
193860484Sobrien	success = 0;
193960484Sobrien      else
194060484Sobrien	{
194160484Sobrien	  tmp[0] = (char)val;
194260484Sobrien	  tmp[1] = '\0';
194360484Sobrien	  string_appendn (s, &tmp[0], 1);
194460484Sobrien	  string_appendn (s, "'", 1);
194560484Sobrien	}
194660484Sobrien    }
194760484Sobrien  else if (tk == tk_bool)
194860484Sobrien    {
194960484Sobrien      int val = consume_count (mangled);
195060484Sobrien      if (val == 0)
195160484Sobrien	string_appendn (s, "false", 5);
195260484Sobrien      else if (val == 1)
195360484Sobrien	string_appendn (s, "true", 4);
195460484Sobrien      else
195560484Sobrien	success = 0;
195660484Sobrien    }
195760484Sobrien  else if (tk == tk_real)
195860484Sobrien    success = demangle_real_value (work, mangled, s);
195960484Sobrien  else if (tk == tk_pointer || tk == tk_reference)
196060484Sobrien    {
196160484Sobrien      if (**mangled == 'Q')
196260484Sobrien	success = demangle_qualified (work, mangled, s,
196360484Sobrien				      /*isfuncname=*/0,
196460484Sobrien				      /*append=*/1);
196560484Sobrien      else
196660484Sobrien	{
196760484Sobrien	  int symbol_len  = consume_count (mangled);
196860484Sobrien	  if (symbol_len == -1)
196960484Sobrien	    return -1;
197060484Sobrien	  if (symbol_len == 0)
197160484Sobrien	    string_appendn (s, "0", 1);
197260484Sobrien	  else
197360484Sobrien	    {
197460484Sobrien	      char *p = xmalloc (symbol_len + 1), *q;
197560484Sobrien	      strncpy (p, *mangled, symbol_len);
197660484Sobrien	      p [symbol_len] = '\0';
197760484Sobrien	      /* We use cplus_demangle here, rather than
197860484Sobrien		 internal_cplus_demangle, because the name of the entity
197960484Sobrien		 mangled here does not make use of any of the squangling
198060484Sobrien		 or type-code information we have built up thus far; it is
198160484Sobrien		 mangled independently.  */
198260484Sobrien	      q = cplus_demangle (p, work->options);
198360484Sobrien	      if (tk == tk_pointer)
198460484Sobrien		string_appendn (s, "&", 1);
198560484Sobrien	      /* FIXME: Pointer-to-member constants should get a
198660484Sobrien		 qualifying class name here.  */
198760484Sobrien	      if (q)
198860484Sobrien		{
198960484Sobrien		  string_append (s, q);
199060484Sobrien		  free (q);
199160484Sobrien		}
199260484Sobrien	      else
199360484Sobrien		string_append (s, p);
199460484Sobrien	      free (p);
199560484Sobrien	    }
199660484Sobrien	  *mangled += symbol_len;
199760484Sobrien	}
199860484Sobrien    }
199960484Sobrien
200060484Sobrien  return success;
200160484Sobrien}
200260484Sobrien
200360484Sobrien/* Demangle the template name in MANGLED.  The full name of the
200460484Sobrien   template (e.g., S<int>) is placed in TNAME.  The name without the
200560484Sobrien   template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
200660484Sobrien   non-NULL.  If IS_TYPE is nonzero, this template is a type template,
200760484Sobrien   not a function template.  If both IS_TYPE and REMEMBER are nonzero,
200868765Sobrien   the template is remembered in the list of back-referenceable
200960484Sobrien   types.  */
201060484Sobrien
201160484Sobrienstatic int
201260484Sobriendemangle_template (work, mangled, tname, trawname, is_type, remember)
201360484Sobrien     struct work_stuff *work;
201460484Sobrien     const char **mangled;
201560484Sobrien     string *tname;
201633965Sjdp     string *trawname;
201738889Sjdp     int is_type;
201860484Sobrien     int remember;
201933965Sjdp{
202033965Sjdp  int i;
202133965Sjdp  int r;
202233965Sjdp  int need_comma = 0;
202333965Sjdp  int success = 0;
202433965Sjdp  const char *start;
202538889Sjdp  int is_java_array = 0;
202633965Sjdp  string temp;
202760484Sobrien  int bindex = 0;
202833965Sjdp
202933965Sjdp  (*mangled)++;
203038889Sjdp  if (is_type)
203133965Sjdp    {
203260484Sobrien      if (remember)
203360484Sobrien	bindex = register_Btype (work);
203438889Sjdp      start = *mangled;
203538889Sjdp      /* get template name */
203660484Sobrien      if (**mangled == 'z')
203738889Sjdp	{
203860484Sobrien	  int idx;
203960484Sobrien	  (*mangled)++;
204060484Sobrien	  (*mangled)++;
204160484Sobrien
204260484Sobrien	  idx = consume_count_with_underscores (mangled);
204360484Sobrien	  if (idx == -1
204460484Sobrien	      || (work->tmpl_argvec && idx >= work->ntmpl_args)
204560484Sobrien	      || consume_count_with_underscores (mangled) == -1)
204660484Sobrien	    return (0);
204760484Sobrien
204860484Sobrien	  if (work->tmpl_argvec)
204960484Sobrien	    {
205060484Sobrien	      string_append (tname, work->tmpl_argvec[idx]);
205160484Sobrien	      if (trawname)
205260484Sobrien		string_append (trawname, work->tmpl_argvec[idx]);
205360484Sobrien	    }
205460484Sobrien	  else
205560484Sobrien	    {
205660484Sobrien	      string_append_template_idx (tname, idx);
205760484Sobrien	      if (trawname)
205860484Sobrien		string_append_template_idx (trawname, idx);
205960484Sobrien	    }
206038889Sjdp	}
206160484Sobrien      else
206238889Sjdp	{
206360484Sobrien	  if ((r = consume_count (mangled)) <= 0
206460484Sobrien	      || (int) strlen (*mangled) < r)
206560484Sobrien	    {
206660484Sobrien	      return (0);
206760484Sobrien	    }
206860484Sobrien	  is_java_array = (work -> options & DMGL_JAVA)
206960484Sobrien	    && strncmp (*mangled, "JArray1Z", 8) == 0;
207060484Sobrien	  if (! is_java_array)
207160484Sobrien	    {
207260484Sobrien	      string_appendn (tname, *mangled, r);
207360484Sobrien	    }
207460484Sobrien	  if (trawname)
207560484Sobrien	    string_appendn (trawname, *mangled, r);
207660484Sobrien	  *mangled += r;
207738889Sjdp	}
207833965Sjdp    }
207938889Sjdp  if (!is_java_array)
208038889Sjdp    string_append (tname, "<");
208133965Sjdp  /* get size of template parameter list */
208233965Sjdp  if (!get_count (mangled, &r))
208333965Sjdp    {
208433965Sjdp      return (0);
208533965Sjdp    }
208638889Sjdp  if (!is_type)
208738889Sjdp    {
208838889Sjdp      /* Create an array for saving the template argument values. */
208938889Sjdp      work->tmpl_argvec = (char**) xmalloc (r * sizeof (char *));
209038889Sjdp      work->ntmpl_args = r;
209138889Sjdp      for (i = 0; i < r; i++)
209238889Sjdp	work->tmpl_argvec[i] = 0;
209338889Sjdp    }
209433965Sjdp  for (i = 0; i < r; i++)
209533965Sjdp    {
209633965Sjdp      if (need_comma)
209733965Sjdp	{
209833965Sjdp	  string_append (tname, ", ");
209933965Sjdp	}
210033965Sjdp      /* Z for type parameters */
210133965Sjdp      if (**mangled == 'Z')
210233965Sjdp	{
210333965Sjdp	  (*mangled)++;
210433965Sjdp	  /* temp is initialized in do_type */
210533965Sjdp	  success = do_type (work, mangled, &temp);
210633965Sjdp	  if (success)
210733965Sjdp	    {
210833965Sjdp	      string_appends (tname, &temp);
210938889Sjdp
211038889Sjdp	      if (!is_type)
211138889Sjdp		{
211238889Sjdp		  /* Save the template argument. */
211338889Sjdp		  int len = temp.p - temp.b;
211438889Sjdp		  work->tmpl_argvec[i] = xmalloc (len + 1);
211538889Sjdp		  memcpy (work->tmpl_argvec[i], temp.b, len);
211638889Sjdp		  work->tmpl_argvec[i][len] = '\0';
211738889Sjdp		}
211833965Sjdp	    }
211933965Sjdp	  string_delete(&temp);
212033965Sjdp	  if (!success)
212133965Sjdp	    {
212233965Sjdp	      break;
212333965Sjdp	    }
212433965Sjdp	}
212560484Sobrien      /* z for template parameters */
212660484Sobrien      else if (**mangled == 'z')
212760484Sobrien	{
212860484Sobrien	  int r2;
212960484Sobrien	  (*mangled)++;
213060484Sobrien	  success = demangle_template_template_parm (work, mangled, tname);
213160484Sobrien
213260484Sobrien	  if (success
213360484Sobrien	      && (r2 = consume_count (mangled)) > 0
213460484Sobrien	      && (int) strlen (*mangled) >= r2)
213560484Sobrien	    {
213660484Sobrien	      string_append (tname, " ");
213760484Sobrien	      string_appendn (tname, *mangled, r2);
213860484Sobrien	      if (!is_type)
213960484Sobrien		{
214060484Sobrien		  /* Save the template argument. */
214160484Sobrien		  int len = r2;
214260484Sobrien		  work->tmpl_argvec[i] = xmalloc (len + 1);
214360484Sobrien		  memcpy (work->tmpl_argvec[i], *mangled, len);
214460484Sobrien		  work->tmpl_argvec[i][len] = '\0';
214560484Sobrien		}
214660484Sobrien	      *mangled += r2;
214760484Sobrien	    }
214860484Sobrien	  if (!success)
214960484Sobrien	    {
215060484Sobrien	      break;
215160484Sobrien	    }
215260484Sobrien	}
215333965Sjdp      else
215433965Sjdp	{
215538889Sjdp	  string  param;
215638889Sjdp	  string* s;
215738889Sjdp
215833965Sjdp	  /* otherwise, value parameter */
215960484Sobrien
216033965Sjdp	  /* temp is initialized in do_type */
216133965Sjdp	  success = do_type (work, mangled, &temp);
216233965Sjdp	  string_delete(&temp);
216333965Sjdp	  if (!success)
216460484Sobrien	    break;
216538889Sjdp
216638889Sjdp	  if (!is_type)
216738889Sjdp	    {
216838889Sjdp	      s = &param;
216938889Sjdp	      string_init (s);
217038889Sjdp	    }
217138889Sjdp	  else
217238889Sjdp	    s = tname;
217338889Sjdp
217460484Sobrien	  success = demangle_template_value_parm (work, mangled, s,
217560484Sobrien						  (type_kind_t) success);
217638889Sjdp
217760484Sobrien	  if (!success)
217838889Sjdp	    {
217960484Sobrien	      if (!is_type)
218060484Sobrien		string_delete (s);
218160484Sobrien	      success = 0;
218260484Sobrien	      break;
218333965Sjdp	    }
218460484Sobrien
218538889Sjdp	  if (!is_type)
218638889Sjdp	    {
218738889Sjdp	      int len = s->p - s->b;
218838889Sjdp	      work->tmpl_argvec[i] = xmalloc (len + 1);
218938889Sjdp	      memcpy (work->tmpl_argvec[i], s->b, len);
219038889Sjdp	      work->tmpl_argvec[i][len] = '\0';
219160484Sobrien
219238889Sjdp	      string_appends (tname, s);
219338889Sjdp	      string_delete (s);
219438889Sjdp	    }
219533965Sjdp	}
219633965Sjdp      need_comma = 1;
219733965Sjdp    }
219838889Sjdp  if (is_java_array)
219938889Sjdp    {
220038889Sjdp      string_append (tname, "[]");
220138889Sjdp    }
220238889Sjdp  else
220338889Sjdp    {
220438889Sjdp      if (tname->p[-1] == '>')
220538889Sjdp	string_append (tname, " ");
220638889Sjdp      string_append (tname, ">");
220738889Sjdp    }
220860484Sobrien
220960484Sobrien  if (is_type && remember)
221060484Sobrien    remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
221160484Sobrien
221233965Sjdp  /*
221333965Sjdp    if (work -> static_type)
221433965Sjdp    {
221533965Sjdp    string_append (declp, *mangled + 1);
221633965Sjdp    *mangled += strlen (*mangled);
221733965Sjdp    success = 1;
221833965Sjdp    }
221933965Sjdp    else
222033965Sjdp    {
222133965Sjdp    success = demangle_args (work, mangled, declp);
222233965Sjdp    }
222333965Sjdp    }
222433965Sjdp    */
222533965Sjdp  return (success);
222633965Sjdp}
222733965Sjdp
222833965Sjdpstatic int
222933965Sjdparm_pt (work, mangled, n, anchor, args)
223033965Sjdp     struct work_stuff *work;
223133965Sjdp     const char *mangled;
223233965Sjdp     int n;
223333965Sjdp     const char **anchor, **args;
223433965Sjdp{
223560484Sobrien  /* Check if ARM template with "__pt__" in it ("parameterized type") */
223660484Sobrien  /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
223789857Sobrien  if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__")))
223833965Sjdp    {
223933965Sjdp      int len;
224033965Sjdp      *args = *anchor + 6;
224133965Sjdp      len = consume_count (args);
224260484Sobrien      if (len == -1)
224360484Sobrien	return 0;
224433965Sjdp      if (*args + len == mangled + n && **args == '_')
224533965Sjdp	{
224633965Sjdp	  ++*args;
224733965Sjdp	  return 1;
224833965Sjdp	}
224933965Sjdp    }
225060484Sobrien  if (AUTO_DEMANGLING || EDG_DEMANGLING)
225160484Sobrien    {
225289857Sobrien      if ((*anchor = strstr (mangled, "__tm__"))
225389857Sobrien          || (*anchor = strstr (mangled, "__ps__"))
225489857Sobrien          || (*anchor = strstr (mangled, "__pt__")))
225560484Sobrien        {
225660484Sobrien          int len;
225760484Sobrien          *args = *anchor + 6;
225860484Sobrien          len = consume_count (args);
225960484Sobrien	  if (len == -1)
226060484Sobrien	    return 0;
226160484Sobrien          if (*args + len == mangled + n && **args == '_')
226260484Sobrien            {
226360484Sobrien              ++*args;
226460484Sobrien              return 1;
226560484Sobrien            }
226660484Sobrien        }
226789857Sobrien      else if ((*anchor = strstr (mangled, "__S")))
226860484Sobrien        {
226960484Sobrien 	  int len;
227060484Sobrien 	  *args = *anchor + 3;
227160484Sobrien 	  len = consume_count (args);
227260484Sobrien	  if (len == -1)
227360484Sobrien	    return 0;
227460484Sobrien 	  if (*args + len == mangled + n && **args == '_')
227560484Sobrien            {
227660484Sobrien              ++*args;
227760484Sobrien 	      return 1;
227860484Sobrien            }
227960484Sobrien        }
228060484Sobrien    }
228160484Sobrien
228233965Sjdp  return 0;
228333965Sjdp}
228433965Sjdp
228533965Sjdpstatic void
228660484Sobriendemangle_arm_hp_template (work, mangled, n, declp)
228733965Sjdp     struct work_stuff *work;
228833965Sjdp     const char **mangled;
228933965Sjdp     int n;
229033965Sjdp     string *declp;
229133965Sjdp{
229233965Sjdp  const char *p;
229333965Sjdp  const char *args;
229433965Sjdp  const char *e = *mangled + n;
229560484Sobrien  string arg;
229633965Sjdp
229760484Sobrien  /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
229860484Sobrien     template args */
229960484Sobrien  if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
230033965Sjdp    {
230160484Sobrien      char *start_spec_args = NULL;
230260484Sobrien
230360484Sobrien      /* First check for and omit template specialization pseudo-arguments,
230460484Sobrien         such as in "Spec<#1,#1.*>" */
230560484Sobrien      start_spec_args = strchr (*mangled, '<');
230660484Sobrien      if (start_spec_args && (start_spec_args - *mangled < n))
230760484Sobrien        string_appendn (declp, *mangled, start_spec_args - *mangled);
230860484Sobrien      else
230960484Sobrien        string_appendn (declp, *mangled, n);
231060484Sobrien      (*mangled) += n + 1;
231133965Sjdp      string_init (&arg);
231260484Sobrien      if (work->temp_start == -1) /* non-recursive call */
231360484Sobrien        work->temp_start = declp->p - declp->b;
231460484Sobrien      string_append (declp, "<");
231560484Sobrien      while (1)
231660484Sobrien        {
231760484Sobrien          string_clear (&arg);
231860484Sobrien          switch (**mangled)
231960484Sobrien            {
232060484Sobrien              case 'T':
232160484Sobrien                /* 'T' signals a type parameter */
232260484Sobrien                (*mangled)++;
232360484Sobrien                if (!do_type (work, mangled, &arg))
232460484Sobrien                  goto hpacc_template_args_done;
232560484Sobrien                break;
232660484Sobrien
232760484Sobrien              case 'U':
232860484Sobrien              case 'S':
232960484Sobrien                /* 'U' or 'S' signals an integral value */
233060484Sobrien                if (!do_hpacc_template_const_value (work, mangled, &arg))
233160484Sobrien                  goto hpacc_template_args_done;
233260484Sobrien                break;
233360484Sobrien
233460484Sobrien              case 'A':
233560484Sobrien                /* 'A' signals a named constant expression (literal) */
233660484Sobrien                if (!do_hpacc_template_literal (work, mangled, &arg))
233760484Sobrien                  goto hpacc_template_args_done;
233860484Sobrien                break;
233960484Sobrien
234060484Sobrien              default:
234160484Sobrien                /* Today, 1997-09-03, we have only the above types
234260484Sobrien                   of template parameters */
234360484Sobrien                /* FIXME: maybe this should fail and return null */
234460484Sobrien                goto hpacc_template_args_done;
234560484Sobrien            }
234660484Sobrien          string_appends (declp, &arg);
234760484Sobrien         /* Check if we're at the end of template args.
234860484Sobrien             0 if at end of static member of template class,
234960484Sobrien             _ if done with template args for a function */
235060484Sobrien          if ((**mangled == '\000') || (**mangled == '_'))
235160484Sobrien            break;
235260484Sobrien          else
235360484Sobrien            string_append (declp, ",");
235460484Sobrien        }
235560484Sobrien    hpacc_template_args_done:
235660484Sobrien      string_append (declp, ">");
235760484Sobrien      string_delete (&arg);
235860484Sobrien      if (**mangled == '_')
235960484Sobrien        (*mangled)++;
236060484Sobrien      return;
236160484Sobrien    }
236260484Sobrien  /* ARM template? (Also handles HP cfront extensions) */
236360484Sobrien  else if (arm_pt (work, *mangled, n, &p, &args))
236460484Sobrien    {
236560484Sobrien      string type_str;
236660484Sobrien
236760484Sobrien      string_init (&arg);
236833965Sjdp      string_appendn (declp, *mangled, p - *mangled);
236960484Sobrien      if (work->temp_start == -1)  /* non-recursive call */
237060484Sobrien	work->temp_start = declp->p - declp->b;
237133965Sjdp      string_append (declp, "<");
237233965Sjdp      /* should do error checking here */
237333965Sjdp      while (args < e) {
237433965Sjdp	string_clear (&arg);
237560484Sobrien
237660484Sobrien	/* Check for type or literal here */
237760484Sobrien	switch (*args)
237860484Sobrien	  {
237960484Sobrien	    /* HP cfront extensions to ARM for template args */
238060484Sobrien	    /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
238160484Sobrien	    /* FIXME: We handle only numeric literals for HP cfront */
238260484Sobrien          case 'X':
238360484Sobrien            /* A typed constant value follows */
238460484Sobrien            args++;
238560484Sobrien            if (!do_type (work, &args, &type_str))
238660484Sobrien	      goto cfront_template_args_done;
238760484Sobrien            string_append (&arg, "(");
238860484Sobrien            string_appends (&arg, &type_str);
238960484Sobrien            string_append (&arg, ")");
239060484Sobrien            if (*args != 'L')
239160484Sobrien              goto cfront_template_args_done;
239260484Sobrien            args++;
239360484Sobrien            /* Now snarf a literal value following 'L' */
239460484Sobrien            if (!snarf_numeric_literal (&args, &arg))
239560484Sobrien	      goto cfront_template_args_done;
239660484Sobrien            break;
239760484Sobrien
239860484Sobrien          case 'L':
239960484Sobrien            /* Snarf a literal following 'L' */
240060484Sobrien            args++;
240160484Sobrien            if (!snarf_numeric_literal (&args, &arg))
240260484Sobrien	      goto cfront_template_args_done;
240360484Sobrien            break;
240460484Sobrien          default:
240560484Sobrien            /* Not handling other HP cfront stuff */
240660484Sobrien            if (!do_type (work, &args, &arg))
240760484Sobrien              goto cfront_template_args_done;
240860484Sobrien	  }
240933965Sjdp	string_appends (declp, &arg);
241033965Sjdp	string_append (declp, ",");
241133965Sjdp      }
241260484Sobrien    cfront_template_args_done:
241333965Sjdp      string_delete (&arg);
241460484Sobrien      if (args >= e)
241560484Sobrien	--declp->p; /* remove extra comma */
241633965Sjdp      string_append (declp, ">");
241733965Sjdp    }
241860484Sobrien  else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
241960484Sobrien	   && (*mangled)[9] == 'N'
242060484Sobrien	   && (*mangled)[8] == (*mangled)[10]
242160484Sobrien	   && strchr (cplus_markers, (*mangled)[8]))
242260484Sobrien    {
242360484Sobrien      /* A member of the anonymous namespace.  */
242460484Sobrien      string_append (declp, "{anonymous}");
242560484Sobrien    }
242633965Sjdp  else
242733965Sjdp    {
242860484Sobrien      if (work->temp_start == -1) /* non-recursive call only */
242960484Sobrien	work->temp_start = 0;     /* disable in recursive calls */
243033965Sjdp      string_appendn (declp, *mangled, n);
243133965Sjdp    }
243233965Sjdp  *mangled += n;
243333965Sjdp}
243433965Sjdp
243560484Sobrien/* Extract a class name, possibly a template with arguments, from the
243660484Sobrien   mangled string; qualifiers, local class indicators, etc. have
243760484Sobrien   already been dealt with */
243860484Sobrien
243933965Sjdpstatic int
244033965Sjdpdemangle_class_name (work, mangled, declp)
244133965Sjdp     struct work_stuff *work;
244233965Sjdp     const char **mangled;
244333965Sjdp     string *declp;
244433965Sjdp{
244533965Sjdp  int n;
244633965Sjdp  int success = 0;
244733965Sjdp
244833965Sjdp  n = consume_count (mangled);
244960484Sobrien  if (n == -1)
245060484Sobrien    return 0;
245160484Sobrien  if ((int) strlen (*mangled) >= n)
245233965Sjdp    {
245360484Sobrien      demangle_arm_hp_template (work, mangled, n, declp);
245433965Sjdp      success = 1;
245533965Sjdp    }
245633965Sjdp
245733965Sjdp  return (success);
245833965Sjdp}
245933965Sjdp
246033965Sjdp/*
246133965Sjdp
246233965SjdpLOCAL FUNCTION
246333965Sjdp
246433965Sjdp	demangle_class -- demangle a mangled class sequence
246533965Sjdp
246633965SjdpSYNOPSIS
246733965Sjdp
246833965Sjdp	static int
246933965Sjdp	demangle_class (struct work_stuff *work, const char **mangled,
247033965Sjdp			strint *declp)
247133965Sjdp
247233965SjdpDESCRIPTION
247333965Sjdp
247433965Sjdp	DECLP points to the buffer into which demangling is being done.
247533965Sjdp
247633965Sjdp	*MANGLED points to the current token to be demangled.  On input,
247733965Sjdp	it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
247833965Sjdp	On exit, it points to the next token after the mangled class on
247933965Sjdp	success, or the first unconsumed token on failure.
248033965Sjdp
248133965Sjdp	If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
248233965Sjdp	we are demangling a constructor or destructor.  In this case
248333965Sjdp	we prepend "class::class" or "class::~class" to DECLP.
248433965Sjdp
248533965Sjdp	Otherwise, we prepend "class::" to the current DECLP.
248633965Sjdp
248733965Sjdp	Reset the constructor/destructor flags once they have been
248833965Sjdp	"consumed".  This allows demangle_class to be called later during
248933965Sjdp	the same demangling, to do normal class demangling.
249033965Sjdp
249133965Sjdp	Returns 1 if demangling is successful, 0 otherwise.
249233965Sjdp
249333965Sjdp*/
249433965Sjdp
249533965Sjdpstatic int
249633965Sjdpdemangle_class (work, mangled, declp)
249733965Sjdp     struct work_stuff *work;
249833965Sjdp     const char **mangled;
249933965Sjdp     string *declp;
250033965Sjdp{
250133965Sjdp  int success = 0;
250260484Sobrien  int btype;
250333965Sjdp  string class_name;
250460484Sobrien  char *save_class_name_end = 0;
250533965Sjdp
250633965Sjdp  string_init (&class_name);
250760484Sobrien  btype = register_Btype (work);
250833965Sjdp  if (demangle_class_name (work, mangled, &class_name))
250933965Sjdp    {
251060484Sobrien      save_class_name_end = class_name.p;
251133965Sjdp      if ((work->constructor & 1) || (work->destructor & 1))
251233965Sjdp	{
251360484Sobrien          /* adjust so we don't include template args */
251460484Sobrien          if (work->temp_start && (work->temp_start != -1))
251560484Sobrien            {
251660484Sobrien              class_name.p = class_name.b + work->temp_start;
251760484Sobrien            }
251833965Sjdp	  string_prepends (declp, &class_name);
251933965Sjdp	  if (work -> destructor & 1)
252033965Sjdp	    {
252133965Sjdp	      string_prepend (declp, "~");
252233965Sjdp              work -> destructor -= 1;
252333965Sjdp	    }
252433965Sjdp	  else
252533965Sjdp	    {
252660484Sobrien	      work -> constructor -= 1;
252733965Sjdp	    }
252833965Sjdp	}
252960484Sobrien      class_name.p = save_class_name_end;
253060484Sobrien      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
253160484Sobrien      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
253260484Sobrien      string_prepend (declp, SCOPE_STRING (work));
253333965Sjdp      string_prepends (declp, &class_name);
253433965Sjdp      success = 1;
253533965Sjdp    }
253633965Sjdp  string_delete (&class_name);
253733965Sjdp  return (success);
253833965Sjdp}
253933965Sjdp
254068765Sobrien
254168765Sobrien/* Called when there's a "__" in the mangled name, with `scan' pointing to
254268765Sobrien   the rightmost guess.
254368765Sobrien
254468765Sobrien   Find the correct "__"-sequence where the function name ends and the
254568765Sobrien   signature starts, which is ambiguous with GNU mangling.
254668765Sobrien   Call demangle_signature here, so we can make sure we found the right
254768765Sobrien   one; *mangled will be consumed so caller will not make further calls to
254868765Sobrien   demangle_signature.  */
254968765Sobrien
255068765Sobrienstatic int
255168765Sobrieniterate_demangle_function (work, mangled, declp, scan)
255268765Sobrien     struct work_stuff *work;
255368765Sobrien     const char **mangled;
255468765Sobrien     string *declp;
255568765Sobrien     const char *scan;
255668765Sobrien{
255768765Sobrien  const char *mangle_init = *mangled;
255868765Sobrien  int success = 0;
255968765Sobrien  string decl_init;
256068765Sobrien  struct work_stuff work_init;
256168765Sobrien
256268765Sobrien  if (*(scan + 2) == '\0')
256368765Sobrien    return 0;
256468765Sobrien
256568765Sobrien  /* Do not iterate for some demangling modes, or if there's only one
256668765Sobrien     "__"-sequence.  This is the normal case.  */
256768765Sobrien  if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
256889857Sobrien      || strstr (scan + 2, "__") == NULL)
256968765Sobrien    {
257068765Sobrien      demangle_function_name (work, mangled, declp, scan);
257168765Sobrien      return 1;
257268765Sobrien    }
257368765Sobrien
257468765Sobrien  /* Save state so we can restart if the guess at the correct "__" was
257568765Sobrien     wrong.  */
257668765Sobrien  string_init (&decl_init);
257768765Sobrien  string_appends (&decl_init, declp);
257868765Sobrien  memset (&work_init, 0, sizeof work_init);
257968765Sobrien  work_stuff_copy_to_from (&work_init, work);
258068765Sobrien
258168765Sobrien  /* Iterate over occurrences of __, allowing names and types to have a
258268765Sobrien     "__" sequence in them.  We must start with the first (not the last)
258368765Sobrien     occurrence, since "__" most often occur between independent mangled
258468765Sobrien     parts, hence starting at the last occurence inside a signature
258568765Sobrien     might get us a "successful" demangling of the signature.  */
258668765Sobrien
258768765Sobrien  while (scan[2])
258868765Sobrien    {
258968765Sobrien      demangle_function_name (work, mangled, declp, scan);
259068765Sobrien      success = demangle_signature (work, mangled, declp);
259168765Sobrien      if (success)
259268765Sobrien	break;
259368765Sobrien
259468765Sobrien      /* Reset demangle state for the next round.  */
259568765Sobrien      *mangled = mangle_init;
259668765Sobrien      string_clear (declp);
259768765Sobrien      string_appends (declp, &decl_init);
259868765Sobrien      work_stuff_copy_to_from (work, &work_init);
259968765Sobrien
260068765Sobrien      /* Leave this underscore-sequence.  */
260168765Sobrien      scan += 2;
260268765Sobrien
260368765Sobrien      /* Scan for the next "__" sequence.  */
260468765Sobrien      while (*scan && (scan[0] != '_' || scan[1] != '_'))
260568765Sobrien	scan++;
260668765Sobrien
260768765Sobrien      /* Move to last "__" in this sequence.  */
260868765Sobrien      while (*scan && *scan == '_')
260968765Sobrien	scan++;
261068765Sobrien      scan -= 2;
261168765Sobrien    }
261268765Sobrien
261368765Sobrien  /* Delete saved state.  */
261468765Sobrien  delete_work_stuff (&work_init);
261568765Sobrien  string_delete (&decl_init);
261668765Sobrien
261768765Sobrien  return success;
261868765Sobrien}
261968765Sobrien
262033965Sjdp/*
262133965Sjdp
262233965SjdpLOCAL FUNCTION
262333965Sjdp
262433965Sjdp	demangle_prefix -- consume the mangled name prefix and find signature
262533965Sjdp
262633965SjdpSYNOPSIS
262733965Sjdp
262833965Sjdp	static int
262933965Sjdp	demangle_prefix (struct work_stuff *work, const char **mangled,
263033965Sjdp			 string *declp);
263133965Sjdp
263233965SjdpDESCRIPTION
263333965Sjdp
263433965Sjdp	Consume and demangle the prefix of the mangled name.
263568765Sobrien	While processing the function name root, arrange to call
263668765Sobrien	demangle_signature if the root is ambiguous.
263733965Sjdp
263833965Sjdp	DECLP points to the string buffer into which demangled output is
263933965Sjdp	placed.  On entry, the buffer is empty.  On exit it contains
264033965Sjdp	the root function name, the demangled operator name, or in some
264133965Sjdp	special cases either nothing or the completely demangled result.
264233965Sjdp
264333965Sjdp	MANGLED points to the current pointer into the mangled name.  As each
264433965Sjdp	token of the mangled name is consumed, it is updated.  Upon entry
264533965Sjdp	the current mangled name pointer points to the first character of
264633965Sjdp	the mangled name.  Upon exit, it should point to the first character
264733965Sjdp	of the signature if demangling was successful, or to the first
264833965Sjdp	unconsumed character if demangling of the prefix was unsuccessful.
264960484Sobrien
265033965Sjdp	Returns 1 on success, 0 otherwise.
265133965Sjdp */
265233965Sjdp
265333965Sjdpstatic int
265433965Sjdpdemangle_prefix (work, mangled, declp)
265533965Sjdp     struct work_stuff *work;
265633965Sjdp     const char **mangled;
265733965Sjdp     string *declp;
265833965Sjdp{
265933965Sjdp  int success = 1;
266033965Sjdp  const char *scan;
266133965Sjdp  int i;
266233965Sjdp
266360484Sobrien  if (strlen(*mangled) > 6
266460484Sobrien      && (strncmp(*mangled, "_imp__", 6) == 0
266560484Sobrien          || strncmp(*mangled, "__imp_", 6) == 0))
266633965Sjdp    {
266760484Sobrien      /* it's a symbol imported from a PE dynamic library. Check for both
266860484Sobrien         new style prefix _imp__ and legacy __imp_ used by older versions
266960484Sobrien	 of dlltool. */
267060484Sobrien      (*mangled) += 6;
267160484Sobrien      work->dllimported = 1;
267260484Sobrien    }
267360484Sobrien  else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
267460484Sobrien    {
267533965Sjdp      char *marker = strchr (cplus_markers, (*mangled)[8]);
267633965Sjdp      if (marker != NULL && *marker == (*mangled)[10])
267733965Sjdp	{
267833965Sjdp	  if ((*mangled)[9] == 'D')
267933965Sjdp	    {
268033965Sjdp	      /* it's a GNU global destructor to be executed at program exit */
268133965Sjdp	      (*mangled) += 11;
268233965Sjdp	      work->destructor = 2;
268333965Sjdp	      if (gnu_special (work, mangled, declp))
268433965Sjdp		return success;
268533965Sjdp	    }
268633965Sjdp	  else if ((*mangled)[9] == 'I')
268733965Sjdp	    {
268833965Sjdp	      /* it's a GNU global constructor to be executed at program init */
268933965Sjdp	      (*mangled) += 11;
269033965Sjdp	      work->constructor = 2;
269133965Sjdp	      if (gnu_special (work, mangled, declp))
269233965Sjdp		return success;
269333965Sjdp	    }
269433965Sjdp	}
269533965Sjdp    }
269660484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
269733965Sjdp    {
269833965Sjdp      /* it's a ARM global destructor to be executed at program exit */
269933965Sjdp      (*mangled) += 7;
270033965Sjdp      work->destructor = 2;
270133965Sjdp    }
270260484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
270333965Sjdp    {
270433965Sjdp      /* it's a ARM global constructor to be executed at program initial */
270533965Sjdp      (*mangled) += 7;
270633965Sjdp      work->constructor = 2;
270733965Sjdp    }
270833965Sjdp
270933965Sjdp  /*  This block of code is a reduction in strength time optimization
271033965Sjdp      of:
271189857Sobrien      scan = strstr (*mangled, "__"); */
271233965Sjdp
271333965Sjdp  {
271433965Sjdp    scan = *mangled;
271533965Sjdp
271633965Sjdp    do {
271733965Sjdp      scan = strchr (scan, '_');
271833965Sjdp    } while (scan != NULL && *++scan != '_');
271933965Sjdp
272033965Sjdp    if (scan != NULL) --scan;
272133965Sjdp  }
272233965Sjdp
272333965Sjdp  if (scan != NULL)
272433965Sjdp    {
272533965Sjdp      /* We found a sequence of two or more '_', ensure that we start at
272633965Sjdp	 the last pair in the sequence.  */
272733965Sjdp      i = strspn (scan, "_");
272833965Sjdp      if (i > 2)
272933965Sjdp	{
273060484Sobrien	  scan += (i - 2);
273133965Sjdp	}
273233965Sjdp    }
273360484Sobrien
273433965Sjdp  if (scan == NULL)
273533965Sjdp    {
273633965Sjdp      success = 0;
273733965Sjdp    }
273833965Sjdp  else if (work -> static_type)
273933965Sjdp    {
274077298Sobrien      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
274133965Sjdp	{
274233965Sjdp	  success = 0;
274333965Sjdp	}
274433965Sjdp    }
274538889Sjdp  else if ((scan == *mangled)
274677298Sobrien	   && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
274760484Sobrien	       || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
274833965Sjdp    {
274933965Sjdp      /* The ARM says nothing about the mangling of local variables.
275033965Sjdp	 But cfront mangles local variables by prepending __<nesting_level>
275133965Sjdp	 to them. As an extension to ARM demangling we handle this case.  */
275260484Sobrien      if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
275377298Sobrien	  && ISDIGIT ((unsigned char)scan[2]))
275433965Sjdp	{
275533965Sjdp	  *mangled = scan + 2;
275633965Sjdp	  consume_count (mangled);
275733965Sjdp	  string_append (declp, *mangled);
275833965Sjdp	  *mangled += strlen (*mangled);
275960484Sobrien	  success = 1;
276033965Sjdp	}
276133965Sjdp      else
276233965Sjdp	{
276333965Sjdp	  /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
276433965Sjdp	     names like __Q2_3foo3bar for nested type names.  So don't accept
276538889Sjdp	     this style of constructor for cfront demangling.  A GNU
276638889Sjdp	     style member-template constructor starts with 'H'. */
276760484Sobrien	  if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
276833965Sjdp	    work -> constructor += 1;
276933965Sjdp	  *mangled = scan + 2;
277033965Sjdp	}
277133965Sjdp    }
277260484Sobrien  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
277333965Sjdp    {
277460484Sobrien      /* Cfront-style parameterized type.  Handled later as a signature. */
277560484Sobrien      success = 1;
277660484Sobrien
277760484Sobrien      /* ARM template? */
277860484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
277960484Sobrien    }
278060484Sobrien  else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
278160484Sobrien                              || (scan[2] == 'p' && scan[3] == 's')
278260484Sobrien                              || (scan[2] == 'p' && scan[3] == 't')))
278360484Sobrien    {
278460484Sobrien      /* EDG-style parameterized type.  Handled later as a signature. */
278560484Sobrien      success = 1;
278660484Sobrien
278760484Sobrien      /* EDG template? */
278860484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
278960484Sobrien    }
279077298Sobrien  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
279160484Sobrien	   && (scan[2] != 't'))
279260484Sobrien    {
279333965Sjdp      /* Mangled name starts with "__".  Skip over any leading '_' characters,
279433965Sjdp	 then find the next "__" that separates the prefix from the signature.
279533965Sjdp	 */
279660484Sobrien      if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
279760484Sobrien	  || (arm_special (mangled, declp) == 0))
279833965Sjdp	{
279933965Sjdp	  while (*scan == '_')
280033965Sjdp	    {
280133965Sjdp	      scan++;
280233965Sjdp	    }
280389857Sobrien	  if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
280433965Sjdp	    {
280533965Sjdp	      /* No separator (I.E. "__not_mangled"), or empty signature
280633965Sjdp		 (I.E. "__not_mangled_either__") */
280733965Sjdp	      success = 0;
280833965Sjdp	    }
280933965Sjdp	  else
281068765Sobrien	    return iterate_demangle_function (work, mangled, declp, scan);
281133965Sjdp	}
281233965Sjdp    }
281333965Sjdp  else if (*(scan + 2) != '\0')
281433965Sjdp    {
281533965Sjdp      /* Mangled name does not start with "__" but does have one somewhere
281633965Sjdp	 in there with non empty stuff after it.  Looks like a global
281768765Sobrien	 function name.  Iterate over all "__":s until the right
281868765Sobrien	 one is found.  */
281968765Sobrien      return iterate_demangle_function (work, mangled, declp, scan);
282033965Sjdp    }
282133965Sjdp  else
282233965Sjdp    {
282333965Sjdp      /* Doesn't look like a mangled name */
282433965Sjdp      success = 0;
282533965Sjdp    }
282633965Sjdp
282733965Sjdp  if (!success && (work->constructor == 2 || work->destructor == 2))
282833965Sjdp    {
282933965Sjdp      string_append (declp, *mangled);
283033965Sjdp      *mangled += strlen (*mangled);
283133965Sjdp      success = 1;
283260484Sobrien    }
283333965Sjdp  return (success);
283433965Sjdp}
283533965Sjdp
283633965Sjdp/*
283733965Sjdp
283833965SjdpLOCAL FUNCTION
283933965Sjdp
284033965Sjdp	gnu_special -- special handling of gnu mangled strings
284133965Sjdp
284233965SjdpSYNOPSIS
284333965Sjdp
284433965Sjdp	static int
284533965Sjdp	gnu_special (struct work_stuff *work, const char **mangled,
284633965Sjdp		     string *declp);
284733965Sjdp
284833965Sjdp
284933965SjdpDESCRIPTION
285033965Sjdp
285133965Sjdp	Process some special GNU style mangling forms that don't fit
285233965Sjdp	the normal pattern.  For example:
285333965Sjdp
285433965Sjdp		_$_3foo		(destructor for class foo)
285533965Sjdp		_vt$foo		(foo virtual table)
285633965Sjdp		_vt$foo$bar	(foo::bar virtual table)
285733965Sjdp		__vt_foo	(foo virtual table, new style with thunks)
285833965Sjdp		_3foo$varname	(static data member)
285933965Sjdp		_Q22rs2tu$vw	(static data member)
286033965Sjdp		__t6vector1Zii	(constructor with template)
286133965Sjdp		__thunk_4__$_7ostream (virtual function thunk)
286233965Sjdp */
286333965Sjdp
286433965Sjdpstatic int
286533965Sjdpgnu_special (work, mangled, declp)
286633965Sjdp     struct work_stuff *work;
286733965Sjdp     const char **mangled;
286833965Sjdp     string *declp;
286933965Sjdp{
287033965Sjdp  int n;
287133965Sjdp  int success = 1;
287233965Sjdp  const char *p;
287333965Sjdp
287433965Sjdp  if ((*mangled)[0] == '_'
287533965Sjdp      && strchr (cplus_markers, (*mangled)[1]) != NULL
287633965Sjdp      && (*mangled)[2] == '_')
287733965Sjdp    {
287833965Sjdp      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
287933965Sjdp      (*mangled) += 3;
288033965Sjdp      work -> destructor += 1;
288133965Sjdp    }
288233965Sjdp  else if ((*mangled)[0] == '_'
288333965Sjdp	   && (((*mangled)[1] == '_'
288433965Sjdp		&& (*mangled)[2] == 'v'
288533965Sjdp		&& (*mangled)[3] == 't'
288633965Sjdp		&& (*mangled)[4] == '_')
288733965Sjdp	       || ((*mangled)[1] == 'v'
288833965Sjdp		   && (*mangled)[2] == 't'
288933965Sjdp		   && strchr (cplus_markers, (*mangled)[3]) != NULL)))
289033965Sjdp    {
289133965Sjdp      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
289233965Sjdp         and create the decl.  Note that we consume the entire mangled
289333965Sjdp	 input string, which means that demangle_signature has no work
289433965Sjdp	 to do.  */
289533965Sjdp      if ((*mangled)[2] == 'v')
289633965Sjdp	(*mangled) += 5; /* New style, with thunks: "__vt_" */
289733965Sjdp      else
289833965Sjdp	(*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
289933965Sjdp      while (**mangled != '\0')
290033965Sjdp	{
290133965Sjdp	  switch (**mangled)
290233965Sjdp	    {
290333965Sjdp	    case 'Q':
290460484Sobrien	    case 'K':
290533965Sjdp	      success = demangle_qualified (work, mangled, declp, 0, 1);
290633965Sjdp	      break;
290733965Sjdp	    case 't':
290860484Sobrien	      success = demangle_template (work, mangled, declp, 0, 1,
290960484Sobrien					   1);
291033965Sjdp	      break;
291133965Sjdp	    default:
291277298Sobrien	      if (ISDIGIT((unsigned char)*mangled[0]))
291333965Sjdp		{
291433965Sjdp		  n = consume_count(mangled);
291538889Sjdp		  /* We may be seeing a too-large size, or else a
291638889Sjdp		     ".<digits>" indicating a static local symbol.  In
291738889Sjdp		     any case, declare victory and move on; *don't* try
291838889Sjdp		     to use n to allocate.  */
291960484Sobrien		  if (n > (int) strlen (*mangled))
292038889Sjdp		    {
292138889Sjdp		      success = 1;
292238889Sjdp		      break;
292338889Sjdp		    }
292433965Sjdp		}
292533965Sjdp	      else
292633965Sjdp		{
292733965Sjdp		  n = strcspn (*mangled, cplus_markers);
292833965Sjdp		}
292933965Sjdp	      string_appendn (declp, *mangled, n);
293033965Sjdp	      (*mangled) += n;
293133965Sjdp	    }
293233965Sjdp
293360484Sobrien	  p = strpbrk (*mangled, cplus_markers);
293433965Sjdp	  if (success && ((p == NULL) || (p == *mangled)))
293533965Sjdp	    {
293633965Sjdp	      if (p != NULL)
293733965Sjdp		{
293860484Sobrien		  string_append (declp, SCOPE_STRING (work));
293933965Sjdp		  (*mangled)++;
294033965Sjdp		}
294133965Sjdp	    }
294233965Sjdp	  else
294333965Sjdp	    {
294433965Sjdp	      success = 0;
294533965Sjdp	      break;
294633965Sjdp	    }
294733965Sjdp	}
294833965Sjdp      if (success)
294933965Sjdp	string_append (declp, " virtual table");
295033965Sjdp    }
295133965Sjdp  else if ((*mangled)[0] == '_'
295233965Sjdp	   && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
295333965Sjdp	   && (p = strpbrk (*mangled, cplus_markers)) != NULL)
295433965Sjdp    {
295533965Sjdp      /* static data member, "_3foo$varname" for example */
295633965Sjdp      (*mangled)++;
295733965Sjdp      switch (**mangled)
295833965Sjdp	{
295933965Sjdp	case 'Q':
296060484Sobrien	case 'K':
296133965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
296233965Sjdp	  break;
296333965Sjdp	case 't':
296460484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
296533965Sjdp	  break;
296633965Sjdp	default:
296733965Sjdp	  n = consume_count (mangled);
296860484Sobrien	  if (n < 0 || n > (long) strlen (*mangled))
296960484Sobrien	    {
297060484Sobrien	      success = 0;
297160484Sobrien	      break;
297260484Sobrien	    }
297368765Sobrien
297468765Sobrien	  if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
297568765Sobrien	      && (*mangled)[9] == 'N'
297668765Sobrien	      && (*mangled)[8] == (*mangled)[10]
297768765Sobrien	      && strchr (cplus_markers, (*mangled)[8]))
297868765Sobrien	    {
297968765Sobrien	      /* A member of the anonymous namespace.  There's information
298068765Sobrien		 about what identifier or filename it was keyed to, but
298168765Sobrien		 it's just there to make the mangled name unique; we just
298268765Sobrien		 step over it.  */
298368765Sobrien	      string_append (declp, "{anonymous}");
298468765Sobrien	      (*mangled) += n;
298568765Sobrien
298668765Sobrien	      /* Now p points to the marker before the N, so we need to
298768765Sobrien		 update it to the first marker after what we consumed.  */
298868765Sobrien	      p = strpbrk (*mangled, cplus_markers);
298968765Sobrien	      break;
299068765Sobrien	    }
299168765Sobrien
299233965Sjdp	  string_appendn (declp, *mangled, n);
299333965Sjdp	  (*mangled) += n;
299433965Sjdp	}
299533965Sjdp      if (success && (p == *mangled))
299633965Sjdp	{
299733965Sjdp	  /* Consumed everything up to the cplus_marker, append the
299833965Sjdp	     variable name.  */
299933965Sjdp	  (*mangled)++;
300060484Sobrien	  string_append (declp, SCOPE_STRING (work));
300133965Sjdp	  n = strlen (*mangled);
300233965Sjdp	  string_appendn (declp, *mangled, n);
300333965Sjdp	  (*mangled) += n;
300433965Sjdp	}
300533965Sjdp      else
300633965Sjdp	{
300733965Sjdp	  success = 0;
300833965Sjdp	}
300933965Sjdp    }
301033965Sjdp  else if (strncmp (*mangled, "__thunk_", 8) == 0)
301133965Sjdp    {
301260484Sobrien      int delta;
301360484Sobrien
301460484Sobrien      (*mangled) += 8;
301560484Sobrien      delta = consume_count (mangled);
301660484Sobrien      if (delta == -1)
301760484Sobrien	success = 0;
301833965Sjdp      else
301933965Sjdp	{
302060484Sobrien	  char *method = internal_cplus_demangle (work, ++*mangled);
302160484Sobrien
302260484Sobrien	  if (method)
302360484Sobrien	    {
302460484Sobrien	      char buf[50];
302560484Sobrien	      sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
302660484Sobrien	      string_append (declp, buf);
302760484Sobrien	      string_append (declp, method);
302860484Sobrien	      free (method);
302960484Sobrien	      n = strlen (*mangled);
303060484Sobrien	      (*mangled) += n;
303160484Sobrien	    }
303260484Sobrien	  else
303360484Sobrien	    {
303460484Sobrien	      success = 0;
303560484Sobrien	    }
303633965Sjdp	}
303733965Sjdp    }
303833965Sjdp  else if (strncmp (*mangled, "__t", 3) == 0
303933965Sjdp	   && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
304033965Sjdp    {
304133965Sjdp      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
304233965Sjdp      (*mangled) += 4;
304333965Sjdp      switch (**mangled)
304433965Sjdp	{
304533965Sjdp	case 'Q':
304660484Sobrien	case 'K':
304733965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
304833965Sjdp	  break;
304933965Sjdp	case 't':
305060484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
305133965Sjdp	  break;
305233965Sjdp	default:
305368765Sobrien	  success = do_type (work, mangled, declp);
305433965Sjdp	  break;
305533965Sjdp	}
305633965Sjdp      if (success && **mangled != '\0')
305733965Sjdp	success = 0;
305833965Sjdp      if (success)
305933965Sjdp	string_append (declp, p);
306033965Sjdp    }
306133965Sjdp  else
306233965Sjdp    {
306333965Sjdp      success = 0;
306433965Sjdp    }
306533965Sjdp  return (success);
306633965Sjdp}
306733965Sjdp
306860484Sobrienstatic void
306960484Sobrienrecursively_demangle(work, mangled, result, namelength)
307060484Sobrien     struct work_stuff *work;
307160484Sobrien     const char **mangled;
307260484Sobrien     string *result;
307360484Sobrien     int namelength;
307460484Sobrien{
307560484Sobrien  char * recurse = (char *)NULL;
307660484Sobrien  char * recurse_dem = (char *)NULL;
307760484Sobrien
307860484Sobrien  recurse = (char *) xmalloc (namelength + 1);
307960484Sobrien  memcpy (recurse, *mangled, namelength);
308060484Sobrien  recurse[namelength] = '\000';
308160484Sobrien
308260484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
308360484Sobrien
308460484Sobrien  if (recurse_dem)
308560484Sobrien    {
308660484Sobrien      string_append (result, recurse_dem);
308760484Sobrien      free (recurse_dem);
308860484Sobrien    }
308960484Sobrien  else
309060484Sobrien    {
309160484Sobrien      string_appendn (result, *mangled, namelength);
309260484Sobrien    }
309360484Sobrien  free (recurse);
309460484Sobrien  *mangled += namelength;
309560484Sobrien}
309660484Sobrien
309733965Sjdp/*
309833965Sjdp
309933965SjdpLOCAL FUNCTION
310033965Sjdp
310133965Sjdp	arm_special -- special handling of ARM/lucid mangled strings
310233965Sjdp
310333965SjdpSYNOPSIS
310433965Sjdp
310533965Sjdp	static int
310660484Sobrien	arm_special (const char **mangled,
310760484Sobrien		     string *declp);
310833965Sjdp
310933965Sjdp
311033965SjdpDESCRIPTION
311133965Sjdp
311233965Sjdp	Process some special ARM style mangling forms that don't fit
311333965Sjdp	the normal pattern.  For example:
311433965Sjdp
311533965Sjdp		__vtbl__3foo		(foo virtual table)
311633965Sjdp		__vtbl__3foo__3bar	(bar::foo virtual table)
311733965Sjdp
311833965Sjdp */
311933965Sjdp
312033965Sjdpstatic int
312160484Sobrienarm_special (mangled, declp)
312233965Sjdp     const char **mangled;
312333965Sjdp     string *declp;
312433965Sjdp{
312533965Sjdp  int n;
312633965Sjdp  int success = 1;
312733965Sjdp  const char *scan;
312833965Sjdp
312933965Sjdp  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
313033965Sjdp    {
313133965Sjdp      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
313233965Sjdp         and create the decl.  Note that we consume the entire mangled
313333965Sjdp	 input string, which means that demangle_signature has no work
313433965Sjdp	 to do.  */
313533965Sjdp      scan = *mangled + ARM_VTABLE_STRLEN;
313633965Sjdp      while (*scan != '\0')        /* first check it can be demangled */
313733965Sjdp        {
313833965Sjdp          n = consume_count (&scan);
313960484Sobrien          if (n == -1)
314033965Sjdp	    {
314133965Sjdp	      return (0);           /* no good */
314233965Sjdp	    }
314333965Sjdp          scan += n;
314433965Sjdp          if (scan[0] == '_' && scan[1] == '_')
314533965Sjdp	    {
314633965Sjdp	      scan += 2;
314733965Sjdp	    }
314833965Sjdp        }
314933965Sjdp      (*mangled) += ARM_VTABLE_STRLEN;
315033965Sjdp      while (**mangled != '\0')
315133965Sjdp	{
315233965Sjdp	  n = consume_count (mangled);
315360484Sobrien          if (n == -1
315460484Sobrien	      || n > (long) strlen (*mangled))
315560484Sobrien	    return 0;
315633965Sjdp	  string_prependn (declp, *mangled, n);
315733965Sjdp	  (*mangled) += n;
315833965Sjdp	  if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
315933965Sjdp	    {
316033965Sjdp	      string_prepend (declp, "::");
316133965Sjdp	      (*mangled) += 2;
316233965Sjdp	    }
316333965Sjdp	}
316433965Sjdp      string_append (declp, " virtual table");
316533965Sjdp    }
316633965Sjdp  else
316733965Sjdp    {
316833965Sjdp      success = 0;
316933965Sjdp    }
317033965Sjdp  return (success);
317133965Sjdp}
317233965Sjdp
317333965Sjdp/*
317433965Sjdp
317533965SjdpLOCAL FUNCTION
317633965Sjdp
317733965Sjdp	demangle_qualified -- demangle 'Q' qualified name strings
317833965Sjdp
317933965SjdpSYNOPSIS
318033965Sjdp
318133965Sjdp	static int
318233965Sjdp	demangle_qualified (struct work_stuff *, const char *mangled,
318333965Sjdp			    string *result, int isfuncname, int append);
318433965Sjdp
318533965SjdpDESCRIPTION
318633965Sjdp
318733965Sjdp	Demangle a qualified name, such as "Q25Outer5Inner" which is
318833965Sjdp	the mangled form of "Outer::Inner".  The demangled output is
318933965Sjdp	prepended or appended to the result string according to the
319033965Sjdp	state of the append flag.
319133965Sjdp
319233965Sjdp	If isfuncname is nonzero, then the qualified name we are building
319333965Sjdp	is going to be used as a member function name, so if it is a
319433965Sjdp	constructor or destructor function, append an appropriate
319533965Sjdp	constructor or destructor name.  I.E. for the above example,
319633965Sjdp	the result for use as a constructor is "Outer::Inner::Inner"
319733965Sjdp	and the result for use as a destructor is "Outer::Inner::~Inner".
319833965Sjdp
319933965SjdpBUGS
320033965Sjdp
320133965Sjdp	Numeric conversion is ASCII dependent (FIXME).
320233965Sjdp
320333965Sjdp */
320433965Sjdp
320533965Sjdpstatic int
320633965Sjdpdemangle_qualified (work, mangled, result, isfuncname, append)
320733965Sjdp     struct work_stuff *work;
320833965Sjdp     const char **mangled;
320933965Sjdp     string *result;
321033965Sjdp     int isfuncname;
321133965Sjdp     int append;
321233965Sjdp{
321360484Sobrien  int qualifiers = 0;
321433965Sjdp  int success = 1;
321533965Sjdp  char num[2];
321633965Sjdp  string temp;
321760484Sobrien  string last_name;
321860484Sobrien  int bindex = register_Btype (work);
321933965Sjdp
322060484Sobrien  /* We only make use of ISFUNCNAME if the entity is a constructor or
322160484Sobrien     destructor.  */
322260484Sobrien  isfuncname = (isfuncname
322360484Sobrien		&& ((work->constructor & 1) || (work->destructor & 1)));
322460484Sobrien
322533965Sjdp  string_init (&temp);
322660484Sobrien  string_init (&last_name);
322760484Sobrien
322860484Sobrien  if ((*mangled)[0] == 'K')
322933965Sjdp    {
323060484Sobrien    /* Squangling qualified name reuse */
323160484Sobrien      int idx;
323260484Sobrien      (*mangled)++;
323360484Sobrien      idx = consume_count_with_underscores (mangled);
323460484Sobrien      if (idx == -1 || idx >= work -> numk)
323560484Sobrien        success = 0;
323660484Sobrien      else
323760484Sobrien        string_append (&temp, work -> ktypevec[idx]);
323860484Sobrien    }
323960484Sobrien  else
324060484Sobrien    switch ((*mangled)[1])
324160484Sobrien    {
324233965Sjdp    case '_':
324333965Sjdp      /* GNU mangled name with more than 9 classes.  The count is preceded
324433965Sjdp	 by an underscore (to distinguish it from the <= 9 case) and followed
324533965Sjdp	 by an underscore.  */
324660484Sobrien      (*mangled)++;
324760484Sobrien      qualifiers = consume_count_with_underscores (mangled);
324860484Sobrien      if (qualifiers == -1)
324933965Sjdp	success = 0;
325033965Sjdp      break;
325133965Sjdp
325233965Sjdp    case '1':
325333965Sjdp    case '2':
325433965Sjdp    case '3':
325533965Sjdp    case '4':
325633965Sjdp    case '5':
325733965Sjdp    case '6':
325833965Sjdp    case '7':
325933965Sjdp    case '8':
326033965Sjdp    case '9':
326133965Sjdp      /* The count is in a single digit.  */
326233965Sjdp      num[0] = (*mangled)[1];
326333965Sjdp      num[1] = '\0';
326433965Sjdp      qualifiers = atoi (num);
326533965Sjdp
326633965Sjdp      /* If there is an underscore after the digit, skip it.  This is
326733965Sjdp	 said to be for ARM-qualified names, but the ARM makes no
326833965Sjdp	 mention of such an underscore.  Perhaps cfront uses one.  */
326933965Sjdp      if ((*mangled)[2] == '_')
327033965Sjdp	{
327133965Sjdp	  (*mangled)++;
327233965Sjdp	}
327333965Sjdp      (*mangled) += 2;
327433965Sjdp      break;
327533965Sjdp
327633965Sjdp    case '0':
327733965Sjdp    default:
327833965Sjdp      success = 0;
327933965Sjdp    }
328033965Sjdp
328133965Sjdp  if (!success)
328233965Sjdp    return success;
328333965Sjdp
328433965Sjdp  /* Pick off the names and collect them in the temp buffer in the order
328533965Sjdp     in which they are found, separated by '::'.  */
328633965Sjdp
328733965Sjdp  while (qualifiers-- > 0)
328833965Sjdp    {
328960484Sobrien      int remember_K = 1;
329060484Sobrien      string_clear (&last_name);
329160484Sobrien
329260484Sobrien      if (*mangled[0] == '_')
329360484Sobrien	(*mangled)++;
329460484Sobrien
329533965Sjdp      if (*mangled[0] == 't')
329633965Sjdp	{
329760484Sobrien	  /* Here we always append to TEMP since we will want to use
329860484Sobrien	     the template name without the template parameters as a
329960484Sobrien	     constructor or destructor name.  The appropriate
330060484Sobrien	     (parameter-less) value is returned by demangle_template
330160484Sobrien	     in LAST_NAME.  We do not remember the template type here,
330260484Sobrien	     in order to match the G++ mangling algorithm.  */
330360484Sobrien	  success = demangle_template(work, mangled, &temp,
330460484Sobrien				      &last_name, 1, 0);
330560484Sobrien	  if (!success)
330660484Sobrien	    break;
330733965Sjdp	}
330860484Sobrien      else if (*mangled[0] == 'K')
330938889Sjdp	{
331060484Sobrien          int idx;
331160484Sobrien          (*mangled)++;
331260484Sobrien          idx = consume_count_with_underscores (mangled);
331360484Sobrien          if (idx == -1 || idx >= work->numk)
331460484Sobrien            success = 0;
331560484Sobrien          else
331660484Sobrien            string_append (&temp, work->ktypevec[idx]);
331760484Sobrien          remember_K = 0;
331860484Sobrien
331938889Sjdp	  if (!success) break;
332038889Sjdp	}
332133965Sjdp      else
332260484Sobrien	{
332360484Sobrien	  if (EDG_DEMANGLING)
332460484Sobrien            {
332560484Sobrien	      int namelength;
332660484Sobrien 	      /* Now recursively demangle the qualifier
332760484Sobrien 	       * This is necessary to deal with templates in
332860484Sobrien 	       * mangling styles like EDG */
332960484Sobrien	      namelength = consume_count (mangled);
333060484Sobrien	      if (namelength == -1)
333160484Sobrien		{
333260484Sobrien		  success = 0;
333360484Sobrien		  break;
333460484Sobrien		}
333560484Sobrien 	      recursively_demangle(work, mangled, &temp, namelength);
333660484Sobrien            }
333760484Sobrien          else
333860484Sobrien            {
333960484Sobrien              success = do_type (work, mangled, &last_name);
334060484Sobrien              if (!success)
334160484Sobrien                break;
334260484Sobrien              string_appends (&temp, &last_name);
334360484Sobrien            }
334433965Sjdp	}
334560484Sobrien
334660484Sobrien      if (remember_K)
334760484Sobrien	remember_Ktype (work, temp.b, LEN_STRING (&temp));
334860484Sobrien
334933965Sjdp      if (qualifiers > 0)
335060484Sobrien	string_append (&temp, SCOPE_STRING (work));
335133965Sjdp    }
335233965Sjdp
335360484Sobrien  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
335460484Sobrien
335533965Sjdp  /* If we are using the result as a function name, we need to append
335633965Sjdp     the appropriate '::' separated constructor or destructor name.
335733965Sjdp     We do this here because this is the most convenient place, where
335833965Sjdp     we already have a pointer to the name and the length of the name.  */
335933965Sjdp
336060484Sobrien  if (isfuncname)
336133965Sjdp    {
336260484Sobrien      string_append (&temp, SCOPE_STRING (work));
336333965Sjdp      if (work -> destructor & 1)
336460484Sobrien	string_append (&temp, "~");
336560484Sobrien      string_appends (&temp, &last_name);
336633965Sjdp    }
336733965Sjdp
336860484Sobrien  /* Now either prepend the temp buffer to the result, or append it,
336933965Sjdp     depending upon the state of the append flag.  */
337033965Sjdp
337133965Sjdp  if (append)
337260484Sobrien    string_appends (result, &temp);
337333965Sjdp  else
337433965Sjdp    {
337533965Sjdp      if (!STRING_EMPTY (result))
337660484Sobrien	string_append (&temp, SCOPE_STRING (work));
337733965Sjdp      string_prepends (result, &temp);
337833965Sjdp    }
337933965Sjdp
338060484Sobrien  string_delete (&last_name);
338133965Sjdp  string_delete (&temp);
338233965Sjdp  return (success);
338333965Sjdp}
338433965Sjdp
338533965Sjdp/*
338633965Sjdp
338733965SjdpLOCAL FUNCTION
338833965Sjdp
338933965Sjdp	get_count -- convert an ascii count to integer, consuming tokens
339033965Sjdp
339133965SjdpSYNOPSIS
339233965Sjdp
339333965Sjdp	static int
339433965Sjdp	get_count (const char **type, int *count)
339533965Sjdp
339633965SjdpDESCRIPTION
339733965Sjdp
339860484Sobrien	Assume that *type points at a count in a mangled name; set
339960484Sobrien	*count to its value, and set *type to the next character after
340060484Sobrien	the count.  There are some weird rules in effect here.
340160484Sobrien
340260484Sobrien	If *type does not point at a string of digits, return zero.
340360484Sobrien
340460484Sobrien	If *type points at a string of digits followed by an
340560484Sobrien	underscore, set *count to their value as an integer, advance
340660484Sobrien	*type to point *after the underscore, and return 1.
340760484Sobrien
340860484Sobrien	If *type points at a string of digits not followed by an
340960484Sobrien	underscore, consume only the first digit.  Set *count to its
341060484Sobrien	value as an integer, leave *type pointing after that digit,
341160484Sobrien	and return 1.
341260484Sobrien
341360484Sobrien        The excuse for this odd behavior: in the ARM and HP demangling
341460484Sobrien        styles, a type can be followed by a repeat count of the form
341560484Sobrien        `Nxy', where:
341660484Sobrien
341760484Sobrien        `x' is a single digit specifying how many additional copies
341860484Sobrien            of the type to append to the argument list, and
341960484Sobrien
342060484Sobrien        `y' is one or more digits, specifying the zero-based index of
342160484Sobrien            the first repeated argument in the list.  Yes, as you're
342260484Sobrien            unmangling the name you can figure this out yourself, but
342360484Sobrien            it's there anyway.
342460484Sobrien
342560484Sobrien        So, for example, in `bar__3fooFPiN51', the first argument is a
342660484Sobrien        pointer to an integer (`Pi'), and then the next five arguments
342760484Sobrien        are the same (`N5'), and the first repeat is the function's
342860484Sobrien        second argument (`1').
342933965Sjdp*/
343033965Sjdp
343133965Sjdpstatic int
343233965Sjdpget_count (type, count)
343333965Sjdp     const char **type;
343433965Sjdp     int *count;
343533965Sjdp{
343633965Sjdp  const char *p;
343733965Sjdp  int n;
343833965Sjdp
343977298Sobrien  if (!ISDIGIT ((unsigned char)**type))
344060484Sobrien    return (0);
344133965Sjdp  else
344233965Sjdp    {
344333965Sjdp      *count = **type - '0';
344433965Sjdp      (*type)++;
344577298Sobrien      if (ISDIGIT ((unsigned char)**type))
344633965Sjdp	{
344733965Sjdp	  p = *type;
344833965Sjdp	  n = *count;
344960484Sobrien	  do
345033965Sjdp	    {
345133965Sjdp	      n *= 10;
345233965Sjdp	      n += *p - '0';
345333965Sjdp	      p++;
345460484Sobrien	    }
345577298Sobrien	  while (ISDIGIT ((unsigned char)*p));
345633965Sjdp	  if (*p == '_')
345733965Sjdp	    {
345833965Sjdp	      *type = p + 1;
345933965Sjdp	      *count = n;
346033965Sjdp	    }
346133965Sjdp	}
346233965Sjdp    }
346333965Sjdp  return (1);
346433965Sjdp}
346533965Sjdp
346660484Sobrien/* RESULT will be initialised here; it will be freed on failure.  The
346760484Sobrien   value returned is really a type_kind_t.  */
346833965Sjdp
346933965Sjdpstatic int
347033965Sjdpdo_type (work, mangled, result)
347133965Sjdp     struct work_stuff *work;
347233965Sjdp     const char **mangled;
347333965Sjdp     string *result;
347433965Sjdp{
347533965Sjdp  int n;
347633965Sjdp  int done;
347733965Sjdp  int success;
347833965Sjdp  string decl;
347933965Sjdp  const char *remembered_type;
348060484Sobrien  int type_quals;
348160484Sobrien  string btype;
348260484Sobrien  type_kind_t tk = tk_none;
348333965Sjdp
348460484Sobrien  string_init (&btype);
348533965Sjdp  string_init (&decl);
348633965Sjdp  string_init (result);
348733965Sjdp
348833965Sjdp  done = 0;
348933965Sjdp  success = 1;
349033965Sjdp  while (success && !done)
349133965Sjdp    {
349233965Sjdp      int member;
349333965Sjdp      switch (**mangled)
349433965Sjdp	{
349533965Sjdp
349633965Sjdp	  /* A pointer type */
349733965Sjdp	case 'P':
349833965Sjdp	case 'p':
349933965Sjdp	  (*mangled)++;
350038889Sjdp	  if (! (work -> options & DMGL_JAVA))
350138889Sjdp	    string_prepend (&decl, "*");
350260484Sobrien	  if (tk == tk_none)
350360484Sobrien	    tk = tk_pointer;
350433965Sjdp	  break;
350533965Sjdp
350633965Sjdp	  /* A reference type */
350733965Sjdp	case 'R':
350833965Sjdp	  (*mangled)++;
350933965Sjdp	  string_prepend (&decl, "&");
351060484Sobrien	  if (tk == tk_none)
351160484Sobrien	    tk = tk_reference;
351233965Sjdp	  break;
351333965Sjdp
351433965Sjdp	  /* An array */
351533965Sjdp	case 'A':
351633965Sjdp	  {
351760484Sobrien	    ++(*mangled);
351860484Sobrien	    if (!STRING_EMPTY (&decl)
351960484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
352033965Sjdp	      {
352160484Sobrien		string_prepend (&decl, "(");
352260484Sobrien		string_append (&decl, ")");
352333965Sjdp	      }
352460484Sobrien	    string_append (&decl, "[");
352560484Sobrien	    if (**mangled != '_')
352660484Sobrien	      success = demangle_template_value_parm (work, mangled, &decl,
352760484Sobrien						      tk_integral);
352860484Sobrien	    if (**mangled == '_')
352960484Sobrien	      ++(*mangled);
353060484Sobrien	    string_append (&decl, "]");
353133965Sjdp	    break;
353233965Sjdp	  }
353333965Sjdp
353433965Sjdp	/* A back reference to a previously seen type */
353533965Sjdp	case 'T':
353633965Sjdp	  (*mangled)++;
353733965Sjdp	  if (!get_count (mangled, &n) || n >= work -> ntypes)
353833965Sjdp	    {
353933965Sjdp	      success = 0;
354033965Sjdp	    }
354133965Sjdp	  else
354233965Sjdp	    {
354333965Sjdp	      remembered_type = work -> typevec[n];
354433965Sjdp	      mangled = &remembered_type;
354533965Sjdp	    }
354633965Sjdp	  break;
354733965Sjdp
354833965Sjdp	  /* A function */
354933965Sjdp	case 'F':
355033965Sjdp	  (*mangled)++;
355160484Sobrien	    if (!STRING_EMPTY (&decl)
355260484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
355333965Sjdp	    {
355433965Sjdp	      string_prepend (&decl, "(");
355533965Sjdp	      string_append (&decl, ")");
355633965Sjdp	    }
355733965Sjdp	  /* After picking off the function args, we expect to either find the
355833965Sjdp	     function return type (preceded by an '_') or the end of the
355933965Sjdp	     string.  */
356060484Sobrien	  if (!demangle_nested_args (work, mangled, &decl)
356133965Sjdp	      || (**mangled != '_' && **mangled != '\0'))
356233965Sjdp	    {
356333965Sjdp	      success = 0;
356460484Sobrien	      break;
356533965Sjdp	    }
356633965Sjdp	  if (success && (**mangled == '_'))
356760484Sobrien	    (*mangled)++;
356833965Sjdp	  break;
356933965Sjdp
357033965Sjdp	case 'M':
357133965Sjdp	case 'O':
357233965Sjdp	  {
357360484Sobrien	    type_quals = TYPE_UNQUALIFIED;
357433965Sjdp
357533965Sjdp	    member = **mangled == 'M';
357633965Sjdp	    (*mangled)++;
357733965Sjdp
357833965Sjdp	    string_append (&decl, ")");
357960484Sobrien
358060484Sobrien	    /* We don't need to prepend `::' for a qualified name;
358160484Sobrien	       demangle_qualified will do that for us.  */
358260484Sobrien	    if (**mangled != 'Q')
358360484Sobrien	      string_prepend (&decl, SCOPE_STRING (work));
358460484Sobrien
358577298Sobrien	    if (ISDIGIT ((unsigned char)**mangled))
358633965Sjdp	      {
358733965Sjdp		n = consume_count (mangled);
358860484Sobrien		if (n == -1
358960484Sobrien		    || (int) strlen (*mangled) < n)
359033965Sjdp		  {
359133965Sjdp		    success = 0;
359233965Sjdp		    break;
359333965Sjdp		  }
359433965Sjdp		string_prependn (&decl, *mangled, n);
359533965Sjdp		*mangled += n;
359633965Sjdp	      }
359760484Sobrien	    else if (**mangled == 'X' || **mangled == 'Y')
359833965Sjdp	      {
359933965Sjdp		string temp;
360060484Sobrien		do_type (work, mangled, &temp);
360160484Sobrien		string_prepends (&decl, &temp);
360260484Sobrien	      }
360360484Sobrien	    else if (**mangled == 't')
360460484Sobrien	      {
360560484Sobrien		string temp;
360633965Sjdp		string_init (&temp);
360760484Sobrien		success = demangle_template (work, mangled, &temp,
360860484Sobrien					     NULL, 1, 1);
360933965Sjdp		if (success)
361033965Sjdp		  {
361133965Sjdp		    string_prependn (&decl, temp.b, temp.p - temp.b);
361233965Sjdp		    string_clear (&temp);
361333965Sjdp		  }
361433965Sjdp		else
361533965Sjdp		  break;
361633965Sjdp	      }
361760484Sobrien	    else if (**mangled == 'Q')
361860484Sobrien	      {
361960484Sobrien		success = demangle_qualified (work, mangled, &decl,
362060484Sobrien					      /*isfuncnam=*/0,
362160484Sobrien					      /*append=*/0);
362260484Sobrien		if (!success)
362360484Sobrien		  break;
362460484Sobrien	      }
362560484Sobrien	    else
362660484Sobrien	      {
362760484Sobrien		success = 0;
362860484Sobrien		break;
362960484Sobrien	      }
363060484Sobrien
363133965Sjdp	    string_prepend (&decl, "(");
363233965Sjdp	    if (member)
363333965Sjdp	      {
363460484Sobrien		switch (**mangled)
363533965Sjdp		  {
363660484Sobrien		  case 'C':
363760484Sobrien		  case 'V':
363860484Sobrien		  case 'u':
363960484Sobrien		    type_quals |= code_for_qualifier (**mangled);
364033965Sjdp		    (*mangled)++;
364160484Sobrien		    break;
364260484Sobrien
364360484Sobrien		  default:
364460484Sobrien		    break;
364533965Sjdp		  }
364660484Sobrien
364733965Sjdp		if (*(*mangled)++ != 'F')
364833965Sjdp		  {
364933965Sjdp		    success = 0;
365033965Sjdp		    break;
365133965Sjdp		  }
365233965Sjdp	      }
365360484Sobrien	    if ((member && !demangle_nested_args (work, mangled, &decl))
365433965Sjdp		|| **mangled != '_')
365533965Sjdp	      {
365633965Sjdp		success = 0;
365733965Sjdp		break;
365833965Sjdp	      }
365933965Sjdp	    (*mangled)++;
366033965Sjdp	    if (! PRINT_ANSI_QUALIFIERS)
366133965Sjdp	      {
366233965Sjdp		break;
366333965Sjdp	      }
366460484Sobrien	    if (type_quals != TYPE_UNQUALIFIED)
366533965Sjdp	      {
366633965Sjdp		APPEND_BLANK (&decl);
366760484Sobrien		string_append (&decl, qualifier_string (type_quals));
366833965Sjdp	      }
366933965Sjdp	    break;
367033965Sjdp	  }
367133965Sjdp        case 'G':
367233965Sjdp	  (*mangled)++;
367333965Sjdp	  break;
367433965Sjdp
367533965Sjdp	case 'C':
367660484Sobrien	case 'V':
367760484Sobrien	case 'u':
367833965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
367933965Sjdp	    {
368033965Sjdp	      if (!STRING_EMPTY (&decl))
368160484Sobrien		string_prepend (&decl, " ");
368260484Sobrien
368360484Sobrien	      string_prepend (&decl, demangle_qualifier (**mangled));
368433965Sjdp	    }
368560484Sobrien	  (*mangled)++;
368633965Sjdp	  break;
368733965Sjdp	  /*
368833965Sjdp	    }
368933965Sjdp	    */
369033965Sjdp
369133965Sjdp	  /* fall through */
369233965Sjdp	default:
369333965Sjdp	  done = 1;
369433965Sjdp	  break;
369533965Sjdp	}
369633965Sjdp    }
369733965Sjdp
369860484Sobrien  if (success) switch (**mangled)
369933965Sjdp    {
370033965Sjdp      /* A qualified name, such as "Outer::Inner".  */
370133965Sjdp    case 'Q':
370260484Sobrien    case 'K':
370360484Sobrien      {
370460484Sobrien        success = demangle_qualified (work, mangled, result, 0, 1);
370560484Sobrien        break;
370660484Sobrien      }
370760484Sobrien
370860484Sobrien    /* A back reference to a previously seen squangled type */
370960484Sobrien    case 'B':
371060484Sobrien      (*mangled)++;
371160484Sobrien      if (!get_count (mangled, &n) || n >= work -> numb)
371260484Sobrien	success = 0;
371360484Sobrien      else
371460484Sobrien	string_append (result, work->btypevec[n]);
371533965Sjdp      break;
371633965Sjdp
371738889Sjdp    case 'X':
371838889Sjdp    case 'Y':
371938889Sjdp      /* A template parm.  We substitute the corresponding argument. */
372038889Sjdp      {
372138889Sjdp	int idx;
372238889Sjdp
372338889Sjdp	(*mangled)++;
372438889Sjdp	idx = consume_count_with_underscores (mangled);
372538889Sjdp
372660484Sobrien	if (idx == -1
372738889Sjdp	    || (work->tmpl_argvec && idx >= work->ntmpl_args)
372838889Sjdp	    || consume_count_with_underscores (mangled) == -1)
372938889Sjdp	  {
373038889Sjdp	    success = 0;
373138889Sjdp	    break;
373238889Sjdp	  }
373338889Sjdp
373438889Sjdp	if (work->tmpl_argvec)
373538889Sjdp	  string_append (result, work->tmpl_argvec[idx]);
373638889Sjdp	else
373760484Sobrien	  string_append_template_idx (result, idx);
373838889Sjdp
373938889Sjdp	success = 1;
374038889Sjdp      }
374138889Sjdp    break;
374238889Sjdp
374333965Sjdp    default:
374433965Sjdp      success = demangle_fund_type (work, mangled, result);
374560484Sobrien      if (tk == tk_none)
374660484Sobrien	tk = (type_kind_t) success;
374733965Sjdp      break;
374833965Sjdp    }
374933965Sjdp
375033965Sjdp  if (success)
375133965Sjdp    {
375233965Sjdp      if (!STRING_EMPTY (&decl))
375333965Sjdp	{
375433965Sjdp	  string_append (result, " ");
375533965Sjdp	  string_appends (result, &decl);
375633965Sjdp	}
375733965Sjdp    }
375833965Sjdp  else
375960484Sobrien    string_delete (result);
376033965Sjdp  string_delete (&decl);
376160484Sobrien
376260484Sobrien  if (success)
376360484Sobrien    /* Assume an integral type, if we're not sure.  */
376460484Sobrien    return (int) ((tk == tk_none) ? tk_integral : tk);
376560484Sobrien  else
376660484Sobrien    return 0;
376733965Sjdp}
376833965Sjdp
376933965Sjdp/* Given a pointer to a type string that represents a fundamental type
377033965Sjdp   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
377133965Sjdp   string in which the demangled output is being built in RESULT, and
377233965Sjdp   the WORK structure, decode the types and add them to the result.
377333965Sjdp
377433965Sjdp   For example:
377533965Sjdp
377633965Sjdp   	"Ci"	=>	"const int"
377733965Sjdp	"Sl"	=>	"signed long"
377833965Sjdp	"CUs"	=>	"const unsigned short"
377933965Sjdp
378060484Sobrien   The value returned is really a type_kind_t.  */
378133965Sjdp
378233965Sjdpstatic int
378333965Sjdpdemangle_fund_type (work, mangled, result)
378433965Sjdp     struct work_stuff *work;
378533965Sjdp     const char **mangled;
378633965Sjdp     string *result;
378733965Sjdp{
378833965Sjdp  int done = 0;
378933965Sjdp  int success = 1;
379060484Sobrien  char buf[10];
379168765Sobrien  unsigned int dec = 0;
379260484Sobrien  string btype;
379360484Sobrien  type_kind_t tk = tk_integral;
379433965Sjdp
379560484Sobrien  string_init (&btype);
379660484Sobrien
379733965Sjdp  /* First pick off any type qualifiers.  There can be more than one.  */
379833965Sjdp
379933965Sjdp  while (!done)
380033965Sjdp    {
380133965Sjdp      switch (**mangled)
380233965Sjdp	{
380333965Sjdp	case 'C':
380460484Sobrien	case 'V':
380560484Sobrien	case 'u':
380633965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
380733965Sjdp	    {
380860484Sobrien              if (!STRING_EMPTY (result))
380960484Sobrien                string_prepend (result, " ");
381060484Sobrien	      string_prepend (result, demangle_qualifier (**mangled));
381133965Sjdp	    }
381260484Sobrien	  (*mangled)++;
381333965Sjdp	  break;
381433965Sjdp	case 'U':
381533965Sjdp	  (*mangled)++;
381633965Sjdp	  APPEND_BLANK (result);
381733965Sjdp	  string_append (result, "unsigned");
381833965Sjdp	  break;
381933965Sjdp	case 'S': /* signed char only */
382033965Sjdp	  (*mangled)++;
382133965Sjdp	  APPEND_BLANK (result);
382233965Sjdp	  string_append (result, "signed");
382333965Sjdp	  break;
382438889Sjdp	case 'J':
382538889Sjdp	  (*mangled)++;
382638889Sjdp	  APPEND_BLANK (result);
382738889Sjdp	  string_append (result, "__complex");
382838889Sjdp	  break;
382933965Sjdp	default:
383033965Sjdp	  done = 1;
383133965Sjdp	  break;
383233965Sjdp	}
383333965Sjdp    }
383433965Sjdp
383533965Sjdp  /* Now pick off the fundamental type.  There can be only one.  */
383633965Sjdp
383733965Sjdp  switch (**mangled)
383833965Sjdp    {
383933965Sjdp    case '\0':
384033965Sjdp    case '_':
384133965Sjdp      break;
384233965Sjdp    case 'v':
384333965Sjdp      (*mangled)++;
384433965Sjdp      APPEND_BLANK (result);
384533965Sjdp      string_append (result, "void");
384633965Sjdp      break;
384733965Sjdp    case 'x':
384833965Sjdp      (*mangled)++;
384933965Sjdp      APPEND_BLANK (result);
385033965Sjdp      string_append (result, "long long");
385133965Sjdp      break;
385233965Sjdp    case 'l':
385333965Sjdp      (*mangled)++;
385433965Sjdp      APPEND_BLANK (result);
385533965Sjdp      string_append (result, "long");
385633965Sjdp      break;
385733965Sjdp    case 'i':
385833965Sjdp      (*mangled)++;
385933965Sjdp      APPEND_BLANK (result);
386033965Sjdp      string_append (result, "int");
386133965Sjdp      break;
386233965Sjdp    case 's':
386333965Sjdp      (*mangled)++;
386433965Sjdp      APPEND_BLANK (result);
386533965Sjdp      string_append (result, "short");
386633965Sjdp      break;
386733965Sjdp    case 'b':
386833965Sjdp      (*mangled)++;
386933965Sjdp      APPEND_BLANK (result);
387033965Sjdp      string_append (result, "bool");
387160484Sobrien      tk = tk_bool;
387233965Sjdp      break;
387333965Sjdp    case 'c':
387433965Sjdp      (*mangled)++;
387533965Sjdp      APPEND_BLANK (result);
387633965Sjdp      string_append (result, "char");
387760484Sobrien      tk = tk_char;
387833965Sjdp      break;
387933965Sjdp    case 'w':
388033965Sjdp      (*mangled)++;
388133965Sjdp      APPEND_BLANK (result);
388233965Sjdp      string_append (result, "wchar_t");
388360484Sobrien      tk = tk_char;
388433965Sjdp      break;
388533965Sjdp    case 'r':
388633965Sjdp      (*mangled)++;
388733965Sjdp      APPEND_BLANK (result);
388833965Sjdp      string_append (result, "long double");
388960484Sobrien      tk = tk_real;
389033965Sjdp      break;
389133965Sjdp    case 'd':
389233965Sjdp      (*mangled)++;
389333965Sjdp      APPEND_BLANK (result);
389433965Sjdp      string_append (result, "double");
389560484Sobrien      tk = tk_real;
389633965Sjdp      break;
389733965Sjdp    case 'f':
389833965Sjdp      (*mangled)++;
389933965Sjdp      APPEND_BLANK (result);
390033965Sjdp      string_append (result, "float");
390160484Sobrien      tk = tk_real;
390233965Sjdp      break;
390333965Sjdp    case 'G':
390433965Sjdp      (*mangled)++;
390577298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
390633965Sjdp	{
390733965Sjdp	  success = 0;
390833965Sjdp	  break;
390933965Sjdp	}
391060484Sobrien    case 'I':
391160484Sobrien      (*mangled)++;
391260484Sobrien      if (**mangled == '_')
391360484Sobrien	{
391460484Sobrien	  int i;
391560484Sobrien	  (*mangled)++;
391660484Sobrien	  for (i = 0;
391760484Sobrien	       i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
391860484Sobrien	       (*mangled)++, i++)
391960484Sobrien	    buf[i] = **mangled;
392060484Sobrien	  if (**mangled != '_')
392160484Sobrien	    {
392260484Sobrien	      success = 0;
392360484Sobrien	      break;
392460484Sobrien	    }
392560484Sobrien	  buf[i] = '\0';
392660484Sobrien	  (*mangled)++;
392760484Sobrien	}
392860484Sobrien      else
392960484Sobrien	{
393060484Sobrien	  strncpy (buf, *mangled, 2);
393160484Sobrien	  buf[2] = '\0';
393260484Sobrien	  *mangled += min (strlen (*mangled), 2);
393360484Sobrien	}
393460484Sobrien      sscanf (buf, "%x", &dec);
393568765Sobrien      sprintf (buf, "int%u_t", dec);
393660484Sobrien      APPEND_BLANK (result);
393760484Sobrien      string_append (result, buf);
393860484Sobrien      break;
393960484Sobrien
394033965Sjdp      /* fall through */
394133965Sjdp      /* An explicit type, such as "6mytype" or "7integer" */
394233965Sjdp    case '0':
394333965Sjdp    case '1':
394433965Sjdp    case '2':
394533965Sjdp    case '3':
394633965Sjdp    case '4':
394733965Sjdp    case '5':
394833965Sjdp    case '6':
394933965Sjdp    case '7':
395033965Sjdp    case '8':
395133965Sjdp    case '9':
395260484Sobrien      {
395360484Sobrien        int bindex = register_Btype (work);
395460484Sobrien        string btype;
395560484Sobrien        string_init (&btype);
395660484Sobrien        if (demangle_class_name (work, mangled, &btype)) {
395760484Sobrien          remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
395860484Sobrien          APPEND_BLANK (result);
395960484Sobrien          string_appends (result, &btype);
396060484Sobrien        }
396160484Sobrien        else
396260484Sobrien          success = 0;
396360484Sobrien        string_delete (&btype);
396460484Sobrien        break;
396533965Sjdp      }
396633965Sjdp    case 't':
396760484Sobrien      {
396860484Sobrien        success = demangle_template (work, mangled, &btype, 0, 1, 1);
396960484Sobrien        string_appends (result, &btype);
397060484Sobrien        break;
397160484Sobrien      }
397233965Sjdp    default:
397333965Sjdp      success = 0;
397433965Sjdp      break;
397533965Sjdp    }
397633965Sjdp
397760484Sobrien  return success ? ((int) tk) : 0;
397833965Sjdp}
397933965Sjdp
398033965Sjdp
398160484Sobrien/* Handle a template's value parameter for HP aCC (extension from ARM)
398260484Sobrien   **mangled points to 'S' or 'U' */
398360484Sobrien
398433965Sjdpstatic int
398560484Sobriendo_hpacc_template_const_value (work, mangled, result)
398660484Sobrien     struct work_stuff *work ATTRIBUTE_UNUSED;
398760484Sobrien     const char **mangled;
398860484Sobrien     string *result;
398960484Sobrien{
399060484Sobrien  int unsigned_const;
399160484Sobrien
399260484Sobrien  if (**mangled != 'U' && **mangled != 'S')
399360484Sobrien    return 0;
399460484Sobrien
399560484Sobrien  unsigned_const = (**mangled == 'U');
399660484Sobrien
399760484Sobrien  (*mangled)++;
399860484Sobrien
399960484Sobrien  switch (**mangled)
400060484Sobrien    {
400160484Sobrien      case 'N':
400260484Sobrien        string_append (result, "-");
400360484Sobrien        /* fall through */
400460484Sobrien      case 'P':
400560484Sobrien        (*mangled)++;
400660484Sobrien        break;
400760484Sobrien      case 'M':
400860484Sobrien        /* special case for -2^31 */
400960484Sobrien        string_append (result, "-2147483648");
401060484Sobrien        (*mangled)++;
401160484Sobrien        return 1;
401260484Sobrien      default:
401360484Sobrien        return 0;
401460484Sobrien    }
401560484Sobrien
401660484Sobrien  /* We have to be looking at an integer now */
401777298Sobrien  if (!(ISDIGIT ((unsigned char)**mangled)))
401860484Sobrien    return 0;
401960484Sobrien
402060484Sobrien  /* We only deal with integral values for template
402160484Sobrien     parameters -- so it's OK to look only for digits */
402277298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
402360484Sobrien    {
402460484Sobrien      char_str[0] = **mangled;
402560484Sobrien      string_append (result, char_str);
402660484Sobrien      (*mangled)++;
402760484Sobrien    }
402860484Sobrien
402960484Sobrien  if (unsigned_const)
403060484Sobrien    string_append (result, "U");
403160484Sobrien
403260484Sobrien  /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
403360484Sobrien     with L or LL suffixes. pai/1997-09-03 */
403460484Sobrien
403560484Sobrien  return 1; /* success */
403660484Sobrien}
403760484Sobrien
403860484Sobrien/* Handle a template's literal parameter for HP aCC (extension from ARM)
403960484Sobrien   **mangled is pointing to the 'A' */
404060484Sobrien
404160484Sobrienstatic int
404260484Sobriendo_hpacc_template_literal (work, mangled, result)
404360484Sobrien     struct work_stuff *work;
404460484Sobrien     const char **mangled;
404560484Sobrien     string *result;
404660484Sobrien{
404760484Sobrien  int literal_len = 0;
404860484Sobrien  char * recurse;
404960484Sobrien  char * recurse_dem;
405060484Sobrien
405160484Sobrien  if (**mangled != 'A')
405260484Sobrien    return 0;
405360484Sobrien
405460484Sobrien  (*mangled)++;
405560484Sobrien
405660484Sobrien  literal_len = consume_count (mangled);
405760484Sobrien
405860484Sobrien  if (literal_len <= 0)
405960484Sobrien    return 0;
406060484Sobrien
406160484Sobrien  /* Literal parameters are names of arrays, functions, etc.  and the
406260484Sobrien     canonical representation uses the address operator */
406360484Sobrien  string_append (result, "&");
406460484Sobrien
406560484Sobrien  /* Now recursively demangle the literal name */
406660484Sobrien  recurse = (char *) xmalloc (literal_len + 1);
406760484Sobrien  memcpy (recurse, *mangled, literal_len);
406860484Sobrien  recurse[literal_len] = '\000';
406960484Sobrien
407060484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
407160484Sobrien
407260484Sobrien  if (recurse_dem)
407360484Sobrien    {
407460484Sobrien      string_append (result, recurse_dem);
407560484Sobrien      free (recurse_dem);
407660484Sobrien    }
407760484Sobrien  else
407860484Sobrien    {
407960484Sobrien      string_appendn (result, *mangled, literal_len);
408060484Sobrien    }
408160484Sobrien  (*mangled) += literal_len;
408260484Sobrien  free (recurse);
408360484Sobrien
408460484Sobrien  return 1;
408560484Sobrien}
408660484Sobrien
408760484Sobrienstatic int
408860484Sobriensnarf_numeric_literal (args, arg)
408960484Sobrien     const char ** args;
409060484Sobrien     string * arg;
409160484Sobrien{
409260484Sobrien  if (**args == '-')
409360484Sobrien    {
409460484Sobrien      char_str[0] = '-';
409560484Sobrien      string_append (arg, char_str);
409660484Sobrien      (*args)++;
409760484Sobrien    }
409860484Sobrien  else if (**args == '+')
409960484Sobrien    (*args)++;
410060484Sobrien
410177298Sobrien  if (!ISDIGIT ((unsigned char)**args))
410260484Sobrien    return 0;
410360484Sobrien
410477298Sobrien  while (ISDIGIT ((unsigned char)**args))
410560484Sobrien    {
410660484Sobrien      char_str[0] = **args;
410760484Sobrien      string_append (arg, char_str);
410860484Sobrien      (*args)++;
410960484Sobrien    }
411060484Sobrien
411160484Sobrien  return 1;
411260484Sobrien}
411360484Sobrien
411460484Sobrien/* Demangle the next argument, given by MANGLED into RESULT, which
411560484Sobrien   *should be an uninitialized* string.  It will be initialized here,
411660484Sobrien   and free'd should anything go wrong.  */
411760484Sobrien
411860484Sobrienstatic int
411933965Sjdpdo_arg (work, mangled, result)
412033965Sjdp     struct work_stuff *work;
412133965Sjdp     const char **mangled;
412233965Sjdp     string *result;
412333965Sjdp{
412460484Sobrien  /* Remember where we started so that we can record the type, for
412560484Sobrien     non-squangling type remembering.  */
412633965Sjdp  const char *start = *mangled;
412733965Sjdp
412860484Sobrien  string_init (result);
412960484Sobrien
413060484Sobrien  if (work->nrepeats > 0)
413133965Sjdp    {
413260484Sobrien      --work->nrepeats;
413360484Sobrien
413460484Sobrien      if (work->previous_argument == 0)
413560484Sobrien	return 0;
413660484Sobrien
413760484Sobrien      /* We want to reissue the previous type in this argument list.  */
413860484Sobrien      string_appends (result, work->previous_argument);
413960484Sobrien      return 1;
414033965Sjdp    }
414160484Sobrien
414260484Sobrien  if (**mangled == 'n')
414360484Sobrien    {
414460484Sobrien      /* A squangling-style repeat.  */
414560484Sobrien      (*mangled)++;
414660484Sobrien      work->nrepeats = consume_count(mangled);
414760484Sobrien
414860484Sobrien      if (work->nrepeats <= 0)
414960484Sobrien	/* This was not a repeat count after all.  */
415060484Sobrien	return 0;
415160484Sobrien
415260484Sobrien      if (work->nrepeats > 9)
415360484Sobrien	{
415460484Sobrien	  if (**mangled != '_')
415560484Sobrien	    /* The repeat count should be followed by an '_' in this
415660484Sobrien	       case.  */
415760484Sobrien	    return 0;
415860484Sobrien	  else
415960484Sobrien	    (*mangled)++;
416060484Sobrien	}
416160484Sobrien
416260484Sobrien      /* Now, the repeat is all set up.  */
416360484Sobrien      return do_arg (work, mangled, result);
416460484Sobrien    }
416560484Sobrien
416660484Sobrien  /* Save the result in WORK->previous_argument so that we can find it
416760484Sobrien     if it's repeated.  Note that saving START is not good enough: we
416860484Sobrien     do not want to add additional types to the back-referenceable
416960484Sobrien     type vector when processing a repeated type.  */
417060484Sobrien  if (work->previous_argument)
417160484Sobrien    string_clear (work->previous_argument);
417233965Sjdp  else
417333965Sjdp    {
417460484Sobrien      work->previous_argument = (string*) xmalloc (sizeof (string));
417560484Sobrien      string_init (work->previous_argument);
417633965Sjdp    }
417760484Sobrien
417860484Sobrien  if (!do_type (work, mangled, work->previous_argument))
417960484Sobrien    return 0;
418060484Sobrien
418160484Sobrien  string_appends (result, work->previous_argument);
418260484Sobrien
418360484Sobrien  remember_type (work, start, *mangled - start);
418460484Sobrien  return 1;
418533965Sjdp}
418633965Sjdp
418733965Sjdpstatic void
418833965Sjdpremember_type (work, start, len)
418933965Sjdp     struct work_stuff *work;
419033965Sjdp     const char *start;
419133965Sjdp     int len;
419233965Sjdp{
419333965Sjdp  char *tem;
419433965Sjdp
419560484Sobrien  if (work->forgetting_types)
419660484Sobrien    return;
419760484Sobrien
419833965Sjdp  if (work -> ntypes >= work -> typevec_size)
419933965Sjdp    {
420033965Sjdp      if (work -> typevec_size == 0)
420133965Sjdp	{
420233965Sjdp	  work -> typevec_size = 3;
420338889Sjdp	  work -> typevec
420438889Sjdp	    = (char **) xmalloc (sizeof (char *) * work -> typevec_size);
420533965Sjdp	}
420633965Sjdp      else
420733965Sjdp	{
420833965Sjdp	  work -> typevec_size *= 2;
420938889Sjdp	  work -> typevec
421038889Sjdp	    = (char **) xrealloc ((char *)work -> typevec,
421138889Sjdp				  sizeof (char *) * work -> typevec_size);
421233965Sjdp	}
421333965Sjdp    }
421433965Sjdp  tem = xmalloc (len + 1);
421533965Sjdp  memcpy (tem, start, len);
421633965Sjdp  tem[len] = '\0';
421733965Sjdp  work -> typevec[work -> ntypes++] = tem;
421833965Sjdp}
421933965Sjdp
422060484Sobrien
422160484Sobrien/* Remember a K type class qualifier. */
422260484Sobrienstatic void
422360484Sobrienremember_Ktype (work, start, len)
422460484Sobrien     struct work_stuff *work;
422560484Sobrien     const char *start;
422660484Sobrien     int len;
422760484Sobrien{
422860484Sobrien  char *tem;
422960484Sobrien
423060484Sobrien  if (work -> numk >= work -> ksize)
423160484Sobrien    {
423260484Sobrien      if (work -> ksize == 0)
423360484Sobrien	{
423460484Sobrien	  work -> ksize = 5;
423560484Sobrien	  work -> ktypevec
423660484Sobrien	    = (char **) xmalloc (sizeof (char *) * work -> ksize);
423760484Sobrien	}
423860484Sobrien      else
423960484Sobrien	{
424060484Sobrien	  work -> ksize *= 2;
424160484Sobrien	  work -> ktypevec
424260484Sobrien	    = (char **) xrealloc ((char *)work -> ktypevec,
424360484Sobrien				  sizeof (char *) * work -> ksize);
424460484Sobrien	}
424560484Sobrien    }
424660484Sobrien  tem = xmalloc (len + 1);
424760484Sobrien  memcpy (tem, start, len);
424860484Sobrien  tem[len] = '\0';
424960484Sobrien  work -> ktypevec[work -> numk++] = tem;
425060484Sobrien}
425160484Sobrien
425260484Sobrien/* Register a B code, and get an index for it. B codes are registered
425360484Sobrien   as they are seen, rather than as they are completed, so map<temp<char> >
425460484Sobrien   registers map<temp<char> > as B0, and temp<char> as B1 */
425560484Sobrien
425660484Sobrienstatic int
425760484Sobrienregister_Btype (work)
425860484Sobrien     struct work_stuff *work;
425960484Sobrien{
426060484Sobrien  int ret;
426160484Sobrien
426260484Sobrien  if (work -> numb >= work -> bsize)
426360484Sobrien    {
426460484Sobrien      if (work -> bsize == 0)
426560484Sobrien	{
426660484Sobrien	  work -> bsize = 5;
426760484Sobrien	  work -> btypevec
426860484Sobrien	    = (char **) xmalloc (sizeof (char *) * work -> bsize);
426960484Sobrien	}
427060484Sobrien      else
427160484Sobrien	{
427260484Sobrien	  work -> bsize *= 2;
427360484Sobrien	  work -> btypevec
427460484Sobrien	    = (char **) xrealloc ((char *)work -> btypevec,
427560484Sobrien				  sizeof (char *) * work -> bsize);
427660484Sobrien	}
427760484Sobrien    }
427860484Sobrien  ret = work -> numb++;
427960484Sobrien  work -> btypevec[ret] = NULL;
428060484Sobrien  return(ret);
428160484Sobrien}
428260484Sobrien
428360484Sobrien/* Store a value into a previously registered B code type. */
428460484Sobrien
428560484Sobrienstatic void
428660484Sobrienremember_Btype (work, start, len, index)
428760484Sobrien     struct work_stuff *work;
428860484Sobrien     const char *start;
428960484Sobrien     int len, index;
429060484Sobrien{
429160484Sobrien  char *tem;
429260484Sobrien
429360484Sobrien  tem = xmalloc (len + 1);
429460484Sobrien  memcpy (tem, start, len);
429560484Sobrien  tem[len] = '\0';
429660484Sobrien  work -> btypevec[index] = tem;
429760484Sobrien}
429860484Sobrien
429960484Sobrien/* Lose all the info related to B and K type codes. */
430060484Sobrienstatic void
430160484Sobrienforget_B_and_K_types (work)
430260484Sobrien     struct work_stuff *work;
430360484Sobrien{
430460484Sobrien  int i;
430560484Sobrien
430660484Sobrien  while (work -> numk > 0)
430760484Sobrien    {
430860484Sobrien      i = --(work -> numk);
430960484Sobrien      if (work -> ktypevec[i] != NULL)
431060484Sobrien	{
431160484Sobrien	  free (work -> ktypevec[i]);
431260484Sobrien	  work -> ktypevec[i] = NULL;
431360484Sobrien	}
431460484Sobrien    }
431560484Sobrien
431660484Sobrien  while (work -> numb > 0)
431760484Sobrien    {
431860484Sobrien      i = --(work -> numb);
431960484Sobrien      if (work -> btypevec[i] != NULL)
432060484Sobrien	{
432160484Sobrien	  free (work -> btypevec[i]);
432260484Sobrien	  work -> btypevec[i] = NULL;
432360484Sobrien	}
432460484Sobrien    }
432560484Sobrien}
432633965Sjdp/* Forget the remembered types, but not the type vector itself.  */
432733965Sjdp
432833965Sjdpstatic void
432933965Sjdpforget_types (work)
433033965Sjdp     struct work_stuff *work;
433133965Sjdp{
433233965Sjdp  int i;
433333965Sjdp
433433965Sjdp  while (work -> ntypes > 0)
433533965Sjdp    {
433633965Sjdp      i = --(work -> ntypes);
433733965Sjdp      if (work -> typevec[i] != NULL)
433833965Sjdp	{
433933965Sjdp	  free (work -> typevec[i]);
434033965Sjdp	  work -> typevec[i] = NULL;
434133965Sjdp	}
434233965Sjdp    }
434333965Sjdp}
434433965Sjdp
434533965Sjdp/* Process the argument list part of the signature, after any class spec
434633965Sjdp   has been consumed, as well as the first 'F' character (if any).  For
434733965Sjdp   example:
434833965Sjdp
434933965Sjdp   "__als__3fooRT0"		=>	process "RT0"
435033965Sjdp   "complexfunc5__FPFPc_PFl_i"	=>	process "PFPc_PFl_i"
435133965Sjdp
435233965Sjdp   DECLP must be already initialised, usually non-empty.  It won't be freed
435333965Sjdp   on failure.
435433965Sjdp
435533965Sjdp   Note that g++ differs significantly from ARM and lucid style mangling
435633965Sjdp   with regards to references to previously seen types.  For example, given
435733965Sjdp   the source fragment:
435833965Sjdp
435933965Sjdp     class foo {
436033965Sjdp       public:
436133965Sjdp       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
436233965Sjdp     };
436333965Sjdp
436433965Sjdp     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
436533965Sjdp     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
436633965Sjdp
436733965Sjdp   g++ produces the names:
436833965Sjdp
436933965Sjdp     __3fooiRT0iT2iT2
437033965Sjdp     foo__FiR3fooiT1iT1
437133965Sjdp
437233965Sjdp   while lcc (and presumably other ARM style compilers as well) produces:
437333965Sjdp
437433965Sjdp     foo__FiR3fooT1T2T1T2
437533965Sjdp     __ct__3fooFiR3fooT1T2T1T2
437633965Sjdp
437760484Sobrien   Note that g++ bases its type numbers starting at zero and counts all
437860484Sobrien   previously seen types, while lucid/ARM bases its type numbers starting
437933965Sjdp   at one and only considers types after it has seen the 'F' character
438033965Sjdp   indicating the start of the function args.  For lucid/ARM style, we
438133965Sjdp   account for this difference by discarding any previously seen types when
438233965Sjdp   we see the 'F' character, and subtracting one from the type number
438333965Sjdp   reference.
438433965Sjdp
438533965Sjdp */
438633965Sjdp
438733965Sjdpstatic int
438833965Sjdpdemangle_args (work, mangled, declp)
438933965Sjdp     struct work_stuff *work;
439033965Sjdp     const char **mangled;
439133965Sjdp     string *declp;
439233965Sjdp{
439333965Sjdp  string arg;
439433965Sjdp  int need_comma = 0;
439533965Sjdp  int r;
439633965Sjdp  int t;
439733965Sjdp  const char *tem;
439833965Sjdp  char temptype;
439933965Sjdp
440033965Sjdp  if (PRINT_ARG_TYPES)
440133965Sjdp    {
440233965Sjdp      string_append (declp, "(");
440333965Sjdp      if (**mangled == '\0')
440433965Sjdp	{
440533965Sjdp	  string_append (declp, "void");
440633965Sjdp	}
440733965Sjdp    }
440833965Sjdp
440960484Sobrien  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
441060484Sobrien	 || work->nrepeats > 0)
441133965Sjdp    {
441233965Sjdp      if ((**mangled == 'N') || (**mangled == 'T'))
441333965Sjdp	{
441433965Sjdp	  temptype = *(*mangled)++;
441560484Sobrien
441633965Sjdp	  if (temptype == 'N')
441733965Sjdp	    {
441833965Sjdp	      if (!get_count (mangled, &r))
441933965Sjdp		{
442033965Sjdp		  return (0);
442133965Sjdp		}
442233965Sjdp	    }
442333965Sjdp	  else
442433965Sjdp	    {
442533965Sjdp	      r = 1;
442633965Sjdp	    }
442760484Sobrien          if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
442833965Sjdp            {
442933965Sjdp              /* If we have 10 or more types we might have more than a 1 digit
443033965Sjdp                 index so we'll have to consume the whole count here. This
443133965Sjdp                 will lose if the next thing is a type name preceded by a
443233965Sjdp                 count but it's impossible to demangle that case properly
443333965Sjdp                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
443433965Sjdp                 Pc, ...)"  or "(..., type12, char *, ...)" */
443560484Sobrien              if ((t = consume_count(mangled)) <= 0)
443633965Sjdp                {
443733965Sjdp                  return (0);
443833965Sjdp                }
443933965Sjdp            }
444033965Sjdp          else
444133965Sjdp	    {
444233965Sjdp	      if (!get_count (mangled, &t))
444333965Sjdp	    	{
444433965Sjdp	          return (0);
444533965Sjdp	    	}
444633965Sjdp	    }
444760484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
444833965Sjdp	    {
444933965Sjdp	      t--;
445033965Sjdp	    }
445133965Sjdp	  /* Validate the type index.  Protect against illegal indices from
445233965Sjdp	     malformed type strings.  */
445333965Sjdp	  if ((t < 0) || (t >= work -> ntypes))
445433965Sjdp	    {
445533965Sjdp	      return (0);
445633965Sjdp	    }
445760484Sobrien	  while (work->nrepeats > 0 || --r >= 0)
445833965Sjdp	    {
445933965Sjdp	      tem = work -> typevec[t];
446033965Sjdp	      if (need_comma && PRINT_ARG_TYPES)
446133965Sjdp		{
446233965Sjdp		  string_append (declp, ", ");
446333965Sjdp		}
446433965Sjdp	      if (!do_arg (work, &tem, &arg))
446533965Sjdp		{
446633965Sjdp		  return (0);
446733965Sjdp		}
446833965Sjdp	      if (PRINT_ARG_TYPES)
446933965Sjdp		{
447033965Sjdp		  string_appends (declp, &arg);
447133965Sjdp		}
447233965Sjdp	      string_delete (&arg);
447333965Sjdp	      need_comma = 1;
447433965Sjdp	    }
447533965Sjdp	}
447633965Sjdp      else
447733965Sjdp	{
447860484Sobrien	  if (need_comma && PRINT_ARG_TYPES)
447960484Sobrien	    string_append (declp, ", ");
448033965Sjdp	  if (!do_arg (work, mangled, &arg))
448160484Sobrien	    return (0);
448233965Sjdp	  if (PRINT_ARG_TYPES)
448360484Sobrien	    string_appends (declp, &arg);
448433965Sjdp	  string_delete (&arg);
448533965Sjdp	  need_comma = 1;
448633965Sjdp	}
448733965Sjdp    }
448833965Sjdp
448933965Sjdp  if (**mangled == 'e')
449033965Sjdp    {
449133965Sjdp      (*mangled)++;
449233965Sjdp      if (PRINT_ARG_TYPES)
449333965Sjdp	{
449433965Sjdp	  if (need_comma)
449533965Sjdp	    {
449633965Sjdp	      string_append (declp, ",");
449733965Sjdp	    }
449833965Sjdp	  string_append (declp, "...");
449933965Sjdp	}
450033965Sjdp    }
450133965Sjdp
450233965Sjdp  if (PRINT_ARG_TYPES)
450333965Sjdp    {
450433965Sjdp      string_append (declp, ")");
450533965Sjdp    }
450633965Sjdp  return (1);
450733965Sjdp}
450833965Sjdp
450960484Sobrien/* Like demangle_args, but for demangling the argument lists of function
451060484Sobrien   and method pointers or references, not top-level declarations.  */
451160484Sobrien
451260484Sobrienstatic int
451360484Sobriendemangle_nested_args (work, mangled, declp)
451460484Sobrien     struct work_stuff *work;
451560484Sobrien     const char **mangled;
451660484Sobrien     string *declp;
451760484Sobrien{
451860484Sobrien  string* saved_previous_argument;
451960484Sobrien  int result;
452060484Sobrien  int saved_nrepeats;
452160484Sobrien
452260484Sobrien  /* The G++ name-mangling algorithm does not remember types on nested
452360484Sobrien     argument lists, unless -fsquangling is used, and in that case the
452460484Sobrien     type vector updated by remember_type is not used.  So, we turn
452560484Sobrien     off remembering of types here.  */
452660484Sobrien  ++work->forgetting_types;
452760484Sobrien
452860484Sobrien  /* For the repeat codes used with -fsquangling, we must keep track of
452960484Sobrien     the last argument.  */
453060484Sobrien  saved_previous_argument = work->previous_argument;
453160484Sobrien  saved_nrepeats = work->nrepeats;
453260484Sobrien  work->previous_argument = 0;
453360484Sobrien  work->nrepeats = 0;
453460484Sobrien
453560484Sobrien  /* Actually demangle the arguments.  */
453660484Sobrien  result = demangle_args (work, mangled, declp);
453760484Sobrien
453860484Sobrien  /* Restore the previous_argument field.  */
453960484Sobrien  if (work->previous_argument)
454060484Sobrien    string_delete (work->previous_argument);
454160484Sobrien  work->previous_argument = saved_previous_argument;
454260484Sobrien  --work->forgetting_types;
454360484Sobrien  work->nrepeats = saved_nrepeats;
454460484Sobrien
454560484Sobrien  return result;
454660484Sobrien}
454760484Sobrien
454833965Sjdpstatic void
454933965Sjdpdemangle_function_name (work, mangled, declp, scan)
455033965Sjdp     struct work_stuff *work;
455133965Sjdp     const char **mangled;
455233965Sjdp     string *declp;
455333965Sjdp     const char *scan;
455433965Sjdp{
455560484Sobrien  size_t i;
455633965Sjdp  string type;
455733965Sjdp  const char *tem;
455833965Sjdp
455933965Sjdp  string_appendn (declp, (*mangled), scan - (*mangled));
456033965Sjdp  string_need (declp, 1);
456133965Sjdp  *(declp -> p) = '\0';
456233965Sjdp
456333965Sjdp  /* Consume the function name, including the "__" separating the name
456433965Sjdp     from the signature.  We are guaranteed that SCAN points to the
456533965Sjdp     separator.  */
456633965Sjdp
456733965Sjdp  (*mangled) = scan + 2;
456860484Sobrien  /* We may be looking at an instantiation of a template function:
456960484Sobrien     foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
457060484Sobrien     following _F marks the start of the function arguments.  Handle
457160484Sobrien     the template arguments first. */
457233965Sjdp
457360484Sobrien  if (HP_DEMANGLING && (**mangled == 'X'))
457433965Sjdp    {
457560484Sobrien      demangle_arm_hp_template (work, mangled, 0, declp);
457660484Sobrien      /* This leaves MANGLED pointing to the 'F' marking func args */
457760484Sobrien    }
457833965Sjdp
457960484Sobrien  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
458060484Sobrien    {
458160484Sobrien
458233965Sjdp      /* See if we have an ARM style constructor or destructor operator.
458333965Sjdp	 If so, then just record it, clear the decl, and return.
458433965Sjdp	 We can't build the actual constructor/destructor decl until later,
458533965Sjdp	 when we recover the class name from the signature.  */
458633965Sjdp
458733965Sjdp      if (strcmp (declp -> b, "__ct") == 0)
458833965Sjdp	{
458933965Sjdp	  work -> constructor += 1;
459033965Sjdp	  string_clear (declp);
459133965Sjdp	  return;
459233965Sjdp	}
459333965Sjdp      else if (strcmp (declp -> b, "__dt") == 0)
459433965Sjdp	{
459533965Sjdp	  work -> destructor += 1;
459633965Sjdp	  string_clear (declp);
459733965Sjdp	  return;
459833965Sjdp	}
459933965Sjdp    }
460033965Sjdp
460160484Sobrien  if (declp->p - declp->b >= 3
460233965Sjdp      && declp->b[0] == 'o'
460333965Sjdp      && declp->b[1] == 'p'
460433965Sjdp      && strchr (cplus_markers, declp->b[2]) != NULL)
460533965Sjdp    {
460633965Sjdp      /* see if it's an assignment expression */
460733965Sjdp      if (declp->p - declp->b >= 10 /* op$assign_ */
460833965Sjdp	  && memcmp (declp->b + 3, "assign_", 7) == 0)
460933965Sjdp	{
461077298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
461133965Sjdp	    {
461260484Sobrien	      int len = declp->p - declp->b - 10;
461360484Sobrien	      if ((int) strlen (optable[i].in) == len
461433965Sjdp		  && memcmp (optable[i].in, declp->b + 10, len) == 0)
461533965Sjdp		{
461633965Sjdp		  string_clear (declp);
461733965Sjdp		  string_append (declp, "operator");
461833965Sjdp		  string_append (declp, optable[i].out);
461933965Sjdp		  string_append (declp, "=");
462033965Sjdp		  break;
462133965Sjdp		}
462233965Sjdp	    }
462333965Sjdp	}
462433965Sjdp      else
462533965Sjdp	{
462677298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
462733965Sjdp	    {
462833965Sjdp	      int len = declp->p - declp->b - 3;
462960484Sobrien	      if ((int) strlen (optable[i].in) == len
463033965Sjdp		  && memcmp (optable[i].in, declp->b + 3, len) == 0)
463133965Sjdp		{
463233965Sjdp		  string_clear (declp);
463333965Sjdp		  string_append (declp, "operator");
463433965Sjdp		  string_append (declp, optable[i].out);
463533965Sjdp		  break;
463633965Sjdp		}
463733965Sjdp	    }
463833965Sjdp	}
463933965Sjdp    }
464033965Sjdp  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
464133965Sjdp	   && strchr (cplus_markers, declp->b[4]) != NULL)
464233965Sjdp    {
464333965Sjdp      /* type conversion operator */
464433965Sjdp      tem = declp->b + 5;
464533965Sjdp      if (do_type (work, &tem, &type))
464633965Sjdp	{
464733965Sjdp	  string_clear (declp);
464833965Sjdp	  string_append (declp, "operator ");
464933965Sjdp	  string_appends (declp, &type);
465033965Sjdp	  string_delete (&type);
465133965Sjdp	}
465233965Sjdp    }
465333965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
465433965Sjdp	   && declp->b[2] == 'o' && declp->b[3] == 'p')
465533965Sjdp    {
465633965Sjdp      /* ANSI.  */
465733965Sjdp      /* type conversion operator.  */
465833965Sjdp      tem = declp->b + 4;
465933965Sjdp      if (do_type (work, &tem, &type))
466033965Sjdp	{
466133965Sjdp	  string_clear (declp);
466233965Sjdp	  string_append (declp, "operator ");
466333965Sjdp	  string_appends (declp, &type);
466433965Sjdp	  string_delete (&type);
466533965Sjdp	}
466633965Sjdp    }
466733965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
466877298Sobrien	   && ISLOWER((unsigned char)declp->b[2])
466977298Sobrien	   && ISLOWER((unsigned char)declp->b[3]))
467033965Sjdp    {
467133965Sjdp      if (declp->b[4] == '\0')
467233965Sjdp	{
467333965Sjdp	  /* Operator.  */
467477298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
467533965Sjdp	    {
467633965Sjdp	      if (strlen (optable[i].in) == 2
467733965Sjdp		  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
467833965Sjdp		{
467933965Sjdp		  string_clear (declp);
468033965Sjdp		  string_append (declp, "operator");
468133965Sjdp		  string_append (declp, optable[i].out);
468233965Sjdp		  break;
468333965Sjdp		}
468433965Sjdp	    }
468533965Sjdp	}
468633965Sjdp      else
468733965Sjdp	{
468833965Sjdp	  if (declp->b[2] == 'a' && declp->b[5] == '\0')
468933965Sjdp	    {
469033965Sjdp	      /* Assignment.  */
469177298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
469233965Sjdp		{
469333965Sjdp		  if (strlen (optable[i].in) == 3
469433965Sjdp		      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
469533965Sjdp		    {
469633965Sjdp		      string_clear (declp);
469733965Sjdp		      string_append (declp, "operator");
469833965Sjdp		      string_append (declp, optable[i].out);
469933965Sjdp		      break;
470060484Sobrien		    }
470133965Sjdp		}
470233965Sjdp	    }
470333965Sjdp	}
470433965Sjdp    }
470533965Sjdp}
470633965Sjdp
470733965Sjdp/* a mini string-handling package */
470833965Sjdp
470933965Sjdpstatic void
471033965Sjdpstring_need (s, n)
471133965Sjdp     string *s;
471233965Sjdp     int n;
471333965Sjdp{
471433965Sjdp  int tem;
471533965Sjdp
471633965Sjdp  if (s->b == NULL)
471733965Sjdp    {
471833965Sjdp      if (n < 32)
471933965Sjdp	{
472033965Sjdp	  n = 32;
472133965Sjdp	}
472233965Sjdp      s->p = s->b = xmalloc (n);
472333965Sjdp      s->e = s->b + n;
472433965Sjdp    }
472533965Sjdp  else if (s->e - s->p < n)
472633965Sjdp    {
472733965Sjdp      tem = s->p - s->b;
472833965Sjdp      n += tem;
472933965Sjdp      n *= 2;
473033965Sjdp      s->b = xrealloc (s->b, n);
473133965Sjdp      s->p = s->b + tem;
473233965Sjdp      s->e = s->b + n;
473333965Sjdp    }
473433965Sjdp}
473533965Sjdp
473633965Sjdpstatic void
473733965Sjdpstring_delete (s)
473833965Sjdp     string *s;
473933965Sjdp{
474033965Sjdp  if (s->b != NULL)
474133965Sjdp    {
474233965Sjdp      free (s->b);
474333965Sjdp      s->b = s->e = s->p = NULL;
474433965Sjdp    }
474533965Sjdp}
474633965Sjdp
474733965Sjdpstatic void
474833965Sjdpstring_init (s)
474933965Sjdp     string *s;
475033965Sjdp{
475133965Sjdp  s->b = s->p = s->e = NULL;
475233965Sjdp}
475333965Sjdp
475460484Sobrienstatic void
475533965Sjdpstring_clear (s)
475633965Sjdp     string *s;
475733965Sjdp{
475833965Sjdp  s->p = s->b;
475933965Sjdp}
476033965Sjdp
476133965Sjdp#if 0
476233965Sjdp
476333965Sjdpstatic int
476433965Sjdpstring_empty (s)
476533965Sjdp     string *s;
476633965Sjdp{
476733965Sjdp  return (s->b == s->p);
476833965Sjdp}
476933965Sjdp
477033965Sjdp#endif
477133965Sjdp
477233965Sjdpstatic void
477333965Sjdpstring_append (p, s)
477433965Sjdp     string *p;
477533965Sjdp     const char *s;
477633965Sjdp{
477733965Sjdp  int n;
477833965Sjdp  if (s == NULL || *s == '\0')
477933965Sjdp    return;
478033965Sjdp  n = strlen (s);
478133965Sjdp  string_need (p, n);
478233965Sjdp  memcpy (p->p, s, n);
478333965Sjdp  p->p += n;
478433965Sjdp}
478533965Sjdp
478633965Sjdpstatic void
478733965Sjdpstring_appends (p, s)
478833965Sjdp     string *p, *s;
478933965Sjdp{
479033965Sjdp  int n;
479133965Sjdp
479233965Sjdp  if (s->b != s->p)
479333965Sjdp    {
479433965Sjdp      n = s->p - s->b;
479533965Sjdp      string_need (p, n);
479633965Sjdp      memcpy (p->p, s->b, n);
479733965Sjdp      p->p += n;
479833965Sjdp    }
479933965Sjdp}
480033965Sjdp
480133965Sjdpstatic void
480233965Sjdpstring_appendn (p, s, n)
480333965Sjdp     string *p;
480433965Sjdp     const char *s;
480533965Sjdp     int n;
480633965Sjdp{
480733965Sjdp  if (n != 0)
480833965Sjdp    {
480933965Sjdp      string_need (p, n);
481033965Sjdp      memcpy (p->p, s, n);
481133965Sjdp      p->p += n;
481233965Sjdp    }
481333965Sjdp}
481433965Sjdp
481533965Sjdpstatic void
481633965Sjdpstring_prepend (p, s)
481733965Sjdp     string *p;
481833965Sjdp     const char *s;
481933965Sjdp{
482033965Sjdp  if (s != NULL && *s != '\0')
482133965Sjdp    {
482233965Sjdp      string_prependn (p, s, strlen (s));
482333965Sjdp    }
482433965Sjdp}
482533965Sjdp
482633965Sjdpstatic void
482733965Sjdpstring_prepends (p, s)
482833965Sjdp     string *p, *s;
482933965Sjdp{
483033965Sjdp  if (s->b != s->p)
483133965Sjdp    {
483233965Sjdp      string_prependn (p, s->b, s->p - s->b);
483333965Sjdp    }
483433965Sjdp}
483533965Sjdp
483633965Sjdpstatic void
483733965Sjdpstring_prependn (p, s, n)
483833965Sjdp     string *p;
483933965Sjdp     const char *s;
484033965Sjdp     int n;
484133965Sjdp{
484233965Sjdp  char *q;
484333965Sjdp
484433965Sjdp  if (n != 0)
484533965Sjdp    {
484633965Sjdp      string_need (p, n);
484733965Sjdp      for (q = p->p - 1; q >= p->b; q--)
484833965Sjdp	{
484933965Sjdp	  q[n] = q[0];
485033965Sjdp	}
485133965Sjdp      memcpy (p->b, s, n);
485233965Sjdp      p->p += n;
485333965Sjdp    }
485433965Sjdp}
485533965Sjdp
485660484Sobrienstatic void
485760484Sobrienstring_append_template_idx (s, idx)
485860484Sobrien     string *s;
485960484Sobrien     int idx;
486060484Sobrien{
486160484Sobrien  char buf[INTBUF_SIZE + 1 /* 'T' */];
486260484Sobrien  sprintf(buf, "T%d", idx);
486360484Sobrien  string_append (s, buf);
486460484Sobrien}
486560484Sobrien
486633965Sjdp/* To generate a standalone demangler program for testing purposes,
486733965Sjdp   just compile and link this file with -DMAIN and libiberty.a.  When
486833965Sjdp   run, it demangles each command line arg, or each stdin string, and
486933965Sjdp   prints the result on stdout.  */
487033965Sjdp
487133965Sjdp#ifdef MAIN
487233965Sjdp
487338889Sjdp#include "getopt.h"
487438889Sjdp
487560484Sobrienstatic const char *program_name;
487660484Sobrienstatic const char *program_version = VERSION;
487791041Sobrienstatic int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
487838889Sjdp
487933965Sjdpstatic void demangle_it PARAMS ((char *));
488060484Sobrienstatic void usage PARAMS ((FILE *, int)) ATTRIBUTE_NORETURN;
488160484Sobrienstatic void fatal PARAMS ((const char *)) ATTRIBUTE_NORETURN;
488268765Sobrienstatic void print_demangler_list PARAMS ((FILE *));
488333965Sjdp
488433965Sjdpstatic void
488533965Sjdpdemangle_it (mangled_name)
488633965Sjdp     char *mangled_name;
488733965Sjdp{
488833965Sjdp  char *result;
488933965Sjdp
489091041Sobrien  /* For command line args, also try to demangle type encodings.  */
489191041Sobrien  result = cplus_demangle (mangled_name, flags | DMGL_TYPES);
489233965Sjdp  if (result == NULL)
489333965Sjdp    {
489433965Sjdp      printf ("%s\n", mangled_name);
489533965Sjdp    }
489633965Sjdp  else
489733965Sjdp    {
489833965Sjdp      printf ("%s\n", result);
489933965Sjdp      free (result);
490033965Sjdp    }
490133965Sjdp}
490233965Sjdp
490368765Sobrienstatic void
490468765Sobrienprint_demangler_list (stream)
490568765Sobrien     FILE *stream;
490668765Sobrien{
490789857Sobrien  const struct demangler_engine *demangler;
490868765Sobrien
490968765Sobrien  fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
491068765Sobrien
491168765Sobrien  for (demangler = libiberty_demanglers + 1;
491268765Sobrien       demangler->demangling_style != unknown_demangling;
491368765Sobrien       ++demangler)
491468765Sobrien    fprintf (stream, ",%s", demangler->demangling_style_name);
491568765Sobrien
491668765Sobrien  fprintf (stream, "}");
491768765Sobrien}
491868765Sobrien
491933965Sjdpstatic void
492033965Sjdpusage (stream, status)
492133965Sjdp     FILE *stream;
492233965Sjdp     int status;
492360484Sobrien{
492433965Sjdp  fprintf (stream, "\
492568765SobrienUsage: %s [-_] [-n] [--strip-underscores] [--no-strip-underscores] \n",
492633965Sjdp	   program_name);
492768765Sobrien
492868765Sobrien  fprintf (stream, "\
492968765Sobrien       [-s ");
493068765Sobrien  print_demangler_list (stream);
493168765Sobrien  fprintf (stream, "]\n");
493268765Sobrien
493368765Sobrien  fprintf (stream, "\
493468765Sobrien       [--format ");
493568765Sobrien  print_demangler_list (stream);
493668765Sobrien  fprintf (stream, "]\n");
493768765Sobrien
493868765Sobrien  fprintf (stream, "\
493968765Sobrien       [--help] [--version] [arg...]\n");
494033965Sjdp  exit (status);
494133965Sjdp}
494233965Sjdp
494360484Sobrien#define MBUF_SIZE 32767
494433965Sjdpchar mbuffer[MBUF_SIZE];
494533965Sjdp
494633965Sjdp/* Defined in the automatically-generated underscore.c.  */
494733965Sjdpextern int prepends_underscore;
494833965Sjdp
494933965Sjdpint strip_underscore = 0;
495033965Sjdp
495189857Sobrienstatic const struct option long_options[] = {
495233965Sjdp  {"strip-underscores", no_argument, 0, '_'},
495333965Sjdp  {"format", required_argument, 0, 's'},
495433965Sjdp  {"help", no_argument, 0, 'h'},
495533965Sjdp  {"no-strip-underscores", no_argument, 0, 'n'},
495633965Sjdp  {"version", no_argument, 0, 'v'},
495733965Sjdp  {0, no_argument, 0, 0}
495833965Sjdp};
495933965Sjdp
496060484Sobrien/* More 'friendly' abort that prints the line and file.
496160484Sobrien   config.h can #define abort fancy_abort if you like that sort of thing.  */
496260484Sobrien
496360484Sobrienvoid
496460484Sobrienfancy_abort ()
496560484Sobrien{
496660484Sobrien  fatal ("Internal gcc abort.");
496760484Sobrien}
496860484Sobrien
496960484Sobrien
497060484Sobrienstatic const char *
497160484Sobrienstandard_symbol_characters PARAMS ((void));
497260484Sobrien
497360484Sobrienstatic const char *
497460484Sobrienhp_symbol_characters PARAMS ((void));
497560484Sobrien
497668765Sobrienstatic const char *
497777298Sobriengnu_v3_symbol_characters PARAMS ((void));
497868765Sobrien
497960484Sobrien/* Return the string of non-alnum characters that may occur
498060484Sobrien   as a valid symbol component, in the standard assembler symbol
498160484Sobrien   syntax.  */
498260484Sobrien
498360484Sobrienstatic const char *
498460484Sobrienstandard_symbol_characters ()
498560484Sobrien{
498660484Sobrien  return "_$.";
498760484Sobrien}
498860484Sobrien
498960484Sobrien
499060484Sobrien/* Return the string of non-alnum characters that may occur
499160484Sobrien   as a valid symbol name component in an HP object file.
499260484Sobrien
499360484Sobrien   Note that, since HP's compiler generates object code straight from
499460484Sobrien   C++ source, without going through an assembler, its mangled
499560484Sobrien   identifiers can use all sorts of characters that no assembler would
499660484Sobrien   tolerate, so the alphabet this function creates is a little odd.
499760484Sobrien   Here are some sample mangled identifiers offered by HP:
499860484Sobrien
499960484Sobrien	typeid*__XT24AddressIndExpClassMember_
500060484Sobrien	[Vftptr]key:__dt__32OrdinaryCompareIndExpClassMemberFv
500160484Sobrien	__ct__Q2_9Elf64_Dyn18{unnamed.union.#1}Fv
500260484Sobrien
500360484Sobrien   This still seems really weird to me, since nowhere else in this
500460484Sobrien   file is there anything to recognize curly brackets, parens, etc.
500560484Sobrien   I've talked with Srikanth <srikanth@cup.hp.com>, and he assures me
500660484Sobrien   this is right, but I still strongly suspect that there's a
500760484Sobrien   misunderstanding here.
500860484Sobrien
500960484Sobrien   If we decide it's better for c++filt to use HP's assembler syntax
501060484Sobrien   to scrape identifiers out of its input, here's the definition of
501160484Sobrien   the symbol name syntax from the HP assembler manual:
501260484Sobrien
501360484Sobrien       Symbols are composed of uppercase and lowercase letters, decimal
501460484Sobrien       digits, dollar symbol, period (.), ampersand (&), pound sign(#) and
501560484Sobrien       underscore (_). A symbol can begin with a letter, digit underscore or
501660484Sobrien       dollar sign. If a symbol begins with a digit, it must contain a
501760484Sobrien       non-digit character.
501860484Sobrien
501960484Sobrien   So have fun.  */
502060484Sobrienstatic const char *
502160484Sobrienhp_symbol_characters ()
502260484Sobrien{
502360484Sobrien  return "_$.<>#,*&[]:(){}";
502460484Sobrien}
502560484Sobrien
502660484Sobrien
502768765Sobrien/* Return the string of non-alnum characters that may occur
502877298Sobrien   as a valid symbol component in the GNU C++ V3 ABI mangling
502968765Sobrien   scheme.  */
503068765Sobrien
503168765Sobrienstatic const char *
503277298Sobriengnu_v3_symbol_characters ()
503368765Sobrien{
503477298Sobrien  return "_$.";
503568765Sobrien}
503668765Sobrien
503768765Sobrien
503860484Sobrienextern int main PARAMS ((int, char **));
503960484Sobrien
504033965Sjdpint
504133965Sjdpmain (argc, argv)
504233965Sjdp     int argc;
504333965Sjdp     char **argv;
504433965Sjdp{
504533965Sjdp  char *result;
504633965Sjdp  int c;
504760484Sobrien  const char *valid_symbols;
504889857Sobrien  enum demangling_styles style = auto_demangling;
504933965Sjdp
505033965Sjdp  program_name = argv[0];
505133965Sjdp
505233965Sjdp  strip_underscore = prepends_underscore;
505333965Sjdp
505489857Sobrien  while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
505533965Sjdp    {
505633965Sjdp      switch (c)
505733965Sjdp	{
505833965Sjdp	case '?':
505933965Sjdp	  usage (stderr, 1);
506033965Sjdp	  break;
506133965Sjdp	case 'h':
506233965Sjdp	  usage (stdout, 0);
506333965Sjdp	case 'n':
506433965Sjdp	  strip_underscore = 0;
506533965Sjdp	  break;
506633965Sjdp	case 'v':
506760484Sobrien	  printf ("GNU %s (C++ demangler), version %s\n", program_name, program_version);
506860484Sobrien	  return (0);
506933965Sjdp	case '_':
507033965Sjdp	  strip_underscore = 1;
507133965Sjdp	  break;
507233965Sjdp	case 's':
507368765Sobrien	  {
507468765Sobrien	    style = cplus_demangle_name_to_style (optarg);
507568765Sobrien	    if (style == unknown_demangling)
507668765Sobrien	      {
507768765Sobrien		fprintf (stderr, "%s: unknown demangling style `%s'\n",
507868765Sobrien			 program_name, optarg);
507968765Sobrien		return (1);
508068765Sobrien	      }
508168765Sobrien	    else
508268765Sobrien	      cplus_demangle_set_style (style);
508368765Sobrien	  }
508433965Sjdp	  break;
508533965Sjdp	}
508633965Sjdp    }
508733965Sjdp
508833965Sjdp  if (optind < argc)
508933965Sjdp    {
509033965Sjdp      for ( ; optind < argc; optind++)
509133965Sjdp	{
509233965Sjdp	  demangle_it (argv[optind]);
509333965Sjdp	}
509433965Sjdp    }
509533965Sjdp  else
509633965Sjdp    {
509760484Sobrien      switch (current_demangling_style)
509860484Sobrien	{
509960484Sobrien	case gnu_demangling:
510060484Sobrien	case lucid_demangling:
510160484Sobrien	case arm_demangling:
510277298Sobrien	case java_demangling:
510360484Sobrien	case edg_demangling:
510477298Sobrien	case gnat_demangling:
510577298Sobrien	case auto_demangling:
510660484Sobrien	  valid_symbols = standard_symbol_characters ();
510760484Sobrien	  break;
510860484Sobrien	case hp_demangling:
510960484Sobrien	  valid_symbols = hp_symbol_characters ();
511060484Sobrien	  break;
511177298Sobrien	case gnu_v3_demangling:
511277298Sobrien	  valid_symbols = gnu_v3_symbol_characters ();
511368765Sobrien	  break;
511460484Sobrien	default:
511560484Sobrien	  /* Folks should explicitly indicate the appropriate alphabet for
511660484Sobrien	     each demangling.  Providing a default would allow the
511760484Sobrien	     question to go unconsidered.  */
511860484Sobrien	  abort ();
511960484Sobrien	}
512060484Sobrien
512133965Sjdp      for (;;)
512233965Sjdp	{
512333965Sjdp	  int i = 0;
512433965Sjdp	  c = getchar ();
512533965Sjdp	  /* Try to read a label.  */
512677298Sobrien	  while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
512733965Sjdp	    {
512833965Sjdp	      if (i >= MBUF_SIZE-1)
512933965Sjdp		break;
513033965Sjdp	      mbuffer[i++] = c;
513133965Sjdp	      c = getchar ();
513233965Sjdp	    }
513333965Sjdp	  if (i > 0)
513433965Sjdp	    {
513533965Sjdp	      int skip_first = 0;
513633965Sjdp
513789857Sobrien	      if (mbuffer[0] == '.' || mbuffer[0] == '$')
513833965Sjdp		++skip_first;
513933965Sjdp	      if (strip_underscore && mbuffer[skip_first] == '_')
514033965Sjdp		++skip_first;
514133965Sjdp
514233965Sjdp	      if (skip_first > i)
514333965Sjdp		skip_first = i;
514433965Sjdp
514533965Sjdp	      mbuffer[i] = 0;
514689857Sobrien	      flags |= (int) style;
514738889Sjdp	      result = cplus_demangle (mbuffer + skip_first, flags);
514833965Sjdp	      if (result)
514933965Sjdp		{
515033965Sjdp		  if (mbuffer[0] == '.')
515133965Sjdp		    putc ('.', stdout);
515233965Sjdp		  fputs (result, stdout);
515333965Sjdp		  free (result);
515433965Sjdp		}
515533965Sjdp	      else
515633965Sjdp		fputs (mbuffer, stdout);
515733965Sjdp
515833965Sjdp	      fflush (stdout);
515933965Sjdp	    }
516033965Sjdp	  if (c == EOF)
516133965Sjdp	    break;
516233965Sjdp	  putchar (c);
516368765Sobrien	  fflush (stdout);
516433965Sjdp	}
516533965Sjdp    }
516633965Sjdp
516760484Sobrien  return (0);
516833965Sjdp}
516933965Sjdp
517033965Sjdpstatic void
517133965Sjdpfatal (str)
517260484Sobrien     const char *str;
517333965Sjdp{
517433965Sjdp  fprintf (stderr, "%s: %s\n", program_name, str);
517533965Sjdp  exit (1);
517633965Sjdp}
517733965Sjdp
517860484SobrienPTR
517933965Sjdpxmalloc (size)
518060484Sobrien  size_t size;
518133965Sjdp{
518260484Sobrien  register PTR value = (PTR) malloc (size);
518333965Sjdp  if (value == 0)
518433965Sjdp    fatal ("virtual memory exhausted");
518533965Sjdp  return value;
518633965Sjdp}
518733965Sjdp
518860484SobrienPTR
518933965Sjdpxrealloc (ptr, size)
519060484Sobrien  PTR ptr;
519160484Sobrien  size_t size;
519233965Sjdp{
519360484Sobrien  register PTR value = (PTR) realloc (ptr, size);
519433965Sjdp  if (value == 0)
519533965Sjdp    fatal ("virtual memory exhausted");
519633965Sjdp  return value;
519733965Sjdp}
519833965Sjdp#endif	/* main */
5199