160484Sobrien/* Demangler for GNU C++
277298Sobrien   Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999,
3130561Sobrien   2000, 2001, 2002, 2003, 2004 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
14130561SobrienIn addition to the permissions in the GNU Library General Public
15130561SobrienLicense, the Free Software Foundation gives you unlimited permission
16130561Sobriento link the compiled version of this file into combinations with other
17130561Sobrienprograms, and to distribute those combinations without any restriction
18130561Sobriencoming from the use of this file.  (The Library Public License
19130561Sobrienrestrictions do apply in other respects; for example, they cover
20130561Sobrienmodification of the file, and distribution when not linked into a
21130561Sobriencombined executable.)
22130561Sobrien
2333965SjdpLibiberty is distributed in the hope that it will be useful,
2433965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
2533965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2633965SjdpLibrary General Public License for more details.
2733965Sjdp
2833965SjdpYou should have received a copy of the GNU Library General Public
2933965SjdpLicense along with libiberty; see the file COPYING.LIB.  If
30218822Sdimnot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
31218822SdimBoston, MA 02110-1301, USA.  */
3233965Sjdp
3333965Sjdp/* This file exports two functions; cplus_mangle_opname and cplus_demangle.
3433965Sjdp
3533965Sjdp   This file imports xmalloc and xrealloc, which are like malloc and
3633965Sjdp   realloc except that they generate a fatal error if there is no
3733965Sjdp   available memory.  */
3833965Sjdp
3933965Sjdp/* This file lives in both GCC and libiberty.  When making changes, please
4033965Sjdp   try not to break either.  */
4133965Sjdp
4260484Sobrien#ifdef HAVE_CONFIG_H
4360484Sobrien#include "config.h"
4460484Sobrien#endif
4560484Sobrien
4677298Sobrien#include "safe-ctype.h"
4777298Sobrien
4860484Sobrien#include <sys/types.h>
4933965Sjdp#include <string.h>
5033965Sjdp#include <stdio.h>
5133965Sjdp
5260484Sobrien#ifdef HAVE_STDLIB_H
5360484Sobrien#include <stdlib.h>
5460484Sobrien#else
5560484Sobrienchar * malloc ();
5660484Sobrienchar * realloc ();
5760484Sobrien#endif
5860484Sobrien
5933965Sjdp#include <demangle.h>
6033965Sjdp#undef CURRENT_DEMANGLING_STYLE
6133965Sjdp#define CURRENT_DEMANGLING_STYLE work->options
6233965Sjdp
6360484Sobrien#include "libiberty.h"
6433965Sjdp
65218822Sdimstatic char *ada_demangle (const char *, int);
6677298Sobrien
6760484Sobrien#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
6860484Sobrien
6960484Sobrien/* A value at least one greater than the maximum number of characters
7060484Sobrien   that will be output when using the `%d' format with `printf'.  */
7160484Sobrien#define INTBUF_SIZE 32
7260484Sobrien
73218822Sdimextern void fancy_abort (void) ATTRIBUTE_NORETURN;
7460484Sobrien
7533965Sjdp/* In order to allow a single demangler executable to demangle strings
7633965Sjdp   using various common values of CPLUS_MARKER, as well as any specific
7733965Sjdp   one set at compile time, we maintain a string containing all the
7833965Sjdp   commonly used ones, and check to see if the marker we are looking for
7933965Sjdp   is in that string.  CPLUS_MARKER is usually '$' on systems where the
8033965Sjdp   assembler can deal with that.  Where the assembler can't, it's usually
8133965Sjdp   '.' (but on many systems '.' is used for other things).  We put the
8233965Sjdp   current defined CPLUS_MARKER first (which defaults to '$'), followed
8333965Sjdp   by the next most common value, followed by an explicit '$' in case
8433965Sjdp   the value of CPLUS_MARKER is not '$'.
8533965Sjdp
8633965Sjdp   We could avoid this if we could just get g++ to tell us what the actual
8733965Sjdp   cplus marker character is as part of the debug information, perhaps by
8833965Sjdp   ensuring that it is the character that terminates the gcc<n>_compiled
8933965Sjdp   marker symbol (FIXME).  */
9033965Sjdp
9133965Sjdp#if !defined (CPLUS_MARKER)
9233965Sjdp#define CPLUS_MARKER '$'
9333965Sjdp#endif
9433965Sjdp
9577298Sobrienenum demangling_styles current_demangling_style = auto_demangling;
9633965Sjdp
9733965Sjdpstatic char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
9833965Sjdp
9960484Sobrienstatic char char_str[2] = { '\000', '\000' };
10060484Sobrien
10133965Sjdpvoid
102218822Sdimset_cplus_marker_for_demangling (int ch)
10333965Sjdp{
10433965Sjdp  cplus_markers[0] = ch;
10533965Sjdp}
10633965Sjdp
10760484Sobrientypedef struct string		/* Beware: these aren't required to be */
10860484Sobrien{				/*  '\0' terminated.  */
10960484Sobrien  char *b;			/* pointer to start of string */
11060484Sobrien  char *p;			/* pointer after last character */
11160484Sobrien  char *e;			/* pointer after end of allocated space */
11260484Sobrien} string;
11360484Sobrien
11433965Sjdp/* Stuff that is shared between sub-routines.
11533965Sjdp   Using a shared structure allows cplus_demangle to be reentrant.  */
11633965Sjdp
11733965Sjdpstruct work_stuff
11833965Sjdp{
11933965Sjdp  int options;
12033965Sjdp  char **typevec;
12160484Sobrien  char **ktypevec;
12260484Sobrien  char **btypevec;
12360484Sobrien  int numk;
12460484Sobrien  int numb;
12560484Sobrien  int ksize;
12660484Sobrien  int bsize;
12733965Sjdp  int ntypes;
12833965Sjdp  int typevec_size;
12933965Sjdp  int constructor;
13033965Sjdp  int destructor;
13133965Sjdp  int static_type;	/* A static member function */
13260484Sobrien  int temp_start;       /* index in demangled to start of template args */
13360484Sobrien  int type_quals;       /* The type qualifiers.  */
13460484Sobrien  int dllimported;	/* Symbol imported from a PE DLL */
13538889Sjdp  char **tmpl_argvec;   /* Template function arguments. */
13638889Sjdp  int ntmpl_args;       /* The number of template function arguments. */
13760484Sobrien  int forgetting_types; /* Nonzero if we are not remembering the types
13860484Sobrien			   we see.  */
13960484Sobrien  string* previous_argument; /* The last function argument demangled.  */
14060484Sobrien  int nrepeats;         /* The number of times to repeat the previous
14160484Sobrien			   argument.  */
14233965Sjdp};
14333965Sjdp
14433965Sjdp#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
14533965Sjdp#define PRINT_ARG_TYPES       (work -> options & DMGL_PARAMS)
14633965Sjdp
14733965Sjdpstatic const struct optable
14833965Sjdp{
14989857Sobrien  const char *const in;
15089857Sobrien  const char *const out;
15189857Sobrien  const int flags;
15233965Sjdp} optable[] = {
15333965Sjdp  {"nw",	  " new",	DMGL_ANSI},	/* new (1.92,	 ansi) */
15433965Sjdp  {"dl",	  " delete",	DMGL_ANSI},	/* new (1.92,	 ansi) */
15533965Sjdp  {"new",	  " new",	0},		/* old (1.91,	 and 1.x) */
15633965Sjdp  {"delete",	  " delete",	0},		/* old (1.91,	 and 1.x) */
15733965Sjdp  {"vn",	  " new []",	DMGL_ANSI},	/* GNU, pending ansi */
15833965Sjdp  {"vd",	  " delete []",	DMGL_ANSI},	/* GNU, pending ansi */
15933965Sjdp  {"as",	  "=",		DMGL_ANSI},	/* ansi */
16033965Sjdp  {"ne",	  "!=",		DMGL_ANSI},	/* old, ansi */
16133965Sjdp  {"eq",	  "==",		DMGL_ANSI},	/* old,	ansi */
16233965Sjdp  {"ge",	  ">=",		DMGL_ANSI},	/* old,	ansi */
16333965Sjdp  {"gt",	  ">",		DMGL_ANSI},	/* old,	ansi */
16433965Sjdp  {"le",	  "<=",		DMGL_ANSI},	/* old,	ansi */
16533965Sjdp  {"lt",	  "<",		DMGL_ANSI},	/* old,	ansi */
16633965Sjdp  {"plus",	  "+",		0},		/* old */
16733965Sjdp  {"pl",	  "+",		DMGL_ANSI},	/* ansi */
16833965Sjdp  {"apl",	  "+=",		DMGL_ANSI},	/* ansi */
16933965Sjdp  {"minus",	  "-",		0},		/* old */
17033965Sjdp  {"mi",	  "-",		DMGL_ANSI},	/* ansi */
17133965Sjdp  {"ami",	  "-=",		DMGL_ANSI},	/* ansi */
17233965Sjdp  {"mult",	  "*",		0},		/* old */
17333965Sjdp  {"ml",	  "*",		DMGL_ANSI},	/* ansi */
17433965Sjdp  {"amu",	  "*=",		DMGL_ANSI},	/* ansi (ARM/Lucid) */
17533965Sjdp  {"aml",	  "*=",		DMGL_ANSI},	/* ansi (GNU/g++) */
17633965Sjdp  {"convert",	  "+",		0},		/* old (unary +) */
17733965Sjdp  {"negate",	  "-",		0},		/* old (unary -) */
17833965Sjdp  {"trunc_mod",	  "%",		0},		/* old */
17933965Sjdp  {"md",	  "%",		DMGL_ANSI},	/* ansi */
18033965Sjdp  {"amd",	  "%=",		DMGL_ANSI},	/* ansi */
18133965Sjdp  {"trunc_div",	  "/",		0},		/* old */
18233965Sjdp  {"dv",	  "/",		DMGL_ANSI},	/* ansi */
18333965Sjdp  {"adv",	  "/=",		DMGL_ANSI},	/* ansi */
18433965Sjdp  {"truth_andif", "&&",		0},		/* old */
18533965Sjdp  {"aa",	  "&&",		DMGL_ANSI},	/* ansi */
18633965Sjdp  {"truth_orif",  "||",		0},		/* old */
18733965Sjdp  {"oo",	  "||",		DMGL_ANSI},	/* ansi */
18833965Sjdp  {"truth_not",	  "!",		0},		/* old */
18933965Sjdp  {"nt",	  "!",		DMGL_ANSI},	/* ansi */
19033965Sjdp  {"postincrement","++",	0},		/* old */
19133965Sjdp  {"pp",	  "++",		DMGL_ANSI},	/* ansi */
19233965Sjdp  {"postdecrement","--",	0},		/* old */
19333965Sjdp  {"mm",	  "--",		DMGL_ANSI},	/* ansi */
19433965Sjdp  {"bit_ior",	  "|",		0},		/* old */
19533965Sjdp  {"or",	  "|",		DMGL_ANSI},	/* ansi */
19633965Sjdp  {"aor",	  "|=",		DMGL_ANSI},	/* ansi */
19733965Sjdp  {"bit_xor",	  "^",		0},		/* old */
19833965Sjdp  {"er",	  "^",		DMGL_ANSI},	/* ansi */
19933965Sjdp  {"aer",	  "^=",		DMGL_ANSI},	/* ansi */
20033965Sjdp  {"bit_and",	  "&",		0},		/* old */
20133965Sjdp  {"ad",	  "&",		DMGL_ANSI},	/* ansi */
20233965Sjdp  {"aad",	  "&=",		DMGL_ANSI},	/* ansi */
20333965Sjdp  {"bit_not",	  "~",		0},		/* old */
20433965Sjdp  {"co",	  "~",		DMGL_ANSI},	/* ansi */
20533965Sjdp  {"call",	  "()",		0},		/* old */
20633965Sjdp  {"cl",	  "()",		DMGL_ANSI},	/* ansi */
20733965Sjdp  {"alshift",	  "<<",		0},		/* old */
20833965Sjdp  {"ls",	  "<<",		DMGL_ANSI},	/* ansi */
20933965Sjdp  {"als",	  "<<=",	DMGL_ANSI},	/* ansi */
21033965Sjdp  {"arshift",	  ">>",		0},		/* old */
21133965Sjdp  {"rs",	  ">>",		DMGL_ANSI},	/* ansi */
21233965Sjdp  {"ars",	  ">>=",	DMGL_ANSI},	/* ansi */
21333965Sjdp  {"component",	  "->",		0},		/* old */
21433965Sjdp  {"pt",	  "->",		DMGL_ANSI},	/* ansi; Lucid C++ form */
21533965Sjdp  {"rf",	  "->",		DMGL_ANSI},	/* ansi; ARM/GNU form */
21633965Sjdp  {"indirect",	  "*",		0},		/* old */
21733965Sjdp  {"method_call",  "->()",	0},		/* old */
21833965Sjdp  {"addr",	  "&",		0},		/* old (unary &) */
21933965Sjdp  {"array",	  "[]",		0},		/* old */
22033965Sjdp  {"vc",	  "[]",		DMGL_ANSI},	/* ansi */
22133965Sjdp  {"compound",	  ", ",		0},		/* old */
22233965Sjdp  {"cm",	  ", ",		DMGL_ANSI},	/* ansi */
22333965Sjdp  {"cond",	  "?:",		0},		/* old */
22433965Sjdp  {"cn",	  "?:",		DMGL_ANSI},	/* pseudo-ansi */
22533965Sjdp  {"max",	  ">?",		0},		/* old */
22633965Sjdp  {"mx",	  ">?",		DMGL_ANSI},	/* pseudo-ansi */
22733965Sjdp  {"min",	  "<?",		0},		/* old */
22833965Sjdp  {"mn",	  "<?",		DMGL_ANSI},	/* pseudo-ansi */
22933965Sjdp  {"nop",	  "",		0},		/* old (for operator=) */
23060484Sobrien  {"rm",	  "->*",	DMGL_ANSI},	/* ansi */
23160484Sobrien  {"sz",          "sizeof ",    DMGL_ANSI}      /* pseudo-ansi */
23233965Sjdp};
23333965Sjdp
23460484Sobrien/* These values are used to indicate the various type varieties.
23560484Sobrien   They are all non-zero so that they can be used as `success'
23660484Sobrien   values.  */
23760484Sobrientypedef enum type_kind_t
23860484Sobrien{
23960484Sobrien  tk_none,
24060484Sobrien  tk_pointer,
24160484Sobrien  tk_reference,
24260484Sobrien  tk_integral,
24360484Sobrien  tk_bool,
24460484Sobrien  tk_char,
24560484Sobrien  tk_real
24660484Sobrien} type_kind_t;
24733965Sjdp
24889857Sobrienconst struct demangler_engine libiberty_demanglers[] =
24968765Sobrien{
25068765Sobrien  {
25189857Sobrien    NO_DEMANGLING_STYLE_STRING,
25289857Sobrien    no_demangling,
25389857Sobrien    "Demangling disabled"
25489857Sobrien  }
25589857Sobrien  ,
25689857Sobrien  {
25768765Sobrien    AUTO_DEMANGLING_STYLE_STRING,
25868765Sobrien      auto_demangling,
25968765Sobrien      "Automatic selection based on executable"
26068765Sobrien  }
26168765Sobrien  ,
26268765Sobrien  {
26368765Sobrien    GNU_DEMANGLING_STYLE_STRING,
26468765Sobrien      gnu_demangling,
26568765Sobrien      "GNU (g++) style demangling"
26668765Sobrien  }
26768765Sobrien  ,
26868765Sobrien  {
26968765Sobrien    LUCID_DEMANGLING_STYLE_STRING,
27068765Sobrien      lucid_demangling,
27168765Sobrien      "Lucid (lcc) style demangling"
27268765Sobrien  }
27368765Sobrien  ,
27468765Sobrien  {
27568765Sobrien    ARM_DEMANGLING_STYLE_STRING,
27668765Sobrien      arm_demangling,
27768765Sobrien      "ARM style demangling"
27868765Sobrien  }
27968765Sobrien  ,
28068765Sobrien  {
28168765Sobrien    HP_DEMANGLING_STYLE_STRING,
28268765Sobrien      hp_demangling,
28368765Sobrien      "HP (aCC) style demangling"
28468765Sobrien  }
28568765Sobrien  ,
28668765Sobrien  {
28768765Sobrien    EDG_DEMANGLING_STYLE_STRING,
28868765Sobrien      edg_demangling,
28968765Sobrien      "EDG style demangling"
29068765Sobrien  }
29168765Sobrien  ,
29268765Sobrien  {
29377298Sobrien    GNU_V3_DEMANGLING_STYLE_STRING,
29477298Sobrien    gnu_v3_demangling,
29577298Sobrien    "GNU (g++) V3 ABI-style demangling"
29668765Sobrien  }
29768765Sobrien  ,
29868765Sobrien  {
29977298Sobrien    JAVA_DEMANGLING_STYLE_STRING,
30077298Sobrien    java_demangling,
30177298Sobrien    "Java style demangling"
30277298Sobrien  }
30377298Sobrien  ,
30477298Sobrien  {
30577298Sobrien    GNAT_DEMANGLING_STYLE_STRING,
30677298Sobrien    gnat_demangling,
30777298Sobrien    "GNAT style demangling"
30877298Sobrien  }
30977298Sobrien  ,
31077298Sobrien  {
31168765Sobrien    NULL, unknown_demangling, NULL
31268765Sobrien  }
31368765Sobrien};
31468765Sobrien
31533965Sjdp#define STRING_EMPTY(str)	((str) -> b == (str) -> p)
31633965Sjdp#define APPEND_BLANK(str)	{if (!STRING_EMPTY(str)) \
31733965Sjdp    string_append(str, " ");}
31860484Sobrien#define LEN_STRING(str)         ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
31933965Sjdp
32060484Sobrien/* The scope separator appropriate for the language being demangled.  */
32160484Sobrien
32260484Sobrien#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::")
32360484Sobrien
32433965Sjdp#define ARM_VTABLE_STRING "__vtbl__"	/* Lucid/ARM virtual table prefix */
32533965Sjdp#define ARM_VTABLE_STRLEN 8		/* strlen (ARM_VTABLE_STRING) */
32633965Sjdp
32733965Sjdp/* Prototypes for local functions */
32833965Sjdp
329218822Sdimstatic void delete_work_stuff (struct work_stuff *);
33068765Sobrien
331218822Sdimstatic void delete_non_B_K_work_stuff (struct work_stuff *);
33268765Sobrien
333218822Sdimstatic char *mop_up (struct work_stuff *, string *, int);
33433965Sjdp
335218822Sdimstatic void squangle_mop_up (struct work_stuff *);
33660484Sobrien
337218822Sdimstatic void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *);
33868765Sobrien
33933965Sjdp#if 0
34033965Sjdpstatic int
341218822Sdimdemangle_method_args (struct work_stuff *, const char **, string *);
34233965Sjdp#endif
34333965Sjdp
34460484Sobrienstatic char *
345218822Sdiminternal_cplus_demangle (struct work_stuff *, const char *);
34660484Sobrien
34733965Sjdpstatic int
348218822Sdimdemangle_template_template_parm (struct work_stuff *work,
349218822Sdim                                 const char **, string *);
35060484Sobrien
35160484Sobrienstatic int
352218822Sdimdemangle_template (struct work_stuff *work, const char **, string *,
353218822Sdim                   string *, int, int);
35433965Sjdp
35533965Sjdpstatic int
356218822Sdimarm_pt (struct work_stuff *, const char *, int, const char **,
357218822Sdim        const char **);
35833965Sjdp
35933965Sjdpstatic int
360218822Sdimdemangle_class_name (struct work_stuff *, const char **, string *);
36133965Sjdp
36233965Sjdpstatic int
363218822Sdimdemangle_qualified (struct work_stuff *, const char **, string *,
364218822Sdim                    int, int);
36533965Sjdp
366218822Sdimstatic int demangle_class (struct work_stuff *, const char **, string *);
36733965Sjdp
368218822Sdimstatic int demangle_fund_type (struct work_stuff *, const char **, string *);
36933965Sjdp
370218822Sdimstatic int demangle_signature (struct work_stuff *, const char **, string *);
37133965Sjdp
372218822Sdimstatic int demangle_prefix (struct work_stuff *, const char **, string *);
37333965Sjdp
374218822Sdimstatic int gnu_special (struct work_stuff *, const char **, string *);
37533965Sjdp
376218822Sdimstatic int arm_special (const char **, string *);
37733965Sjdp
378218822Sdimstatic void string_need (string *, int);
37933965Sjdp
380218822Sdimstatic void string_delete (string *);
38133965Sjdp
38233965Sjdpstatic void
383218822Sdimstring_init (string *);
38433965Sjdp
385218822Sdimstatic void string_clear (string *);
38633965Sjdp
38733965Sjdp#if 0
388218822Sdimstatic int string_empty (string *);
38933965Sjdp#endif
39033965Sjdp
391218822Sdimstatic void string_append (string *, const char *);
39233965Sjdp
393218822Sdimstatic void string_appends (string *, string *);
39433965Sjdp
395218822Sdimstatic void string_appendn (string *, const char *, int);
39633965Sjdp
397218822Sdimstatic void string_prepend (string *, const char *);
39833965Sjdp
399218822Sdimstatic void string_prependn (string *, const char *, int);
40033965Sjdp
401218822Sdimstatic void string_append_template_idx (string *, int);
40260484Sobrien
403218822Sdimstatic int get_count (const char **, int *);
40433965Sjdp
405218822Sdimstatic int consume_count (const char **);
40633965Sjdp
407218822Sdimstatic int consume_count_with_underscores (const char**);
40838889Sjdp
409218822Sdimstatic int demangle_args (struct work_stuff *, const char **, string *);
41033965Sjdp
411218822Sdimstatic int demangle_nested_args (struct work_stuff*, const char**, string*);
41260484Sobrien
413218822Sdimstatic int do_type (struct work_stuff *, const char **, string *);
41433965Sjdp
415218822Sdimstatic int do_arg (struct work_stuff *, const char **, string *);
41633965Sjdp
41733965Sjdpstatic void
418218822Sdimdemangle_function_name (struct work_stuff *, const char **, string *,
419218822Sdim                        const char *);
42033965Sjdp
42168765Sobrienstatic int
422218822Sdimiterate_demangle_function (struct work_stuff *,
423218822Sdim                           const char **, string *, const char *);
42468765Sobrien
425218822Sdimstatic void remember_type (struct work_stuff *, const char *, int);
42633965Sjdp
427218822Sdimstatic void remember_Btype (struct work_stuff *, const char *, int, int);
42860484Sobrien
429218822Sdimstatic int register_Btype (struct work_stuff *);
43060484Sobrien
431218822Sdimstatic void remember_Ktype (struct work_stuff *, const char *, int);
43260484Sobrien
433218822Sdimstatic void forget_types (struct work_stuff *);
43433965Sjdp
435218822Sdimstatic void forget_B_and_K_types (struct work_stuff *);
43660484Sobrien
437218822Sdimstatic void string_prepends (string *, string *);
43833965Sjdp
43960484Sobrienstatic int
440218822Sdimdemangle_template_value_parm (struct work_stuff*, const char**,
441218822Sdim                              string*, type_kind_t);
44233965Sjdp
44333965Sjdpstatic int
444218822Sdimdo_hpacc_template_const_value (struct work_stuff *, const char **, string *);
44560484Sobrien
44660484Sobrienstatic int
447218822Sdimdo_hpacc_template_literal (struct work_stuff *, const char **, string *);
44860484Sobrien
449218822Sdimstatic int snarf_numeric_literal (const char **, string *);
45060484Sobrien
45160484Sobrien/* There is a TYPE_QUAL value for each type qualifier.  They can be
45260484Sobrien   combined by bitwise-or to form the complete set of qualifiers for a
45360484Sobrien   type.  */
45460484Sobrien
45560484Sobrien#define TYPE_UNQUALIFIED   0x0
45660484Sobrien#define TYPE_QUAL_CONST    0x1
45760484Sobrien#define TYPE_QUAL_VOLATILE 0x2
45860484Sobrien#define TYPE_QUAL_RESTRICT 0x4
45960484Sobrien
460218822Sdimstatic int code_for_qualifier (int);
46160484Sobrien
462218822Sdimstatic const char* qualifier_string (int);
46360484Sobrien
464218822Sdimstatic const char* demangle_qualifier (int);
46560484Sobrien
466218822Sdimstatic int demangle_expression (struct work_stuff *, const char **, string *,
467218822Sdim                                type_kind_t);
46860484Sobrien
46960484Sobrienstatic int
470218822Sdimdemangle_integral_value (struct work_stuff *, const char **, string *);
47160484Sobrien
47260484Sobrienstatic int
473218822Sdimdemangle_real_value (struct work_stuff *, const char **, string *);
47460484Sobrien
47560484Sobrienstatic void
476218822Sdimdemangle_arm_hp_template (struct work_stuff *, const char **, int, string *);
47760484Sobrien
47860484Sobrienstatic void
479218822Sdimrecursively_demangle (struct work_stuff *, const char **, string *, int);
48060484Sobrien
481218822Sdimstatic void grow_vect (char **, size_t *, size_t, int);
48277298Sobrien
48360484Sobrien/* Translate count to integer, consuming tokens in the process.
48460484Sobrien   Conversion terminates on the first non-digit character.
48560484Sobrien
48660484Sobrien   Trying to consume something that isn't a count results in no
48760484Sobrien   consumption of input and a return of -1.
48860484Sobrien
48960484Sobrien   Overflow consumes the rest of the digits, and returns -1.  */
49060484Sobrien
49160484Sobrienstatic int
492218822Sdimconsume_count (const char **type)
49333965Sjdp{
49433965Sjdp  int count = 0;
49533965Sjdp
49677298Sobrien  if (! ISDIGIT ((unsigned char)**type))
49760484Sobrien    return -1;
49860484Sobrien
49977298Sobrien  while (ISDIGIT ((unsigned char)**type))
50033965Sjdp    {
50133965Sjdp      count *= 10;
50260484Sobrien
50360484Sobrien      /* Check for overflow.
50460484Sobrien	 We assume that count is represented using two's-complement;
50560484Sobrien	 no power of two is divisible by ten, so if an overflow occurs
50660484Sobrien	 when multiplying by ten, the result will not be a multiple of
50760484Sobrien	 ten.  */
50860484Sobrien      if ((count % 10) != 0)
50960484Sobrien	{
51077298Sobrien	  while (ISDIGIT ((unsigned char) **type))
51160484Sobrien	    (*type)++;
51260484Sobrien	  return -1;
51360484Sobrien	}
51460484Sobrien
51533965Sjdp      count += **type - '0';
51633965Sjdp      (*type)++;
51733965Sjdp    }
51860484Sobrien
51989857Sobrien  if (count < 0)
52089857Sobrien    count = -1;
52189857Sobrien
52233965Sjdp  return (count);
52333965Sjdp}
52433965Sjdp
52538889Sjdp
52660484Sobrien/* Like consume_count, but for counts that are preceded and followed
52738889Sjdp   by '_' if they are greater than 10.  Also, -1 is returned for
52838889Sjdp   failure, since 0 can be a valid value.  */
52938889Sjdp
53038889Sjdpstatic int
531218822Sdimconsume_count_with_underscores (const char **mangled)
53238889Sjdp{
53338889Sjdp  int idx;
53438889Sjdp
53538889Sjdp  if (**mangled == '_')
53638889Sjdp    {
53738889Sjdp      (*mangled)++;
53877298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
53938889Sjdp	return -1;
54038889Sjdp
54138889Sjdp      idx = consume_count (mangled);
54238889Sjdp      if (**mangled != '_')
54338889Sjdp	/* The trailing underscore was missing. */
54438889Sjdp	return -1;
54560484Sobrien
54638889Sjdp      (*mangled)++;
54738889Sjdp    }
54838889Sjdp  else
54938889Sjdp    {
55038889Sjdp      if (**mangled < '0' || **mangled > '9')
55138889Sjdp	return -1;
55260484Sobrien
55338889Sjdp      idx = **mangled - '0';
55438889Sjdp      (*mangled)++;
55538889Sjdp    }
55638889Sjdp
55738889Sjdp  return idx;
55838889Sjdp}
55938889Sjdp
56060484Sobrien/* C is the code for a type-qualifier.  Return the TYPE_QUAL
56160484Sobrien   corresponding to this qualifier.  */
56260484Sobrien
56360484Sobrienstatic int
564218822Sdimcode_for_qualifier (int c)
56560484Sobrien{
56660484Sobrien  switch (c)
56760484Sobrien    {
56860484Sobrien    case 'C':
56960484Sobrien      return TYPE_QUAL_CONST;
57060484Sobrien
57160484Sobrien    case 'V':
57260484Sobrien      return TYPE_QUAL_VOLATILE;
57360484Sobrien
57460484Sobrien    case 'u':
57560484Sobrien      return TYPE_QUAL_RESTRICT;
57660484Sobrien
57760484Sobrien    default:
57860484Sobrien      break;
57960484Sobrien    }
58060484Sobrien
58160484Sobrien  /* C was an invalid qualifier.  */
58260484Sobrien  abort ();
58360484Sobrien}
58460484Sobrien
58560484Sobrien/* Return the string corresponding to the qualifiers given by
58660484Sobrien   TYPE_QUALS.  */
58760484Sobrien
58860484Sobrienstatic const char*
589218822Sdimqualifier_string (int type_quals)
59060484Sobrien{
59160484Sobrien  switch (type_quals)
59260484Sobrien    {
59360484Sobrien    case TYPE_UNQUALIFIED:
59460484Sobrien      return "";
59560484Sobrien
59660484Sobrien    case TYPE_QUAL_CONST:
59760484Sobrien      return "const";
59860484Sobrien
59960484Sobrien    case TYPE_QUAL_VOLATILE:
60060484Sobrien      return "volatile";
60160484Sobrien
60260484Sobrien    case TYPE_QUAL_RESTRICT:
60360484Sobrien      return "__restrict";
60460484Sobrien
60560484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE:
60660484Sobrien      return "const volatile";
60760484Sobrien
60860484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT:
60960484Sobrien      return "const __restrict";
61060484Sobrien
61160484Sobrien    case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
61260484Sobrien      return "volatile __restrict";
61360484Sobrien
61460484Sobrien    case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT:
61560484Sobrien      return "const volatile __restrict";
61660484Sobrien
61760484Sobrien    default:
61860484Sobrien      break;
61960484Sobrien    }
62060484Sobrien
62160484Sobrien  /* TYPE_QUALS was an invalid qualifier set.  */
62260484Sobrien  abort ();
62360484Sobrien}
62460484Sobrien
62560484Sobrien/* C is the code for a type-qualifier.  Return the string
62660484Sobrien   corresponding to this qualifier.  This function should only be
62760484Sobrien   called with a valid qualifier code.  */
62860484Sobrien
62960484Sobrienstatic const char*
630218822Sdimdemangle_qualifier (int c)
63160484Sobrien{
63260484Sobrien  return qualifier_string (code_for_qualifier (c));
63360484Sobrien}
63460484Sobrien
63533965Sjdpint
636218822Sdimcplus_demangle_opname (const char *opname, char *result, int options)
63733965Sjdp{
63860484Sobrien  int len, len1, ret;
63933965Sjdp  string type;
64033965Sjdp  struct work_stuff work[1];
64133965Sjdp  const char *tem;
64233965Sjdp
64333965Sjdp  len = strlen(opname);
64433965Sjdp  result[0] = '\0';
64533965Sjdp  ret = 0;
64660484Sobrien  memset ((char *) work, 0, sizeof (work));
64733965Sjdp  work->options = options;
64860484Sobrien
64933965Sjdp  if (opname[0] == '_' && opname[1] == '_'
65033965Sjdp      && opname[2] == 'o' && opname[3] == 'p')
65133965Sjdp    {
65233965Sjdp      /* ANSI.  */
65333965Sjdp      /* type conversion operator.  */
65433965Sjdp      tem = opname + 4;
65533965Sjdp      if (do_type (work, &tem, &type))
65633965Sjdp	{
65733965Sjdp	  strcat (result, "operator ");
65833965Sjdp	  strncat (result, type.b, type.p - type.b);
65933965Sjdp	  string_delete (&type);
66033965Sjdp	  ret = 1;
66133965Sjdp	}
66233965Sjdp    }
66333965Sjdp  else if (opname[0] == '_' && opname[1] == '_'
66477298Sobrien	   && ISLOWER((unsigned char)opname[2])
66577298Sobrien	   && ISLOWER((unsigned char)opname[3]))
66633965Sjdp    {
66733965Sjdp      if (opname[4] == '\0')
66833965Sjdp	{
66933965Sjdp	  /* Operator.  */
67060484Sobrien	  size_t i;
67177298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
67233965Sjdp	    {
67333965Sjdp	      if (strlen (optable[i].in) == 2
67433965Sjdp		  && memcmp (optable[i].in, opname + 2, 2) == 0)
67533965Sjdp		{
67633965Sjdp		  strcat (result, "operator");
67733965Sjdp		  strcat (result, optable[i].out);
67833965Sjdp		  ret = 1;
67933965Sjdp		  break;
68033965Sjdp		}
68133965Sjdp	    }
68233965Sjdp	}
68333965Sjdp      else
68433965Sjdp	{
68533965Sjdp	  if (opname[2] == 'a' && opname[5] == '\0')
68633965Sjdp	    {
68733965Sjdp	      /* Assignment.  */
68860484Sobrien	      size_t i;
68977298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
69033965Sjdp		{
69133965Sjdp		  if (strlen (optable[i].in) == 3
69233965Sjdp		      && memcmp (optable[i].in, opname + 2, 3) == 0)
69333965Sjdp		    {
69433965Sjdp		      strcat (result, "operator");
69533965Sjdp		      strcat (result, optable[i].out);
69633965Sjdp		      ret = 1;
69733965Sjdp		      break;
69860484Sobrien		    }
69933965Sjdp		}
70033965Sjdp	    }
70133965Sjdp	}
70233965Sjdp    }
70360484Sobrien  else if (len >= 3
70433965Sjdp	   && opname[0] == 'o'
70533965Sjdp	   && opname[1] == 'p'
70633965Sjdp	   && strchr (cplus_markers, opname[2]) != NULL)
70733965Sjdp    {
70833965Sjdp      /* see if it's an assignment expression */
70933965Sjdp      if (len >= 10 /* op$assign_ */
71033965Sjdp	  && memcmp (opname + 3, "assign_", 7) == 0)
71133965Sjdp	{
71260484Sobrien	  size_t i;
71377298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
71433965Sjdp	    {
71533965Sjdp	      len1 = len - 10;
71660484Sobrien	      if ((int) strlen (optable[i].in) == len1
71733965Sjdp		  && memcmp (optable[i].in, opname + 10, len1) == 0)
71833965Sjdp		{
71933965Sjdp		  strcat (result, "operator");
72033965Sjdp		  strcat (result, optable[i].out);
72133965Sjdp		  strcat (result, "=");
72233965Sjdp		  ret = 1;
72333965Sjdp		  break;
72433965Sjdp		}
72533965Sjdp	    }
72633965Sjdp	}
72733965Sjdp      else
72833965Sjdp	{
72960484Sobrien	  size_t i;
73077298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
73133965Sjdp	    {
73233965Sjdp	      len1 = len - 3;
73360484Sobrien	      if ((int) strlen (optable[i].in) == len1
73433965Sjdp		  && memcmp (optable[i].in, opname + 3, len1) == 0)
73533965Sjdp		{
73633965Sjdp		  strcat (result, "operator");
73733965Sjdp		  strcat (result, optable[i].out);
73833965Sjdp		  ret = 1;
73933965Sjdp		  break;
74033965Sjdp		}
74133965Sjdp	    }
74233965Sjdp	}
74333965Sjdp    }
74433965Sjdp  else if (len >= 5 && memcmp (opname, "type", 4) == 0
74533965Sjdp	   && strchr (cplus_markers, opname[4]) != NULL)
74633965Sjdp    {
74733965Sjdp      /* type conversion operator */
74833965Sjdp      tem = opname + 5;
74933965Sjdp      if (do_type (work, &tem, &type))
75033965Sjdp	{
75133965Sjdp	  strcat (result, "operator ");
75233965Sjdp	  strncat (result, type.b, type.p - type.b);
75333965Sjdp	  string_delete (&type);
75433965Sjdp	  ret = 1;
75533965Sjdp	}
75633965Sjdp    }
75760484Sobrien  squangle_mop_up (work);
75833965Sjdp  return ret;
75933965Sjdp
76033965Sjdp}
76168765Sobrien
76233965Sjdp/* Takes operator name as e.g. "++" and returns mangled
76333965Sjdp   operator name (e.g. "postincrement_expr"), or NULL if not found.
76433965Sjdp
76533965Sjdp   If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
76633965Sjdp   if OPTIONS & DMGL_ANSI == 0, return the old GNU name.  */
76733965Sjdp
76833965Sjdpconst char *
769218822Sdimcplus_mangle_opname (const char *opname, int options)
77033965Sjdp{
77160484Sobrien  size_t i;
77233965Sjdp  int len;
77333965Sjdp
77433965Sjdp  len = strlen (opname);
77577298Sobrien  for (i = 0; i < ARRAY_SIZE (optable); i++)
77633965Sjdp    {
77760484Sobrien      if ((int) strlen (optable[i].out) == len
77833965Sjdp	  && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
77933965Sjdp	  && memcmp (optable[i].out, opname, len) == 0)
78033965Sjdp	return optable[i].in;
78133965Sjdp    }
78233965Sjdp  return (0);
78333965Sjdp}
78433965Sjdp
78568765Sobrien/* Add a routine to set the demangling style to be sure it is valid and
78668765Sobrien   allow for any demangler initialization that maybe necessary. */
78768765Sobrien
78868765Sobrienenum demangling_styles
789218822Sdimcplus_demangle_set_style (enum demangling_styles style)
79068765Sobrien{
79189857Sobrien  const struct demangler_engine *demangler = libiberty_demanglers;
79268765Sobrien
79368765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
79468765Sobrien    if (style == demangler->demangling_style)
79568765Sobrien      {
79668765Sobrien	current_demangling_style = style;
79768765Sobrien	return current_demangling_style;
79868765Sobrien      }
79968765Sobrien
80068765Sobrien  return unknown_demangling;
80168765Sobrien}
80268765Sobrien
80368765Sobrien/* Do string name to style translation */
80468765Sobrien
80568765Sobrienenum demangling_styles
806218822Sdimcplus_demangle_name_to_style (const char *name)
80768765Sobrien{
80889857Sobrien  const struct demangler_engine *demangler = libiberty_demanglers;
80968765Sobrien
81068765Sobrien  for (; demangler->demangling_style != unknown_demangling; ++demangler)
81168765Sobrien    if (strcmp (name, demangler->demangling_style_name) == 0)
81268765Sobrien      return demangler->demangling_style;
81368765Sobrien
81468765Sobrien  return unknown_demangling;
81568765Sobrien}
81668765Sobrien
81733965Sjdp/* char *cplus_demangle (const char *mangled, int options)
81833965Sjdp
81933965Sjdp   If MANGLED is a mangled function name produced by GNU C++, then
82089857Sobrien   a pointer to a @code{malloc}ed string giving a C++ representation
82133965Sjdp   of the name will be returned; otherwise NULL will be returned.
82233965Sjdp   It is the caller's responsibility to free the string which
82333965Sjdp   is returned.
82433965Sjdp
82533965Sjdp   The OPTIONS arg may contain one or more of the following bits:
82633965Sjdp
82733965Sjdp   	DMGL_ANSI	ANSI qualifiers such as `const' and `void' are
82833965Sjdp			included.
82933965Sjdp	DMGL_PARAMS	Function parameters are included.
83033965Sjdp
83133965Sjdp   For example,
83260484Sobrien
83333965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS)		=> "A::foo(int)"
83433965Sjdp   cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI)	=> "A::foo(int)"
83533965Sjdp   cplus_demangle ("foo__1Ai", 0)			=> "A::foo"
83633965Sjdp
83733965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS)		=> "A::foo(float,...)"
83833965Sjdp   cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
83933965Sjdp   cplus_demangle ("foo__1Afe", 0)			=> "A::foo"
84033965Sjdp
84133965Sjdp   Note that any leading underscores, or other such characters prepended by
84233965Sjdp   the compilation system, are presumed to have already been stripped from
84333965Sjdp   MANGLED.  */
84433965Sjdp
84533965Sjdpchar *
846218822Sdimcplus_demangle (const char *mangled, int options)
84733965Sjdp{
84860484Sobrien  char *ret;
84960484Sobrien  struct work_stuff work[1];
85089857Sobrien
85189857Sobrien  if (current_demangling_style == no_demangling)
85289857Sobrien    return xstrdup (mangled);
85389857Sobrien
85460484Sobrien  memset ((char *) work, 0, sizeof (work));
85577298Sobrien  work->options = options;
85677298Sobrien  if ((work->options & DMGL_STYLE_MASK) == 0)
85777298Sobrien    work->options |= (int) current_demangling_style & DMGL_STYLE_MASK;
85860484Sobrien
85977298Sobrien  /* The V3 ABI demangling is implemented elsewhere.  */
86077298Sobrien  if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
86177298Sobrien    {
86291041Sobrien      ret = cplus_demangle_v3 (mangled, work->options);
86377298Sobrien      if (ret || GNU_V3_DEMANGLING)
86477298Sobrien	return ret;
86577298Sobrien    }
86668765Sobrien
86789857Sobrien  if (JAVA_DEMANGLING)
86889857Sobrien    {
86989857Sobrien      ret = java_demangle_v3 (mangled);
87089857Sobrien      if (ret)
87189857Sobrien        return ret;
87289857Sobrien    }
87389857Sobrien
87477298Sobrien  if (GNAT_DEMANGLING)
87577298Sobrien    return ada_demangle(mangled,options);
87677298Sobrien
87760484Sobrien  ret = internal_cplus_demangle (work, mangled);
87860484Sobrien  squangle_mop_up (work);
87960484Sobrien  return (ret);
88060484Sobrien}
88160484Sobrien
88260484Sobrien
88377298Sobrien/* Assuming *OLD_VECT points to an array of *SIZE objects of size
88477298Sobrien   ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
88577298Sobrien   updating *OLD_VECT and *SIZE as necessary.  */
88677298Sobrien
88777298Sobrienstatic void
888218822Sdimgrow_vect (char **old_vect, size_t *size, size_t min_size, int element_size)
88977298Sobrien{
89077298Sobrien  if (*size < min_size)
89177298Sobrien    {
89277298Sobrien      *size *= 2;
89377298Sobrien      if (*size < min_size)
89477298Sobrien	*size = min_size;
895218822Sdim      *old_vect = XRESIZEVAR (char, *old_vect, *size * element_size);
89677298Sobrien    }
89777298Sobrien}
89877298Sobrien
89977298Sobrien/* Demangle ada names:
90077298Sobrien   1. Discard final __{DIGIT}+ or ${DIGIT}+
90177298Sobrien   2. Convert other instances of embedded "__" to `.'.
90277298Sobrien   3. Discard leading _ada_.
90377298Sobrien   4. Remove everything after first ___ if it is followed by 'X'.
90477298Sobrien   5. Put symbols that should be suppressed in <...> brackets.
90577298Sobrien   The resulting string is valid until the next call of ada_demangle.  */
90677298Sobrien
90777298Sobrienstatic char *
908218822Sdimada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
90977298Sobrien{
91077298Sobrien  int i, j;
91177298Sobrien  int len0;
91277298Sobrien  const char* p;
91377298Sobrien  char *demangled = NULL;
91477298Sobrien  int changed;
915130561Sobrien  size_t demangled_size = 0;
91677298Sobrien
91777298Sobrien  changed = 0;
91877298Sobrien
91977298Sobrien  if (strncmp (mangled, "_ada_", 5) == 0)
92077298Sobrien    {
92177298Sobrien      mangled += 5;
92277298Sobrien      changed = 1;
92377298Sobrien    }
92477298Sobrien
92577298Sobrien  if (mangled[0] == '_' || mangled[0] == '<')
92677298Sobrien    goto Suppress;
92777298Sobrien
92877298Sobrien  p = strstr (mangled, "___");
92977298Sobrien  if (p == NULL)
93077298Sobrien    len0 = strlen (mangled);
93177298Sobrien  else
93277298Sobrien    {
93377298Sobrien      if (p[3] == 'X')
93477298Sobrien	{
93577298Sobrien	  len0 = p - mangled;
93677298Sobrien	  changed = 1;
93777298Sobrien	}
93877298Sobrien      else
93977298Sobrien	goto Suppress;
94077298Sobrien    }
94177298Sobrien
94277298Sobrien  /* Make demangled big enough for possible expansion by operator name.  */
943130561Sobrien  grow_vect (&demangled,
944130561Sobrien	     &demangled_size,  2 * len0 + 1,
94577298Sobrien	     sizeof (char));
94677298Sobrien
94777298Sobrien  if (ISDIGIT ((unsigned char) mangled[len0 - 1])) {
94877298Sobrien    for (i = len0 - 2; i >= 0 && ISDIGIT ((unsigned char) mangled[i]); i -= 1)
94977298Sobrien      ;
95077298Sobrien    if (i > 1 && mangled[i] == '_' && mangled[i - 1] == '_')
95177298Sobrien      {
95277298Sobrien	len0 = i - 1;
95377298Sobrien	changed = 1;
95477298Sobrien      }
95577298Sobrien    else if (mangled[i] == '$')
95677298Sobrien      {
95777298Sobrien	len0 = i;
95877298Sobrien	changed = 1;
95977298Sobrien      }
96077298Sobrien  }
96177298Sobrien
96277298Sobrien  for (i = 0, j = 0; i < len0 && ! ISALPHA ((unsigned char)mangled[i]);
96377298Sobrien       i += 1, j += 1)
96477298Sobrien    demangled[j] = mangled[i];
96577298Sobrien
96677298Sobrien  while (i < len0)
96777298Sobrien    {
96877298Sobrien      if (i < len0 - 2 && mangled[i] == '_' && mangled[i + 1] == '_')
96977298Sobrien	{
97077298Sobrien	  demangled[j] = '.';
971218822Sdim	  changed = 1;
97277298Sobrien	  i += 2; j += 1;
97377298Sobrien	}
97477298Sobrien      else
97577298Sobrien	{
97677298Sobrien	  demangled[j] = mangled[i];
97777298Sobrien	  i += 1;  j += 1;
97877298Sobrien	}
97977298Sobrien    }
98077298Sobrien  demangled[j] = '\000';
98177298Sobrien
98277298Sobrien  for (i = 0; demangled[i] != '\0'; i += 1)
98377298Sobrien    if (ISUPPER ((unsigned char)demangled[i]) || demangled[i] == ' ')
98477298Sobrien      goto Suppress;
98577298Sobrien
98677298Sobrien  if (! changed)
98777298Sobrien    return NULL;
98877298Sobrien  else
98977298Sobrien    return demangled;
99077298Sobrien
99177298Sobrien Suppress:
992130561Sobrien  grow_vect (&demangled,
993130561Sobrien	     &demangled_size,  strlen (mangled) + 3,
99477298Sobrien	     sizeof (char));
995130561Sobrien
99677298Sobrien  if (mangled[0] == '<')
99777298Sobrien     strcpy (demangled, mangled);
99877298Sobrien  else
99977298Sobrien    sprintf (demangled, "<%s>", mangled);
100077298Sobrien
100177298Sobrien  return demangled;
100277298Sobrien}
100377298Sobrien
100460484Sobrien/* This function performs most of what cplus_demangle use to do, but
100560484Sobrien   to be able to demangle a name with a B, K or n code, we need to
100660484Sobrien   have a longer term memory of what types have been seen. The original
1007130561Sobrien   now initializes and cleans up the squangle code info, while internal
100860484Sobrien   calls go directly to this routine to avoid resetting that info. */
100960484Sobrien
101060484Sobrienstatic char *
1011218822Sdiminternal_cplus_demangle (struct work_stuff *work, const char *mangled)
101260484Sobrien{
101360484Sobrien
101433965Sjdp  string decl;
101533965Sjdp  int success = 0;
101633965Sjdp  char *demangled = NULL;
101777298Sobrien  int s1, s2, s3, s4;
101860484Sobrien  s1 = work->constructor;
101960484Sobrien  s2 = work->destructor;
102060484Sobrien  s3 = work->static_type;
102160484Sobrien  s4 = work->type_quals;
102260484Sobrien  work->constructor = work->destructor = 0;
102360484Sobrien  work->type_quals = TYPE_UNQUALIFIED;
102460484Sobrien  work->dllimported = 0;
102533965Sjdp
102633965Sjdp  if ((mangled != NULL) && (*mangled != '\0'))
102733965Sjdp    {
102833965Sjdp      string_init (&decl);
102933965Sjdp
103033965Sjdp      /* First check to see if gnu style demangling is active and if the
103133965Sjdp	 string to be demangled contains a CPLUS_MARKER.  If so, attempt to
103233965Sjdp	 recognize one of the gnu special forms rather than looking for a
103333965Sjdp	 standard prefix.  In particular, don't worry about whether there
103433965Sjdp	 is a "__" string in the mangled string.  Consider "_$_5__foo" for
103533965Sjdp	 example.  */
103633965Sjdp
103733965Sjdp      if ((AUTO_DEMANGLING || GNU_DEMANGLING))
103833965Sjdp	{
103933965Sjdp	  success = gnu_special (work, &mangled, &decl);
104033965Sjdp	}
104133965Sjdp      if (!success)
104233965Sjdp	{
104333965Sjdp	  success = demangle_prefix (work, &mangled, &decl);
104433965Sjdp	}
104533965Sjdp      if (success && (*mangled != '\0'))
104633965Sjdp	{
104733965Sjdp	  success = demangle_signature (work, &mangled, &decl);
104833965Sjdp	}
104933965Sjdp      if (work->constructor == 2)
105033965Sjdp        {
105160484Sobrien          string_prepend (&decl, "global constructors keyed to ");
105233965Sjdp          work->constructor = 0;
105333965Sjdp        }
105433965Sjdp      else if (work->destructor == 2)
105533965Sjdp        {
105660484Sobrien          string_prepend (&decl, "global destructors keyed to ");
105733965Sjdp          work->destructor = 0;
105833965Sjdp        }
105960484Sobrien      else if (work->dllimported == 1)
106060484Sobrien        {
106160484Sobrien          string_prepend (&decl, "import stub for ");
106260484Sobrien          work->dllimported = 0;
106360484Sobrien        }
106433965Sjdp      demangled = mop_up (work, &decl, success);
106533965Sjdp    }
106660484Sobrien  work->constructor = s1;
106760484Sobrien  work->destructor = s2;
106860484Sobrien  work->static_type = s3;
106960484Sobrien  work->type_quals = s4;
107077298Sobrien  return demangled;
107133965Sjdp}
107233965Sjdp
107360484Sobrien
107460484Sobrien/* Clear out and squangling related storage */
107560484Sobrienstatic void
1076218822Sdimsquangle_mop_up (struct work_stuff *work)
107760484Sobrien{
107860484Sobrien  /* clean up the B and K type mangling types. */
107960484Sobrien  forget_B_and_K_types (work);
108060484Sobrien  if (work -> btypevec != NULL)
108160484Sobrien    {
108260484Sobrien      free ((char *) work -> btypevec);
108360484Sobrien    }
108460484Sobrien  if (work -> ktypevec != NULL)
108560484Sobrien    {
108660484Sobrien      free ((char *) work -> ktypevec);
108760484Sobrien    }
108860484Sobrien}
108960484Sobrien
109060484Sobrien
109168765Sobrien/* Copy the work state and storage.  */
109268765Sobrien
109368765Sobrienstatic void
1094218822Sdimwork_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from)
109568765Sobrien{
109668765Sobrien  int i;
109768765Sobrien
109868765Sobrien  delete_work_stuff (to);
109968765Sobrien
110068765Sobrien  /* Shallow-copy scalars.  */
110168765Sobrien  memcpy (to, from, sizeof (*to));
110268765Sobrien
110368765Sobrien  /* Deep-copy dynamic storage.  */
110468765Sobrien  if (from->typevec_size)
1105218822Sdim    to->typevec = XNEWVEC (char *, from->typevec_size);
110668765Sobrien
110768765Sobrien  for (i = 0; i < from->ntypes; i++)
110868765Sobrien    {
110968765Sobrien      int len = strlen (from->typevec[i]) + 1;
111068765Sobrien
1111218822Sdim      to->typevec[i] = XNEWVEC (char, len);
111268765Sobrien      memcpy (to->typevec[i], from->typevec[i], len);
111368765Sobrien    }
111468765Sobrien
111568765Sobrien  if (from->ksize)
1116218822Sdim    to->ktypevec = XNEWVEC (char *, from->ksize);
111768765Sobrien
111868765Sobrien  for (i = 0; i < from->numk; i++)
111968765Sobrien    {
112068765Sobrien      int len = strlen (from->ktypevec[i]) + 1;
112168765Sobrien
1122218822Sdim      to->ktypevec[i] = XNEWVEC (char, len);
112368765Sobrien      memcpy (to->ktypevec[i], from->ktypevec[i], len);
112468765Sobrien    }
112568765Sobrien
112668765Sobrien  if (from->bsize)
1127218822Sdim    to->btypevec = XNEWVEC (char *, from->bsize);
112868765Sobrien
112968765Sobrien  for (i = 0; i < from->numb; i++)
113068765Sobrien    {
113168765Sobrien      int len = strlen (from->btypevec[i]) + 1;
113268765Sobrien
1133218822Sdim      to->btypevec[i] = XNEWVEC (char , len);
113468765Sobrien      memcpy (to->btypevec[i], from->btypevec[i], len);
113568765Sobrien    }
113668765Sobrien
113768765Sobrien  if (from->ntmpl_args)
1138218822Sdim    to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args);
113968765Sobrien
114068765Sobrien  for (i = 0; i < from->ntmpl_args; i++)
114168765Sobrien    {
114268765Sobrien      int len = strlen (from->tmpl_argvec[i]) + 1;
114368765Sobrien
1144218822Sdim      to->tmpl_argvec[i] = XNEWVEC (char, len);
114568765Sobrien      memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len);
114668765Sobrien    }
114768765Sobrien
114868765Sobrien  if (from->previous_argument)
114968765Sobrien    {
1150218822Sdim      to->previous_argument = XNEW (string);
115168765Sobrien      string_init (to->previous_argument);
115268765Sobrien      string_appends (to->previous_argument, from->previous_argument);
115368765Sobrien    }
115468765Sobrien}
115568765Sobrien
115668765Sobrien
115768765Sobrien/* Delete dynamic stuff in work_stuff that is not to be re-used.  */
115868765Sobrien
115968765Sobrienstatic void
1160218822Sdimdelete_non_B_K_work_stuff (struct work_stuff *work)
116133965Sjdp{
116233965Sjdp  /* Discard the remembered types, if any.  */
116360484Sobrien
116433965Sjdp  forget_types (work);
116533965Sjdp  if (work -> typevec != NULL)
116633965Sjdp    {
116733965Sjdp      free ((char *) work -> typevec);
116860484Sobrien      work -> typevec = NULL;
116960484Sobrien      work -> typevec_size = 0;
117033965Sjdp    }
117138889Sjdp  if (work->tmpl_argvec)
117238889Sjdp    {
117338889Sjdp      int i;
117438889Sjdp
117538889Sjdp      for (i = 0; i < work->ntmpl_args; i++)
117638889Sjdp	if (work->tmpl_argvec[i])
117738889Sjdp	  free ((char*) work->tmpl_argvec[i]);
117860484Sobrien
117938889Sjdp      free ((char*) work->tmpl_argvec);
118060484Sobrien      work->tmpl_argvec = NULL;
118138889Sjdp    }
118260484Sobrien  if (work->previous_argument)
118360484Sobrien    {
118460484Sobrien      string_delete (work->previous_argument);
118560484Sobrien      free ((char*) work->previous_argument);
118660484Sobrien      work->previous_argument = NULL;
118760484Sobrien    }
118868765Sobrien}
118938889Sjdp
119068765Sobrien
119168765Sobrien/* Delete all dynamic storage in work_stuff.  */
119268765Sobrienstatic void
1193218822Sdimdelete_work_stuff (struct work_stuff *work)
119468765Sobrien{
119568765Sobrien  delete_non_B_K_work_stuff (work);
119668765Sobrien  squangle_mop_up (work);
119768765Sobrien}
119868765Sobrien
119968765Sobrien
120068765Sobrien/* Clear out any mangled storage */
120168765Sobrien
120268765Sobrienstatic char *
1203218822Sdimmop_up (struct work_stuff *work, string *declp, int success)
120468765Sobrien{
120568765Sobrien  char *demangled = NULL;
120668765Sobrien
120768765Sobrien  delete_non_B_K_work_stuff (work);
120868765Sobrien
120933965Sjdp  /* If demangling was successful, ensure that the demangled string is null
121033965Sjdp     terminated and return it.  Otherwise, free the demangling decl.  */
121160484Sobrien
121233965Sjdp  if (!success)
121333965Sjdp    {
121433965Sjdp      string_delete (declp);
121533965Sjdp    }
121633965Sjdp  else
121733965Sjdp    {
121833965Sjdp      string_appendn (declp, "", 1);
121977298Sobrien      demangled = declp->b;
122033965Sjdp    }
122133965Sjdp  return (demangled);
122233965Sjdp}
122333965Sjdp
122433965Sjdp/*
122533965Sjdp
122633965SjdpLOCAL FUNCTION
122733965Sjdp
122833965Sjdp	demangle_signature -- demangle the signature part of a mangled name
122933965Sjdp
123033965SjdpSYNOPSIS
123133965Sjdp
123233965Sjdp	static int
123333965Sjdp	demangle_signature (struct work_stuff *work, const char **mangled,
123433965Sjdp			    string *declp);
123533965Sjdp
123633965SjdpDESCRIPTION
123733965Sjdp
123833965Sjdp	Consume and demangle the signature portion of the mangled name.
123933965Sjdp
124033965Sjdp	DECLP is the string where demangled output is being built.  At
124133965Sjdp	entry it contains the demangled root name from the mangled name
124233965Sjdp	prefix.  I.E. either a demangled operator name or the root function
124333965Sjdp	name.  In some special cases, it may contain nothing.
124433965Sjdp
124533965Sjdp	*MANGLED points to the current unconsumed location in the mangled
124633965Sjdp	name.  As tokens are consumed and demangling is performed, the
124733965Sjdp	pointer is updated to continuously point at the next token to
124833965Sjdp	be consumed.
124933965Sjdp
125033965Sjdp	Demangling GNU style mangled names is nasty because there is no
125133965Sjdp	explicit token that marks the start of the outermost function
125233965Sjdp	argument list.  */
125333965Sjdp
125433965Sjdpstatic int
1255218822Sdimdemangle_signature (struct work_stuff *work,
1256218822Sdim                    const char **mangled, string *declp)
125733965Sjdp{
125833965Sjdp  int success = 1;
125933965Sjdp  int func_done = 0;
126033965Sjdp  int expect_func = 0;
126138889Sjdp  int expect_return_type = 0;
126233965Sjdp  const char *oldmangled = NULL;
126333965Sjdp  string trawname;
126433965Sjdp  string tname;
126533965Sjdp
126633965Sjdp  while (success && (**mangled != '\0'))
126733965Sjdp    {
126833965Sjdp      switch (**mangled)
126933965Sjdp	{
127033965Sjdp	case 'Q':
127133965Sjdp	  oldmangled = *mangled;
127233965Sjdp	  success = demangle_qualified (work, mangled, declp, 1, 0);
127333965Sjdp	  if (success)
127460484Sobrien	    remember_type (work, oldmangled, *mangled - oldmangled);
127533965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
127660484Sobrien	    expect_func = 1;
127760484Sobrien	  oldmangled = NULL;
127860484Sobrien	  break;
127960484Sobrien
128060484Sobrien        case 'K':
128160484Sobrien	  oldmangled = *mangled;
128260484Sobrien	  success = demangle_qualified (work, mangled, declp, 1, 0);
128360484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
128433965Sjdp	    {
128533965Sjdp	      expect_func = 1;
128633965Sjdp	    }
128733965Sjdp	  oldmangled = NULL;
128833965Sjdp	  break;
128960484Sobrien
129033965Sjdp	case 'S':
129133965Sjdp	  /* Static member function */
129233965Sjdp	  if (oldmangled == NULL)
129333965Sjdp	    {
129433965Sjdp	      oldmangled = *mangled;
129533965Sjdp	    }
129633965Sjdp	  (*mangled)++;
129733965Sjdp	  work -> static_type = 1;
129833965Sjdp	  break;
129933965Sjdp
130033965Sjdp	case 'C':
130160484Sobrien	case 'V':
130260484Sobrien	case 'u':
130360484Sobrien	  work->type_quals |= code_for_qualifier (**mangled);
130460484Sobrien
130560484Sobrien	  /* a qualified member function */
130633965Sjdp	  if (oldmangled == NULL)
130760484Sobrien	    oldmangled = *mangled;
130860484Sobrien	  (*mangled)++;
130960484Sobrien	  break;
131060484Sobrien
131160484Sobrien	case 'L':
131260484Sobrien	  /* Local class name follows after "Lnnn_" */
131360484Sobrien	  if (HP_DEMANGLING)
131433965Sjdp	    {
131560484Sobrien	      while (**mangled && (**mangled != '_'))
131660484Sobrien		(*mangled)++;
131760484Sobrien	      if (!**mangled)
131860484Sobrien		success = 0;
131960484Sobrien	      else
132060484Sobrien		(*mangled)++;
132133965Sjdp	    }
132260484Sobrien	  else
132360484Sobrien	    success = 0;
132433965Sjdp	  break;
132560484Sobrien
132633965Sjdp	case '0': case '1': case '2': case '3': case '4':
132733965Sjdp	case '5': case '6': case '7': case '8': case '9':
132833965Sjdp	  if (oldmangled == NULL)
132933965Sjdp	    {
133033965Sjdp	      oldmangled = *mangled;
133133965Sjdp	    }
133260484Sobrien          work->temp_start = -1; /* uppermost call to demangle_class */
133333965Sjdp	  success = demangle_class (work, mangled, declp);
133433965Sjdp	  if (success)
133533965Sjdp	    {
133633965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
133733965Sjdp	    }
133860484Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING)
133933965Sjdp	    {
134060484Sobrien              /* EDG and others will have the "F", so we let the loop cycle
134160484Sobrien                 if we are looking at one. */
134260484Sobrien              if (**mangled != 'F')
134360484Sobrien                 expect_func = 1;
134433965Sjdp	    }
134533965Sjdp	  oldmangled = NULL;
134633965Sjdp	  break;
134760484Sobrien
134860484Sobrien	case 'B':
134960484Sobrien	  {
135060484Sobrien	    string s;
135160484Sobrien	    success = do_type (work, mangled, &s);
135260484Sobrien	    if (success)
135360484Sobrien	      {
135460484Sobrien		string_append (&s, SCOPE_STRING (work));
135560484Sobrien		string_prepends (declp, &s);
1356130561Sobrien		string_delete (&s);
135760484Sobrien	      }
135860484Sobrien	    oldmangled = NULL;
135960484Sobrien	    expect_func = 1;
136060484Sobrien	  }
136160484Sobrien	  break;
136260484Sobrien
136333965Sjdp	case 'F':
136433965Sjdp	  /* Function */
136560484Sobrien	  /* ARM/HP style demangling includes a specific 'F' character after
136633965Sjdp	     the class name.  For GNU style, it is just implied.  So we can
136733965Sjdp	     safely just consume any 'F' at this point and be compatible
136833965Sjdp	     with either style.  */
136933965Sjdp
137033965Sjdp	  oldmangled = NULL;
137133965Sjdp	  func_done = 1;
137233965Sjdp	  (*mangled)++;
137333965Sjdp
137460484Sobrien	  /* For lucid/ARM/HP style we have to forget any types we might
137533965Sjdp	     have remembered up to this point, since they were not argument
137633965Sjdp	     types.  GNU style considers all types seen as available for
137733965Sjdp	     back references.  See comment in demangle_args() */
137833965Sjdp
137960484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
138033965Sjdp	    {
138133965Sjdp	      forget_types (work);
138233965Sjdp	    }
138333965Sjdp	  success = demangle_args (work, mangled, declp);
138460484Sobrien	  /* After picking off the function args, we expect to either
138560484Sobrien	     find the function return type (preceded by an '_') or the
138660484Sobrien	     end of the string. */
138760484Sobrien	  if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_')
138860484Sobrien	    {
138960484Sobrien	      ++(*mangled);
139060484Sobrien              /* At this level, we do not care about the return type. */
139160484Sobrien              success = do_type (work, mangled, &tname);
139260484Sobrien              string_delete (&tname);
139360484Sobrien            }
139460484Sobrien
139533965Sjdp	  break;
139660484Sobrien
139733965Sjdp	case 't':
139833965Sjdp	  /* G++ Template */
139960484Sobrien	  string_init(&trawname);
140033965Sjdp	  string_init(&tname);
140133965Sjdp	  if (oldmangled == NULL)
140233965Sjdp	    {
140333965Sjdp	      oldmangled = *mangled;
140433965Sjdp	    }
140560484Sobrien	  success = demangle_template (work, mangled, &tname,
140660484Sobrien				       &trawname, 1, 1);
140733965Sjdp	  if (success)
140833965Sjdp	    {
140933965Sjdp	      remember_type (work, oldmangled, *mangled - oldmangled);
141033965Sjdp	    }
141160484Sobrien	  string_append (&tname, SCOPE_STRING (work));
141260484Sobrien
141333965Sjdp	  string_prepends(declp, &tname);
141433965Sjdp	  if (work -> destructor & 1)
141533965Sjdp	    {
141633965Sjdp	      string_prepend (&trawname, "~");
141733965Sjdp	      string_appends (declp, &trawname);
141833965Sjdp	      work->destructor -= 1;
141933965Sjdp	    }
142033965Sjdp	  if ((work->constructor & 1) || (work->destructor & 1))
142133965Sjdp	    {
142233965Sjdp	      string_appends (declp, &trawname);
142333965Sjdp	      work->constructor -= 1;
142433965Sjdp	    }
142533965Sjdp	  string_delete(&trawname);
142633965Sjdp	  string_delete(&tname);
142733965Sjdp	  oldmangled = NULL;
142833965Sjdp	  expect_func = 1;
142933965Sjdp	  break;
143033965Sjdp
143133965Sjdp	case '_':
143268765Sobrien	  if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type)
143338889Sjdp	    {
143438889Sjdp	      /* Read the return type. */
143538889Sjdp	      string return_type;
143638889Sjdp
143738889Sjdp	      (*mangled)++;
143838889Sjdp	      success = do_type (work, mangled, &return_type);
143938889Sjdp	      APPEND_BLANK (&return_type);
144038889Sjdp
144138889Sjdp	      string_prepends (declp, &return_type);
144238889Sjdp	      string_delete (&return_type);
144338889Sjdp	      break;
144438889Sjdp	    }
144538889Sjdp	  else
144638889Sjdp	    /* At the outermost level, we cannot have a return type specified,
144738889Sjdp	       so if we run into another '_' at this point we are dealing with
144838889Sjdp	       a mangled name that is either bogus, or has been mangled by
144938889Sjdp	       some algorithm we don't know how to deal with.  So just
145038889Sjdp	       reject the entire demangling.  */
145160484Sobrien            /* However, "_nnn" is an expected suffix for alternate entry point
145260484Sobrien               numbered nnn for a function, with HP aCC, so skip over that
145360484Sobrien               without reporting failure. pai/1997-09-04 */
145460484Sobrien            if (HP_DEMANGLING)
145560484Sobrien              {
145660484Sobrien                (*mangled)++;
145777298Sobrien                while (**mangled && ISDIGIT ((unsigned char)**mangled))
145860484Sobrien                  (*mangled)++;
145960484Sobrien              }
146060484Sobrien            else
146160484Sobrien	      success = 0;
146233965Sjdp	  break;
146333965Sjdp
146438889Sjdp	case 'H':
146568765Sobrien	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
146638889Sjdp	    {
146738889Sjdp	      /* A G++ template function.  Read the template arguments. */
146860484Sobrien	      success = demangle_template (work, mangled, declp, 0, 0,
146960484Sobrien					   0);
147038889Sjdp	      if (!(work->constructor & 1))
147138889Sjdp		expect_return_type = 1;
147238889Sjdp	      (*mangled)++;
147338889Sjdp	      break;
147438889Sjdp	    }
147538889Sjdp	  else
147638889Sjdp	    /* fall through */
147760484Sobrien	    {;}
147838889Sjdp
147933965Sjdp	default:
148033965Sjdp	  if (AUTO_DEMANGLING || GNU_DEMANGLING)
148133965Sjdp	    {
148233965Sjdp	      /* Assume we have stumbled onto the first outermost function
148333965Sjdp		 argument token, and start processing args.  */
148433965Sjdp	      func_done = 1;
148533965Sjdp	      success = demangle_args (work, mangled, declp);
148633965Sjdp	    }
148733965Sjdp	  else
148833965Sjdp	    {
148933965Sjdp	      /* Non-GNU demanglers use a specific token to mark the start
149033965Sjdp		 of the outermost function argument tokens.  Typically 'F',
149160484Sobrien		 for ARM/HP-demangling, for example.  So if we find something
149233965Sjdp		 we are not prepared for, it must be an error.  */
149333965Sjdp	      success = 0;
149433965Sjdp	    }
149533965Sjdp	  break;
149633965Sjdp	}
149733965Sjdp      /*
149833965Sjdp	if (AUTO_DEMANGLING || GNU_DEMANGLING)
149933965Sjdp	*/
150033965Sjdp      {
150133965Sjdp	if (success && expect_func)
150233965Sjdp	  {
150333965Sjdp	    func_done = 1;
150460484Sobrien              if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING)
150560484Sobrien                {
150660484Sobrien                  forget_types (work);
150760484Sobrien                }
150833965Sjdp	    success = demangle_args (work, mangled, declp);
150938889Sjdp	    /* Since template include the mangling of their return types,
151038889Sjdp	       we must set expect_func to 0 so that we don't try do
151138889Sjdp	       demangle more arguments the next time we get here.  */
151238889Sjdp	    expect_func = 0;
151333965Sjdp	  }
151433965Sjdp      }
151533965Sjdp    }
151633965Sjdp  if (success && !func_done)
151733965Sjdp    {
151833965Sjdp      if (AUTO_DEMANGLING || GNU_DEMANGLING)
151933965Sjdp	{
152033965Sjdp	  /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
152133965Sjdp	     bar__3fooi is 'foo::bar(int)'.  We get here when we find the
152233965Sjdp	     first case, and need to ensure that the '(void)' gets added to
152360484Sobrien	     the current declp.  Note that with ARM/HP, the first case
152433965Sjdp	     represents the name of a static data member 'foo::bar',
152533965Sjdp	     which is in the current declp, so we leave it alone.  */
152633965Sjdp	  success = demangle_args (work, mangled, declp);
152733965Sjdp	}
152833965Sjdp    }
152960484Sobrien  if (success && PRINT_ARG_TYPES)
153033965Sjdp    {
153160484Sobrien      if (work->static_type)
153260484Sobrien	string_append (declp, " static");
153360484Sobrien      if (work->type_quals != TYPE_UNQUALIFIED)
153460484Sobrien	{
153560484Sobrien	  APPEND_BLANK (declp);
153660484Sobrien	  string_append (declp, qualifier_string (work->type_quals));
153760484Sobrien	}
153833965Sjdp    }
153960484Sobrien
154033965Sjdp  return (success);
154133965Sjdp}
154233965Sjdp
154333965Sjdp#if 0
154433965Sjdp
154533965Sjdpstatic int
1546218822Sdimdemangle_method_args (struct work_stuff *work, const char **mangled,
1547218822Sdim                      string *declp)
154833965Sjdp{
154933965Sjdp  int success = 0;
155033965Sjdp
155133965Sjdp  if (work -> static_type)
155233965Sjdp    {
155333965Sjdp      string_append (declp, *mangled + 1);
155433965Sjdp      *mangled += strlen (*mangled);
155533965Sjdp      success = 1;
155633965Sjdp    }
155733965Sjdp  else
155833965Sjdp    {
155933965Sjdp      success = demangle_args (work, mangled, declp);
156033965Sjdp    }
156133965Sjdp  return (success);
156233965Sjdp}
156333965Sjdp
156433965Sjdp#endif
156533965Sjdp
156633965Sjdpstatic int
1567218822Sdimdemangle_template_template_parm (struct work_stuff *work,
1568218822Sdim                                 const char **mangled, string *tname)
156960484Sobrien{
157060484Sobrien  int i;
157160484Sobrien  int r;
157260484Sobrien  int need_comma = 0;
157360484Sobrien  int success = 1;
157460484Sobrien  string temp;
157560484Sobrien
157660484Sobrien  string_append (tname, "template <");
157760484Sobrien  /* get size of template parameter list */
157860484Sobrien  if (get_count (mangled, &r))
157960484Sobrien    {
158060484Sobrien      for (i = 0; i < r; i++)
158160484Sobrien	{
158260484Sobrien	  if (need_comma)
158360484Sobrien	    {
158460484Sobrien	      string_append (tname, ", ");
158560484Sobrien	    }
158660484Sobrien
158760484Sobrien	    /* Z for type parameters */
158860484Sobrien	    if (**mangled == 'Z')
158960484Sobrien	      {
159060484Sobrien		(*mangled)++;
159160484Sobrien		string_append (tname, "class");
159260484Sobrien	      }
159360484Sobrien	      /* z for template parameters */
159460484Sobrien	    else if (**mangled == 'z')
159560484Sobrien	      {
159660484Sobrien		(*mangled)++;
159760484Sobrien		success =
159860484Sobrien		  demangle_template_template_parm (work, mangled, tname);
159960484Sobrien		if (!success)
160060484Sobrien		  {
160160484Sobrien		    break;
160260484Sobrien		  }
160360484Sobrien	      }
160460484Sobrien	    else
160560484Sobrien	      {
160660484Sobrien		/* temp is initialized in do_type */
160760484Sobrien		success = do_type (work, mangled, &temp);
160860484Sobrien		if (success)
160960484Sobrien		  {
161060484Sobrien		    string_appends (tname, &temp);
161160484Sobrien		  }
161260484Sobrien		string_delete(&temp);
161360484Sobrien		if (!success)
161460484Sobrien		  {
161560484Sobrien		    break;
161660484Sobrien		  }
161760484Sobrien	      }
161860484Sobrien	  need_comma = 1;
161960484Sobrien	}
162060484Sobrien
162160484Sobrien    }
162260484Sobrien  if (tname->p[-1] == '>')
162360484Sobrien    string_append (tname, " ");
162460484Sobrien  string_append (tname, "> class");
162560484Sobrien  return (success);
162660484Sobrien}
162760484Sobrien
162860484Sobrienstatic int
1629218822Sdimdemangle_expression (struct work_stuff *work, const char **mangled,
1630218822Sdim                     string *s, type_kind_t tk)
163160484Sobrien{
163260484Sobrien  int need_operator = 0;
163360484Sobrien  int success;
163460484Sobrien
163560484Sobrien  success = 1;
163660484Sobrien  string_appendn (s, "(", 1);
163760484Sobrien  (*mangled)++;
163860484Sobrien  while (success && **mangled != 'W' && **mangled != '\0')
163960484Sobrien    {
164060484Sobrien      if (need_operator)
164160484Sobrien	{
164260484Sobrien	  size_t i;
164360484Sobrien	  size_t len;
164460484Sobrien
164560484Sobrien	  success = 0;
164660484Sobrien
164760484Sobrien	  len = strlen (*mangled);
164860484Sobrien
164977298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); ++i)
165060484Sobrien	    {
165160484Sobrien	      size_t l = strlen (optable[i].in);
165260484Sobrien
165360484Sobrien	      if (l <= len
165460484Sobrien		  && memcmp (optable[i].in, *mangled, l) == 0)
165560484Sobrien		{
165660484Sobrien		  string_appendn (s, " ", 1);
165760484Sobrien		  string_append (s, optable[i].out);
165860484Sobrien		  string_appendn (s, " ", 1);
165960484Sobrien		  success = 1;
166060484Sobrien		  (*mangled) += l;
166160484Sobrien		  break;
166260484Sobrien		}
166360484Sobrien	    }
166460484Sobrien
166560484Sobrien	  if (!success)
166660484Sobrien	    break;
166760484Sobrien	}
166860484Sobrien      else
166960484Sobrien	need_operator = 1;
167060484Sobrien
167160484Sobrien      success = demangle_template_value_parm (work, mangled, s, tk);
167260484Sobrien    }
167360484Sobrien
167460484Sobrien  if (**mangled != 'W')
167560484Sobrien    success = 0;
167660484Sobrien  else
167760484Sobrien    {
167860484Sobrien      string_appendn (s, ")", 1);
167960484Sobrien      (*mangled)++;
168060484Sobrien    }
168160484Sobrien
168260484Sobrien  return success;
168360484Sobrien}
168460484Sobrien
168560484Sobrienstatic int
1686218822Sdimdemangle_integral_value (struct work_stuff *work,
1687218822Sdim                         const char **mangled, string *s)
168860484Sobrien{
168960484Sobrien  int success;
169060484Sobrien
169160484Sobrien  if (**mangled == 'E')
169260484Sobrien    success = demangle_expression (work, mangled, s, tk_integral);
169360484Sobrien  else if (**mangled == 'Q' || **mangled == 'K')
169460484Sobrien    success = demangle_qualified (work, mangled, s, 0, 1);
169560484Sobrien  else
169660484Sobrien    {
169760484Sobrien      int value;
169860484Sobrien
169968765Sobrien      /* By default, we let the number decide whether we shall consume an
170068765Sobrien	 underscore.  */
1701104834Sobrien      int multidigit_without_leading_underscore = 0;
170268765Sobrien      int leave_following_underscore = 0;
170368765Sobrien
170460484Sobrien      success = 0;
170560484Sobrien
1706130561Sobrien      if (**mangled == '_')
1707130561Sobrien        {
1708130561Sobrien	  if (mangled[0][1] == 'm')
1709130561Sobrien	    {
1710130561Sobrien	      /* Since consume_count_with_underscores does not handle the
1711130561Sobrien		 `m'-prefix we must do it here, using consume_count and
1712130561Sobrien		 adjusting underscores: we have to consume the underscore
1713130561Sobrien		 matching the prepended one.  */
1714130561Sobrien	      multidigit_without_leading_underscore = 1;
1715130561Sobrien	      string_appendn (s, "-", 1);
1716130561Sobrien	      (*mangled) += 2;
1717130561Sobrien	    }
1718130561Sobrien	  else
1719130561Sobrien	    {
1720130561Sobrien	      /* Do not consume a following underscore;
1721130561Sobrien	         consume_count_with_underscores will consume what
1722130561Sobrien	         should be consumed.  */
1723130561Sobrien	      leave_following_underscore = 1;
1724130561Sobrien	    }
172560484Sobrien	}
1726104834Sobrien      else
1727104834Sobrien	{
1728130561Sobrien	  /* Negative numbers are indicated with a leading `m'.  */
1729130561Sobrien	  if (**mangled == 'm')
1730130561Sobrien	  {
1731130561Sobrien	    string_appendn (s, "-", 1);
1732130561Sobrien	    (*mangled)++;
1733130561Sobrien	  }
1734104834Sobrien	  /* Since consume_count_with_underscores does not handle
1735104834Sobrien	     multi-digit numbers that do not start with an underscore,
1736104834Sobrien	     and this number can be an integer template parameter,
1737104834Sobrien	     we have to call consume_count. */
1738104834Sobrien	  multidigit_without_leading_underscore = 1;
1739104834Sobrien	  /* These multi-digit numbers never end on an underscore,
1740104834Sobrien	     so if there is one then don't eat it. */
1741104834Sobrien	  leave_following_underscore = 1;
1742104834Sobrien	}
174360484Sobrien
174468765Sobrien      /* We must call consume_count if we expect to remove a trailing
174568765Sobrien	 underscore, since consume_count_with_underscores expects
174668765Sobrien	 the leading underscore (that we consumed) if it is to handle
174768765Sobrien	 multi-digit numbers.  */
1748104834Sobrien      if (multidigit_without_leading_underscore)
174968765Sobrien	value = consume_count (mangled);
175068765Sobrien      else
175168765Sobrien	value = consume_count_with_underscores (mangled);
175268765Sobrien
175360484Sobrien      if (value != -1)
175460484Sobrien	{
175560484Sobrien	  char buf[INTBUF_SIZE];
175660484Sobrien	  sprintf (buf, "%d", value);
175760484Sobrien	  string_append (s, buf);
175860484Sobrien
175968765Sobrien	  /* Numbers not otherwise delimited, might have an underscore
176068765Sobrien	     appended as a delimeter, which we should skip.
176168765Sobrien
176268765Sobrien	     ??? This used to always remove a following underscore, which
176368765Sobrien	     is wrong.  If other (arbitrary) cases are followed by an
176468765Sobrien	     underscore, we need to do something more radical.  */
176568765Sobrien
1766104834Sobrien	  if ((value > 9 || multidigit_without_leading_underscore)
176768765Sobrien	      && ! leave_following_underscore
176868765Sobrien	      && **mangled == '_')
176960484Sobrien	    (*mangled)++;
177060484Sobrien
177160484Sobrien	  /* All is well.  */
177260484Sobrien	  success = 1;
177360484Sobrien	}
1774130561Sobrien      }
177560484Sobrien
177660484Sobrien  return success;
177760484Sobrien}
177860484Sobrien
177960484Sobrien/* Demangle the real value in MANGLED.  */
178060484Sobrien
178160484Sobrienstatic int
1782218822Sdimdemangle_real_value (struct work_stuff *work,
1783218822Sdim                     const char **mangled, string *s)
178460484Sobrien{
178560484Sobrien  if (**mangled == 'E')
178660484Sobrien    return demangle_expression (work, mangled, s, tk_real);
178760484Sobrien
178860484Sobrien  if (**mangled == 'm')
178960484Sobrien    {
179060484Sobrien      string_appendn (s, "-", 1);
179160484Sobrien      (*mangled)++;
179260484Sobrien    }
179377298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
179460484Sobrien    {
179560484Sobrien      string_appendn (s, *mangled, 1);
179660484Sobrien      (*mangled)++;
179760484Sobrien    }
179860484Sobrien  if (**mangled == '.') /* fraction */
179960484Sobrien    {
180060484Sobrien      string_appendn (s, ".", 1);
180160484Sobrien      (*mangled)++;
180277298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
180360484Sobrien	{
180460484Sobrien	  string_appendn (s, *mangled, 1);
180560484Sobrien	  (*mangled)++;
180660484Sobrien	}
180760484Sobrien    }
180860484Sobrien  if (**mangled == 'e') /* exponent */
180960484Sobrien    {
181060484Sobrien      string_appendn (s, "e", 1);
181160484Sobrien      (*mangled)++;
181277298Sobrien      while (ISDIGIT ((unsigned char)**mangled))
181360484Sobrien	{
181460484Sobrien	  string_appendn (s, *mangled, 1);
181560484Sobrien	  (*mangled)++;
181660484Sobrien	}
181760484Sobrien    }
181860484Sobrien
181960484Sobrien  return 1;
182060484Sobrien}
182160484Sobrien
182260484Sobrienstatic int
1823218822Sdimdemangle_template_value_parm (struct work_stuff *work, const char **mangled,
1824218822Sdim                              string *s, type_kind_t tk)
182560484Sobrien{
182660484Sobrien  int success = 1;
182760484Sobrien
182860484Sobrien  if (**mangled == 'Y')
182960484Sobrien    {
183060484Sobrien      /* The next argument is a template parameter. */
183160484Sobrien      int idx;
183260484Sobrien
183360484Sobrien      (*mangled)++;
183460484Sobrien      idx = consume_count_with_underscores (mangled);
183560484Sobrien      if (idx == -1
183660484Sobrien	  || (work->tmpl_argvec && idx >= work->ntmpl_args)
183760484Sobrien	  || consume_count_with_underscores (mangled) == -1)
183860484Sobrien	return -1;
183960484Sobrien      if (work->tmpl_argvec)
184060484Sobrien	string_append (s, work->tmpl_argvec[idx]);
184160484Sobrien      else
184260484Sobrien	string_append_template_idx (s, idx);
184360484Sobrien    }
184460484Sobrien  else if (tk == tk_integral)
184560484Sobrien    success = demangle_integral_value (work, mangled, s);
184660484Sobrien  else if (tk == tk_char)
184760484Sobrien    {
184860484Sobrien      char tmp[2];
184960484Sobrien      int val;
185060484Sobrien      if (**mangled == 'm')
185160484Sobrien	{
185260484Sobrien	  string_appendn (s, "-", 1);
185360484Sobrien	  (*mangled)++;
185460484Sobrien	}
185560484Sobrien      string_appendn (s, "'", 1);
185660484Sobrien      val = consume_count(mangled);
185760484Sobrien      if (val <= 0)
185860484Sobrien	success = 0;
185960484Sobrien      else
186060484Sobrien	{
186160484Sobrien	  tmp[0] = (char)val;
186260484Sobrien	  tmp[1] = '\0';
186360484Sobrien	  string_appendn (s, &tmp[0], 1);
186460484Sobrien	  string_appendn (s, "'", 1);
186560484Sobrien	}
186660484Sobrien    }
186760484Sobrien  else if (tk == tk_bool)
186860484Sobrien    {
186960484Sobrien      int val = consume_count (mangled);
187060484Sobrien      if (val == 0)
187160484Sobrien	string_appendn (s, "false", 5);
187260484Sobrien      else if (val == 1)
187360484Sobrien	string_appendn (s, "true", 4);
187460484Sobrien      else
187560484Sobrien	success = 0;
187660484Sobrien    }
187760484Sobrien  else if (tk == tk_real)
187860484Sobrien    success = demangle_real_value (work, mangled, s);
187960484Sobrien  else if (tk == tk_pointer || tk == tk_reference)
188060484Sobrien    {
188160484Sobrien      if (**mangled == 'Q')
188260484Sobrien	success = demangle_qualified (work, mangled, s,
188360484Sobrien				      /*isfuncname=*/0,
188460484Sobrien				      /*append=*/1);
188560484Sobrien      else
188660484Sobrien	{
188760484Sobrien	  int symbol_len  = consume_count (mangled);
188860484Sobrien	  if (symbol_len == -1)
188960484Sobrien	    return -1;
189060484Sobrien	  if (symbol_len == 0)
189160484Sobrien	    string_appendn (s, "0", 1);
189260484Sobrien	  else
189360484Sobrien	    {
1894218822Sdim	      char *p = XNEWVEC (char, symbol_len + 1), *q;
189560484Sobrien	      strncpy (p, *mangled, symbol_len);
189660484Sobrien	      p [symbol_len] = '\0';
189760484Sobrien	      /* We use cplus_demangle here, rather than
189860484Sobrien		 internal_cplus_demangle, because the name of the entity
189960484Sobrien		 mangled here does not make use of any of the squangling
190060484Sobrien		 or type-code information we have built up thus far; it is
190160484Sobrien		 mangled independently.  */
190260484Sobrien	      q = cplus_demangle (p, work->options);
190360484Sobrien	      if (tk == tk_pointer)
190460484Sobrien		string_appendn (s, "&", 1);
190560484Sobrien	      /* FIXME: Pointer-to-member constants should get a
190660484Sobrien		 qualifying class name here.  */
190760484Sobrien	      if (q)
190860484Sobrien		{
190960484Sobrien		  string_append (s, q);
191060484Sobrien		  free (q);
191160484Sobrien		}
191260484Sobrien	      else
191360484Sobrien		string_append (s, p);
191460484Sobrien	      free (p);
191560484Sobrien	    }
191660484Sobrien	  *mangled += symbol_len;
191760484Sobrien	}
191860484Sobrien    }
191960484Sobrien
192060484Sobrien  return success;
192160484Sobrien}
192260484Sobrien
192360484Sobrien/* Demangle the template name in MANGLED.  The full name of the
192460484Sobrien   template (e.g., S<int>) is placed in TNAME.  The name without the
192560484Sobrien   template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
192660484Sobrien   non-NULL.  If IS_TYPE is nonzero, this template is a type template,
192760484Sobrien   not a function template.  If both IS_TYPE and REMEMBER are nonzero,
192868765Sobrien   the template is remembered in the list of back-referenceable
192960484Sobrien   types.  */
193060484Sobrien
193160484Sobrienstatic int
1932218822Sdimdemangle_template (struct work_stuff *work, const char **mangled,
1933218822Sdim                   string *tname, string *trawname,
1934218822Sdim                   int is_type, int remember)
193533965Sjdp{
193633965Sjdp  int i;
193733965Sjdp  int r;
193833965Sjdp  int need_comma = 0;
193933965Sjdp  int success = 0;
194038889Sjdp  int is_java_array = 0;
194133965Sjdp  string temp;
194233965Sjdp
194333965Sjdp  (*mangled)++;
194438889Sjdp  if (is_type)
194533965Sjdp    {
194638889Sjdp      /* get template name */
194760484Sobrien      if (**mangled == 'z')
194838889Sjdp	{
194960484Sobrien	  int idx;
195060484Sobrien	  (*mangled)++;
195160484Sobrien	  (*mangled)++;
195260484Sobrien
195360484Sobrien	  idx = consume_count_with_underscores (mangled);
195460484Sobrien	  if (idx == -1
195560484Sobrien	      || (work->tmpl_argvec && idx >= work->ntmpl_args)
195660484Sobrien	      || consume_count_with_underscores (mangled) == -1)
195760484Sobrien	    return (0);
195860484Sobrien
195960484Sobrien	  if (work->tmpl_argvec)
196060484Sobrien	    {
196160484Sobrien	      string_append (tname, work->tmpl_argvec[idx]);
196260484Sobrien	      if (trawname)
196360484Sobrien		string_append (trawname, work->tmpl_argvec[idx]);
196460484Sobrien	    }
196560484Sobrien	  else
196660484Sobrien	    {
196760484Sobrien	      string_append_template_idx (tname, idx);
196860484Sobrien	      if (trawname)
196960484Sobrien		string_append_template_idx (trawname, idx);
197060484Sobrien	    }
197138889Sjdp	}
197260484Sobrien      else
197338889Sjdp	{
197460484Sobrien	  if ((r = consume_count (mangled)) <= 0
197560484Sobrien	      || (int) strlen (*mangled) < r)
197660484Sobrien	    {
197760484Sobrien	      return (0);
197860484Sobrien	    }
197960484Sobrien	  is_java_array = (work -> options & DMGL_JAVA)
198060484Sobrien	    && strncmp (*mangled, "JArray1Z", 8) == 0;
198160484Sobrien	  if (! is_java_array)
198260484Sobrien	    {
198360484Sobrien	      string_appendn (tname, *mangled, r);
198460484Sobrien	    }
198560484Sobrien	  if (trawname)
198660484Sobrien	    string_appendn (trawname, *mangled, r);
198760484Sobrien	  *mangled += r;
198838889Sjdp	}
198933965Sjdp    }
199038889Sjdp  if (!is_java_array)
199138889Sjdp    string_append (tname, "<");
199233965Sjdp  /* get size of template parameter list */
199333965Sjdp  if (!get_count (mangled, &r))
199433965Sjdp    {
199533965Sjdp      return (0);
199633965Sjdp    }
199738889Sjdp  if (!is_type)
199838889Sjdp    {
199938889Sjdp      /* Create an array for saving the template argument values. */
2000218822Sdim      work->tmpl_argvec = XNEWVEC (char *, r);
200138889Sjdp      work->ntmpl_args = r;
200238889Sjdp      for (i = 0; i < r; i++)
200338889Sjdp	work->tmpl_argvec[i] = 0;
200438889Sjdp    }
200533965Sjdp  for (i = 0; i < r; i++)
200633965Sjdp    {
200733965Sjdp      if (need_comma)
200833965Sjdp	{
200933965Sjdp	  string_append (tname, ", ");
201033965Sjdp	}
201133965Sjdp      /* Z for type parameters */
201233965Sjdp      if (**mangled == 'Z')
201333965Sjdp	{
201433965Sjdp	  (*mangled)++;
201533965Sjdp	  /* temp is initialized in do_type */
201633965Sjdp	  success = do_type (work, mangled, &temp);
201733965Sjdp	  if (success)
201833965Sjdp	    {
201933965Sjdp	      string_appends (tname, &temp);
202038889Sjdp
202138889Sjdp	      if (!is_type)
202238889Sjdp		{
202338889Sjdp		  /* Save the template argument. */
202438889Sjdp		  int len = temp.p - temp.b;
2025218822Sdim		  work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
202638889Sjdp		  memcpy (work->tmpl_argvec[i], temp.b, len);
202738889Sjdp		  work->tmpl_argvec[i][len] = '\0';
202838889Sjdp		}
202933965Sjdp	    }
203033965Sjdp	  string_delete(&temp);
203133965Sjdp	  if (!success)
203233965Sjdp	    {
203333965Sjdp	      break;
203433965Sjdp	    }
203533965Sjdp	}
203660484Sobrien      /* z for template parameters */
203760484Sobrien      else if (**mangled == 'z')
203860484Sobrien	{
203960484Sobrien	  int r2;
204060484Sobrien	  (*mangled)++;
204160484Sobrien	  success = demangle_template_template_parm (work, mangled, tname);
204260484Sobrien
204360484Sobrien	  if (success
204460484Sobrien	      && (r2 = consume_count (mangled)) > 0
204560484Sobrien	      && (int) strlen (*mangled) >= r2)
204660484Sobrien	    {
204760484Sobrien	      string_append (tname, " ");
204860484Sobrien	      string_appendn (tname, *mangled, r2);
204960484Sobrien	      if (!is_type)
205060484Sobrien		{
205160484Sobrien		  /* Save the template argument. */
205260484Sobrien		  int len = r2;
2053218822Sdim		  work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
205460484Sobrien		  memcpy (work->tmpl_argvec[i], *mangled, len);
205560484Sobrien		  work->tmpl_argvec[i][len] = '\0';
205660484Sobrien		}
205760484Sobrien	      *mangled += r2;
205860484Sobrien	    }
205960484Sobrien	  if (!success)
206060484Sobrien	    {
206160484Sobrien	      break;
206260484Sobrien	    }
206360484Sobrien	}
206433965Sjdp      else
206533965Sjdp	{
206638889Sjdp	  string  param;
206738889Sjdp	  string* s;
206838889Sjdp
206933965Sjdp	  /* otherwise, value parameter */
207060484Sobrien
207133965Sjdp	  /* temp is initialized in do_type */
207233965Sjdp	  success = do_type (work, mangled, &temp);
207333965Sjdp	  string_delete(&temp);
207433965Sjdp	  if (!success)
207560484Sobrien	    break;
207638889Sjdp
207738889Sjdp	  if (!is_type)
207838889Sjdp	    {
207938889Sjdp	      s = &param;
208038889Sjdp	      string_init (s);
208138889Sjdp	    }
208238889Sjdp	  else
208338889Sjdp	    s = tname;
208438889Sjdp
208560484Sobrien	  success = demangle_template_value_parm (work, mangled, s,
208660484Sobrien						  (type_kind_t) success);
208738889Sjdp
208860484Sobrien	  if (!success)
208938889Sjdp	    {
209060484Sobrien	      if (!is_type)
209160484Sobrien		string_delete (s);
209260484Sobrien	      success = 0;
209360484Sobrien	      break;
209433965Sjdp	    }
209560484Sobrien
209638889Sjdp	  if (!is_type)
209738889Sjdp	    {
209838889Sjdp	      int len = s->p - s->b;
2099218822Sdim	      work->tmpl_argvec[i] = XNEWVEC (char, len + 1);
210038889Sjdp	      memcpy (work->tmpl_argvec[i], s->b, len);
210138889Sjdp	      work->tmpl_argvec[i][len] = '\0';
210260484Sobrien
210338889Sjdp	      string_appends (tname, s);
210438889Sjdp	      string_delete (s);
210538889Sjdp	    }
210633965Sjdp	}
210733965Sjdp      need_comma = 1;
210833965Sjdp    }
210938889Sjdp  if (is_java_array)
211038889Sjdp    {
211138889Sjdp      string_append (tname, "[]");
211238889Sjdp    }
211338889Sjdp  else
211438889Sjdp    {
211538889Sjdp      if (tname->p[-1] == '>')
211638889Sjdp	string_append (tname, " ");
211738889Sjdp      string_append (tname, ">");
211838889Sjdp    }
211960484Sobrien
212060484Sobrien  if (is_type && remember)
2121130561Sobrien    {
2122130561Sobrien      const int bindex = register_Btype (work);
2123130561Sobrien      remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
2124130561Sobrien    }
212560484Sobrien
212633965Sjdp  /*
212733965Sjdp    if (work -> static_type)
212833965Sjdp    {
212933965Sjdp    string_append (declp, *mangled + 1);
213033965Sjdp    *mangled += strlen (*mangled);
213133965Sjdp    success = 1;
213233965Sjdp    }
213333965Sjdp    else
213433965Sjdp    {
213533965Sjdp    success = demangle_args (work, mangled, declp);
213633965Sjdp    }
213733965Sjdp    }
213833965Sjdp    */
213933965Sjdp  return (success);
214033965Sjdp}
214133965Sjdp
214233965Sjdpstatic int
2143218822Sdimarm_pt (struct work_stuff *work, const char *mangled,
2144218822Sdim        int n, const char **anchor, const char **args)
214533965Sjdp{
214660484Sobrien  /* Check if ARM template with "__pt__" in it ("parameterized type") */
214760484Sobrien  /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */
214889857Sobrien  if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__")))
214933965Sjdp    {
215033965Sjdp      int len;
215133965Sjdp      *args = *anchor + 6;
215233965Sjdp      len = consume_count (args);
215360484Sobrien      if (len == -1)
215460484Sobrien	return 0;
215533965Sjdp      if (*args + len == mangled + n && **args == '_')
215633965Sjdp	{
215733965Sjdp	  ++*args;
215833965Sjdp	  return 1;
215933965Sjdp	}
216033965Sjdp    }
216160484Sobrien  if (AUTO_DEMANGLING || EDG_DEMANGLING)
216260484Sobrien    {
216389857Sobrien      if ((*anchor = strstr (mangled, "__tm__"))
216489857Sobrien          || (*anchor = strstr (mangled, "__ps__"))
216589857Sobrien          || (*anchor = strstr (mangled, "__pt__")))
216660484Sobrien        {
216760484Sobrien          int len;
216860484Sobrien          *args = *anchor + 6;
216960484Sobrien          len = consume_count (args);
217060484Sobrien	  if (len == -1)
217160484Sobrien	    return 0;
217260484Sobrien          if (*args + len == mangled + n && **args == '_')
217360484Sobrien            {
217460484Sobrien              ++*args;
217560484Sobrien              return 1;
217660484Sobrien            }
217760484Sobrien        }
217889857Sobrien      else if ((*anchor = strstr (mangled, "__S")))
217960484Sobrien        {
218060484Sobrien 	  int len;
218160484Sobrien 	  *args = *anchor + 3;
218260484Sobrien 	  len = consume_count (args);
218360484Sobrien	  if (len == -1)
218460484Sobrien	    return 0;
218560484Sobrien 	  if (*args + len == mangled + n && **args == '_')
218660484Sobrien            {
218760484Sobrien              ++*args;
218860484Sobrien 	      return 1;
218960484Sobrien            }
219060484Sobrien        }
219160484Sobrien    }
219260484Sobrien
219333965Sjdp  return 0;
219433965Sjdp}
219533965Sjdp
219633965Sjdpstatic void
2197218822Sdimdemangle_arm_hp_template (struct work_stuff *work, const char **mangled,
2198218822Sdim                          int n, string *declp)
219933965Sjdp{
220033965Sjdp  const char *p;
220133965Sjdp  const char *args;
220233965Sjdp  const char *e = *mangled + n;
220360484Sobrien  string arg;
220433965Sjdp
220560484Sobrien  /* Check for HP aCC template spec: classXt1t2 where t1, t2 are
220660484Sobrien     template args */
220760484Sobrien  if (HP_DEMANGLING && ((*mangled)[n] == 'X'))
220833965Sjdp    {
220960484Sobrien      char *start_spec_args = NULL;
2210130561Sobrien      int hold_options;
221160484Sobrien
221260484Sobrien      /* First check for and omit template specialization pseudo-arguments,
221360484Sobrien         such as in "Spec<#1,#1.*>" */
221460484Sobrien      start_spec_args = strchr (*mangled, '<');
221560484Sobrien      if (start_spec_args && (start_spec_args - *mangled < n))
221660484Sobrien        string_appendn (declp, *mangled, start_spec_args - *mangled);
221760484Sobrien      else
221860484Sobrien        string_appendn (declp, *mangled, n);
221960484Sobrien      (*mangled) += n + 1;
222033965Sjdp      string_init (&arg);
222160484Sobrien      if (work->temp_start == -1) /* non-recursive call */
222260484Sobrien        work->temp_start = declp->p - declp->b;
2223130561Sobrien
2224130561Sobrien      /* We want to unconditionally demangle parameter types in
2225130561Sobrien	 template parameters.  */
2226130561Sobrien      hold_options = work->options;
2227130561Sobrien      work->options |= DMGL_PARAMS;
2228130561Sobrien
222960484Sobrien      string_append (declp, "<");
223060484Sobrien      while (1)
223160484Sobrien        {
2232130561Sobrien          string_delete (&arg);
223360484Sobrien          switch (**mangled)
223460484Sobrien            {
223560484Sobrien              case 'T':
223660484Sobrien                /* 'T' signals a type parameter */
223760484Sobrien                (*mangled)++;
223860484Sobrien                if (!do_type (work, mangled, &arg))
223960484Sobrien                  goto hpacc_template_args_done;
224060484Sobrien                break;
224160484Sobrien
224260484Sobrien              case 'U':
224360484Sobrien              case 'S':
224460484Sobrien                /* 'U' or 'S' signals an integral value */
224560484Sobrien                if (!do_hpacc_template_const_value (work, mangled, &arg))
224660484Sobrien                  goto hpacc_template_args_done;
224760484Sobrien                break;
224860484Sobrien
224960484Sobrien              case 'A':
225060484Sobrien                /* 'A' signals a named constant expression (literal) */
225160484Sobrien                if (!do_hpacc_template_literal (work, mangled, &arg))
225260484Sobrien                  goto hpacc_template_args_done;
225360484Sobrien                break;
225460484Sobrien
225560484Sobrien              default:
225660484Sobrien                /* Today, 1997-09-03, we have only the above types
225760484Sobrien                   of template parameters */
225860484Sobrien                /* FIXME: maybe this should fail and return null */
225960484Sobrien                goto hpacc_template_args_done;
226060484Sobrien            }
226160484Sobrien          string_appends (declp, &arg);
226260484Sobrien         /* Check if we're at the end of template args.
226360484Sobrien             0 if at end of static member of template class,
226460484Sobrien             _ if done with template args for a function */
226560484Sobrien          if ((**mangled == '\000') || (**mangled == '_'))
226660484Sobrien            break;
226760484Sobrien          else
226860484Sobrien            string_append (declp, ",");
226960484Sobrien        }
227060484Sobrien    hpacc_template_args_done:
227160484Sobrien      string_append (declp, ">");
227260484Sobrien      string_delete (&arg);
227360484Sobrien      if (**mangled == '_')
227460484Sobrien        (*mangled)++;
2275130561Sobrien      work->options = hold_options;
227660484Sobrien      return;
227760484Sobrien    }
227860484Sobrien  /* ARM template? (Also handles HP cfront extensions) */
227960484Sobrien  else if (arm_pt (work, *mangled, n, &p, &args))
228060484Sobrien    {
2281130561Sobrien      int hold_options;
228260484Sobrien      string type_str;
228360484Sobrien
228460484Sobrien      string_init (&arg);
228533965Sjdp      string_appendn (declp, *mangled, p - *mangled);
228660484Sobrien      if (work->temp_start == -1)  /* non-recursive call */
228760484Sobrien	work->temp_start = declp->p - declp->b;
2288130561Sobrien
2289130561Sobrien      /* We want to unconditionally demangle parameter types in
2290130561Sobrien	 template parameters.  */
2291130561Sobrien      hold_options = work->options;
2292130561Sobrien      work->options |= DMGL_PARAMS;
2293130561Sobrien
229433965Sjdp      string_append (declp, "<");
229533965Sjdp      /* should do error checking here */
229633965Sjdp      while (args < e) {
2297130561Sobrien	string_delete (&arg);
229860484Sobrien
229960484Sobrien	/* Check for type or literal here */
230060484Sobrien	switch (*args)
230160484Sobrien	  {
230260484Sobrien	    /* HP cfront extensions to ARM for template args */
230360484Sobrien	    /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */
230460484Sobrien	    /* FIXME: We handle only numeric literals for HP cfront */
230560484Sobrien          case 'X':
230660484Sobrien            /* A typed constant value follows */
230760484Sobrien            args++;
230860484Sobrien            if (!do_type (work, &args, &type_str))
230960484Sobrien	      goto cfront_template_args_done;
231060484Sobrien            string_append (&arg, "(");
231160484Sobrien            string_appends (&arg, &type_str);
2312130561Sobrien            string_delete (&type_str);
231360484Sobrien            string_append (&arg, ")");
231460484Sobrien            if (*args != 'L')
231560484Sobrien              goto cfront_template_args_done;
231660484Sobrien            args++;
231760484Sobrien            /* Now snarf a literal value following 'L' */
231860484Sobrien            if (!snarf_numeric_literal (&args, &arg))
231960484Sobrien	      goto cfront_template_args_done;
232060484Sobrien            break;
232160484Sobrien
232260484Sobrien          case 'L':
232360484Sobrien            /* Snarf a literal following 'L' */
232460484Sobrien            args++;
232560484Sobrien            if (!snarf_numeric_literal (&args, &arg))
232660484Sobrien	      goto cfront_template_args_done;
232760484Sobrien            break;
232860484Sobrien          default:
232960484Sobrien            /* Not handling other HP cfront stuff */
2330104834Sobrien            {
2331104834Sobrien              const char* old_args = args;
2332104834Sobrien              if (!do_type (work, &args, &arg))
2333104834Sobrien                goto cfront_template_args_done;
2334104834Sobrien
2335104834Sobrien              /* Fail if we didn't make any progress: prevent infinite loop. */
2336104834Sobrien              if (args == old_args)
2337130561Sobrien		{
2338130561Sobrien		  work->options = hold_options;
2339130561Sobrien		  return;
2340130561Sobrien		}
2341104834Sobrien            }
234260484Sobrien	  }
234333965Sjdp	string_appends (declp, &arg);
234433965Sjdp	string_append (declp, ",");
234533965Sjdp      }
234660484Sobrien    cfront_template_args_done:
234733965Sjdp      string_delete (&arg);
234860484Sobrien      if (args >= e)
234960484Sobrien	--declp->p; /* remove extra comma */
235033965Sjdp      string_append (declp, ">");
2351130561Sobrien      work->options = hold_options;
235233965Sjdp    }
235360484Sobrien  else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
235460484Sobrien	   && (*mangled)[9] == 'N'
235560484Sobrien	   && (*mangled)[8] == (*mangled)[10]
235660484Sobrien	   && strchr (cplus_markers, (*mangled)[8]))
235760484Sobrien    {
235860484Sobrien      /* A member of the anonymous namespace.  */
235960484Sobrien      string_append (declp, "{anonymous}");
236060484Sobrien    }
236133965Sjdp  else
236233965Sjdp    {
236360484Sobrien      if (work->temp_start == -1) /* non-recursive call only */
236460484Sobrien	work->temp_start = 0;     /* disable in recursive calls */
236533965Sjdp      string_appendn (declp, *mangled, n);
236633965Sjdp    }
236733965Sjdp  *mangled += n;
236833965Sjdp}
236933965Sjdp
237060484Sobrien/* Extract a class name, possibly a template with arguments, from the
237160484Sobrien   mangled string; qualifiers, local class indicators, etc. have
237260484Sobrien   already been dealt with */
237360484Sobrien
237433965Sjdpstatic int
2375218822Sdimdemangle_class_name (struct work_stuff *work, const char **mangled,
2376218822Sdim                     string *declp)
237733965Sjdp{
237833965Sjdp  int n;
237933965Sjdp  int success = 0;
238033965Sjdp
238133965Sjdp  n = consume_count (mangled);
238260484Sobrien  if (n == -1)
238360484Sobrien    return 0;
238460484Sobrien  if ((int) strlen (*mangled) >= n)
238533965Sjdp    {
238660484Sobrien      demangle_arm_hp_template (work, mangled, n, declp);
238733965Sjdp      success = 1;
238833965Sjdp    }
238933965Sjdp
239033965Sjdp  return (success);
239133965Sjdp}
239233965Sjdp
239333965Sjdp/*
239433965Sjdp
239533965SjdpLOCAL FUNCTION
239633965Sjdp
239733965Sjdp	demangle_class -- demangle a mangled class sequence
239833965Sjdp
239933965SjdpSYNOPSIS
240033965Sjdp
240133965Sjdp	static int
240233965Sjdp	demangle_class (struct work_stuff *work, const char **mangled,
240333965Sjdp			strint *declp)
240433965Sjdp
240533965SjdpDESCRIPTION
240633965Sjdp
240733965Sjdp	DECLP points to the buffer into which demangling is being done.
240833965Sjdp
240933965Sjdp	*MANGLED points to the current token to be demangled.  On input,
241033965Sjdp	it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
241133965Sjdp	On exit, it points to the next token after the mangled class on
241233965Sjdp	success, or the first unconsumed token on failure.
241333965Sjdp
241433965Sjdp	If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
241533965Sjdp	we are demangling a constructor or destructor.  In this case
241633965Sjdp	we prepend "class::class" or "class::~class" to DECLP.
241733965Sjdp
241833965Sjdp	Otherwise, we prepend "class::" to the current DECLP.
241933965Sjdp
242033965Sjdp	Reset the constructor/destructor flags once they have been
242133965Sjdp	"consumed".  This allows demangle_class to be called later during
242233965Sjdp	the same demangling, to do normal class demangling.
242333965Sjdp
242433965Sjdp	Returns 1 if demangling is successful, 0 otherwise.
242533965Sjdp
242633965Sjdp*/
242733965Sjdp
242833965Sjdpstatic int
2429218822Sdimdemangle_class (struct work_stuff *work, const char **mangled, string *declp)
243033965Sjdp{
243133965Sjdp  int success = 0;
243260484Sobrien  int btype;
243333965Sjdp  string class_name;
243460484Sobrien  char *save_class_name_end = 0;
243533965Sjdp
243633965Sjdp  string_init (&class_name);
243760484Sobrien  btype = register_Btype (work);
243833965Sjdp  if (demangle_class_name (work, mangled, &class_name))
243933965Sjdp    {
244060484Sobrien      save_class_name_end = class_name.p;
244133965Sjdp      if ((work->constructor & 1) || (work->destructor & 1))
244233965Sjdp	{
244360484Sobrien          /* adjust so we don't include template args */
244460484Sobrien          if (work->temp_start && (work->temp_start != -1))
244560484Sobrien            {
244660484Sobrien              class_name.p = class_name.b + work->temp_start;
244760484Sobrien            }
244833965Sjdp	  string_prepends (declp, &class_name);
244933965Sjdp	  if (work -> destructor & 1)
245033965Sjdp	    {
245133965Sjdp	      string_prepend (declp, "~");
245233965Sjdp              work -> destructor -= 1;
245333965Sjdp	    }
245433965Sjdp	  else
245533965Sjdp	    {
245660484Sobrien	      work -> constructor -= 1;
245733965Sjdp	    }
245833965Sjdp	}
245960484Sobrien      class_name.p = save_class_name_end;
246060484Sobrien      remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
246160484Sobrien      remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
246260484Sobrien      string_prepend (declp, SCOPE_STRING (work));
246333965Sjdp      string_prepends (declp, &class_name);
246433965Sjdp      success = 1;
246533965Sjdp    }
246633965Sjdp  string_delete (&class_name);
246733965Sjdp  return (success);
246833965Sjdp}
246933965Sjdp
247068765Sobrien
247168765Sobrien/* Called when there's a "__" in the mangled name, with `scan' pointing to
247268765Sobrien   the rightmost guess.
247368765Sobrien
247468765Sobrien   Find the correct "__"-sequence where the function name ends and the
247568765Sobrien   signature starts, which is ambiguous with GNU mangling.
247668765Sobrien   Call demangle_signature here, so we can make sure we found the right
247768765Sobrien   one; *mangled will be consumed so caller will not make further calls to
247868765Sobrien   demangle_signature.  */
247968765Sobrien
248068765Sobrienstatic int
2481218822Sdimiterate_demangle_function (struct work_stuff *work, const char **mangled,
2482218822Sdim                           string *declp, const char *scan)
248368765Sobrien{
248468765Sobrien  const char *mangle_init = *mangled;
248568765Sobrien  int success = 0;
248668765Sobrien  string decl_init;
248768765Sobrien  struct work_stuff work_init;
248868765Sobrien
248968765Sobrien  if (*(scan + 2) == '\0')
249068765Sobrien    return 0;
249168765Sobrien
249268765Sobrien  /* Do not iterate for some demangling modes, or if there's only one
249368765Sobrien     "__"-sequence.  This is the normal case.  */
249468765Sobrien  if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING
249589857Sobrien      || strstr (scan + 2, "__") == NULL)
249668765Sobrien    {
249768765Sobrien      demangle_function_name (work, mangled, declp, scan);
249868765Sobrien      return 1;
249968765Sobrien    }
250068765Sobrien
250168765Sobrien  /* Save state so we can restart if the guess at the correct "__" was
250268765Sobrien     wrong.  */
250368765Sobrien  string_init (&decl_init);
250468765Sobrien  string_appends (&decl_init, declp);
250568765Sobrien  memset (&work_init, 0, sizeof work_init);
250668765Sobrien  work_stuff_copy_to_from (&work_init, work);
250768765Sobrien
250868765Sobrien  /* Iterate over occurrences of __, allowing names and types to have a
250968765Sobrien     "__" sequence in them.  We must start with the first (not the last)
251068765Sobrien     occurrence, since "__" most often occur between independent mangled
251168765Sobrien     parts, hence starting at the last occurence inside a signature
251268765Sobrien     might get us a "successful" demangling of the signature.  */
251368765Sobrien
251468765Sobrien  while (scan[2])
251568765Sobrien    {
251668765Sobrien      demangle_function_name (work, mangled, declp, scan);
251768765Sobrien      success = demangle_signature (work, mangled, declp);
251868765Sobrien      if (success)
251968765Sobrien	break;
252068765Sobrien
252168765Sobrien      /* Reset demangle state for the next round.  */
252268765Sobrien      *mangled = mangle_init;
252368765Sobrien      string_clear (declp);
252468765Sobrien      string_appends (declp, &decl_init);
252568765Sobrien      work_stuff_copy_to_from (work, &work_init);
252668765Sobrien
252768765Sobrien      /* Leave this underscore-sequence.  */
252868765Sobrien      scan += 2;
252968765Sobrien
253068765Sobrien      /* Scan for the next "__" sequence.  */
253168765Sobrien      while (*scan && (scan[0] != '_' || scan[1] != '_'))
253268765Sobrien	scan++;
253368765Sobrien
253468765Sobrien      /* Move to last "__" in this sequence.  */
253568765Sobrien      while (*scan && *scan == '_')
253668765Sobrien	scan++;
253768765Sobrien      scan -= 2;
253868765Sobrien    }
253968765Sobrien
254068765Sobrien  /* Delete saved state.  */
254168765Sobrien  delete_work_stuff (&work_init);
254268765Sobrien  string_delete (&decl_init);
254368765Sobrien
254468765Sobrien  return success;
254568765Sobrien}
254668765Sobrien
254733965Sjdp/*
254833965Sjdp
254933965SjdpLOCAL FUNCTION
255033965Sjdp
255133965Sjdp	demangle_prefix -- consume the mangled name prefix and find signature
255233965Sjdp
255333965SjdpSYNOPSIS
255433965Sjdp
255533965Sjdp	static int
255633965Sjdp	demangle_prefix (struct work_stuff *work, const char **mangled,
255733965Sjdp			 string *declp);
255833965Sjdp
255933965SjdpDESCRIPTION
256033965Sjdp
256133965Sjdp	Consume and demangle the prefix of the mangled name.
256268765Sobrien	While processing the function name root, arrange to call
256368765Sobrien	demangle_signature if the root is ambiguous.
256433965Sjdp
256533965Sjdp	DECLP points to the string buffer into which demangled output is
256633965Sjdp	placed.  On entry, the buffer is empty.  On exit it contains
256733965Sjdp	the root function name, the demangled operator name, or in some
256833965Sjdp	special cases either nothing or the completely demangled result.
256933965Sjdp
257033965Sjdp	MANGLED points to the current pointer into the mangled name.  As each
257133965Sjdp	token of the mangled name is consumed, it is updated.  Upon entry
257233965Sjdp	the current mangled name pointer points to the first character of
257333965Sjdp	the mangled name.  Upon exit, it should point to the first character
257433965Sjdp	of the signature if demangling was successful, or to the first
257533965Sjdp	unconsumed character if demangling of the prefix was unsuccessful.
257660484Sobrien
257733965Sjdp	Returns 1 on success, 0 otherwise.
257833965Sjdp */
257933965Sjdp
258033965Sjdpstatic int
2581218822Sdimdemangle_prefix (struct work_stuff *work, const char **mangled,
2582218822Sdim                 string *declp)
258333965Sjdp{
258433965Sjdp  int success = 1;
258533965Sjdp  const char *scan;
258633965Sjdp  int i;
258733965Sjdp
258860484Sobrien  if (strlen(*mangled) > 6
258960484Sobrien      && (strncmp(*mangled, "_imp__", 6) == 0
259060484Sobrien          || strncmp(*mangled, "__imp_", 6) == 0))
259133965Sjdp    {
259260484Sobrien      /* it's a symbol imported from a PE dynamic library. Check for both
259360484Sobrien         new style prefix _imp__ and legacy __imp_ used by older versions
259460484Sobrien	 of dlltool. */
259560484Sobrien      (*mangled) += 6;
259660484Sobrien      work->dllimported = 1;
259760484Sobrien    }
259860484Sobrien  else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0)
259960484Sobrien    {
260033965Sjdp      char *marker = strchr (cplus_markers, (*mangled)[8]);
260133965Sjdp      if (marker != NULL && *marker == (*mangled)[10])
260233965Sjdp	{
260333965Sjdp	  if ((*mangled)[9] == 'D')
260433965Sjdp	    {
260533965Sjdp	      /* it's a GNU global destructor to be executed at program exit */
260633965Sjdp	      (*mangled) += 11;
260733965Sjdp	      work->destructor = 2;
260833965Sjdp	      if (gnu_special (work, mangled, declp))
260933965Sjdp		return success;
261033965Sjdp	    }
261133965Sjdp	  else if ((*mangled)[9] == 'I')
261233965Sjdp	    {
261333965Sjdp	      /* it's a GNU global constructor to be executed at program init */
261433965Sjdp	      (*mangled) += 11;
261533965Sjdp	      work->constructor = 2;
261633965Sjdp	      if (gnu_special (work, mangled, declp))
261733965Sjdp		return success;
261833965Sjdp	    }
261933965Sjdp	}
262033965Sjdp    }
262160484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0)
262233965Sjdp    {
262333965Sjdp      /* it's a ARM global destructor to be executed at program exit */
262433965Sjdp      (*mangled) += 7;
262533965Sjdp      work->destructor = 2;
262633965Sjdp    }
262760484Sobrien  else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0)
262833965Sjdp    {
262933965Sjdp      /* it's a ARM global constructor to be executed at program initial */
263033965Sjdp      (*mangled) += 7;
263133965Sjdp      work->constructor = 2;
263233965Sjdp    }
263333965Sjdp
263433965Sjdp  /*  This block of code is a reduction in strength time optimization
263533965Sjdp      of:
263689857Sobrien      scan = strstr (*mangled, "__"); */
263733965Sjdp
263833965Sjdp  {
263933965Sjdp    scan = *mangled;
264033965Sjdp
264133965Sjdp    do {
264233965Sjdp      scan = strchr (scan, '_');
264333965Sjdp    } while (scan != NULL && *++scan != '_');
264433965Sjdp
264533965Sjdp    if (scan != NULL) --scan;
264633965Sjdp  }
264733965Sjdp
264833965Sjdp  if (scan != NULL)
264933965Sjdp    {
265033965Sjdp      /* We found a sequence of two or more '_', ensure that we start at
265133965Sjdp	 the last pair in the sequence.  */
265233965Sjdp      i = strspn (scan, "_");
265333965Sjdp      if (i > 2)
265433965Sjdp	{
265560484Sobrien	  scan += (i - 2);
265633965Sjdp	}
265733965Sjdp    }
265860484Sobrien
265933965Sjdp  if (scan == NULL)
266033965Sjdp    {
266133965Sjdp      success = 0;
266233965Sjdp    }
266333965Sjdp  else if (work -> static_type)
266433965Sjdp    {
266577298Sobrien      if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't'))
266633965Sjdp	{
266733965Sjdp	  success = 0;
266833965Sjdp	}
266933965Sjdp    }
267038889Sjdp  else if ((scan == *mangled)
267177298Sobrien	   && (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q')
267260484Sobrien	       || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H')))
267333965Sjdp    {
267433965Sjdp      /* The ARM says nothing about the mangling of local variables.
267533965Sjdp	 But cfront mangles local variables by prepending __<nesting_level>
267633965Sjdp	 to them. As an extension to ARM demangling we handle this case.  */
267760484Sobrien      if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING)
267877298Sobrien	  && ISDIGIT ((unsigned char)scan[2]))
267933965Sjdp	{
268033965Sjdp	  *mangled = scan + 2;
268133965Sjdp	  consume_count (mangled);
268233965Sjdp	  string_append (declp, *mangled);
268333965Sjdp	  *mangled += strlen (*mangled);
268460484Sobrien	  success = 1;
268533965Sjdp	}
268633965Sjdp      else
268733965Sjdp	{
268833965Sjdp	  /* A GNU style constructor starts with __[0-9Qt].  But cfront uses
268933965Sjdp	     names like __Q2_3foo3bar for nested type names.  So don't accept
269038889Sjdp	     this style of constructor for cfront demangling.  A GNU
269138889Sjdp	     style member-template constructor starts with 'H'. */
269260484Sobrien	  if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING))
269333965Sjdp	    work -> constructor += 1;
269433965Sjdp	  *mangled = scan + 2;
269533965Sjdp	}
269633965Sjdp    }
269760484Sobrien  else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
269833965Sjdp    {
269960484Sobrien      /* Cfront-style parameterized type.  Handled later as a signature. */
270060484Sobrien      success = 1;
270160484Sobrien
270260484Sobrien      /* ARM template? */
270360484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
270460484Sobrien    }
270560484Sobrien  else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm')
270660484Sobrien                              || (scan[2] == 'p' && scan[3] == 's')
270760484Sobrien                              || (scan[2] == 'p' && scan[3] == 't')))
270860484Sobrien    {
270960484Sobrien      /* EDG-style parameterized type.  Handled later as a signature. */
271060484Sobrien      success = 1;
271160484Sobrien
271260484Sobrien      /* EDG template? */
271360484Sobrien      demangle_arm_hp_template (work, mangled, strlen (*mangled), declp);
271460484Sobrien    }
271577298Sobrien  else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2])
271660484Sobrien	   && (scan[2] != 't'))
271760484Sobrien    {
271833965Sjdp      /* Mangled name starts with "__".  Skip over any leading '_' characters,
271933965Sjdp	 then find the next "__" that separates the prefix from the signature.
272033965Sjdp	 */
272160484Sobrien      if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
272260484Sobrien	  || (arm_special (mangled, declp) == 0))
272333965Sjdp	{
272433965Sjdp	  while (*scan == '_')
272533965Sjdp	    {
272633965Sjdp	      scan++;
272733965Sjdp	    }
272889857Sobrien	  if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
272933965Sjdp	    {
273033965Sjdp	      /* No separator (I.E. "__not_mangled"), or empty signature
273133965Sjdp		 (I.E. "__not_mangled_either__") */
273233965Sjdp	      success = 0;
273333965Sjdp	    }
273433965Sjdp	  else
273568765Sobrien	    return iterate_demangle_function (work, mangled, declp, scan);
273633965Sjdp	}
273733965Sjdp    }
273833965Sjdp  else if (*(scan + 2) != '\0')
273933965Sjdp    {
274033965Sjdp      /* Mangled name does not start with "__" but does have one somewhere
274133965Sjdp	 in there with non empty stuff after it.  Looks like a global
274268765Sobrien	 function name.  Iterate over all "__":s until the right
274368765Sobrien	 one is found.  */
274468765Sobrien      return iterate_demangle_function (work, mangled, declp, scan);
274533965Sjdp    }
274633965Sjdp  else
274733965Sjdp    {
274833965Sjdp      /* Doesn't look like a mangled name */
274933965Sjdp      success = 0;
275033965Sjdp    }
275133965Sjdp
275233965Sjdp  if (!success && (work->constructor == 2 || work->destructor == 2))
275333965Sjdp    {
275433965Sjdp      string_append (declp, *mangled);
275533965Sjdp      *mangled += strlen (*mangled);
275633965Sjdp      success = 1;
275760484Sobrien    }
275833965Sjdp  return (success);
275933965Sjdp}
276033965Sjdp
276133965Sjdp/*
276233965Sjdp
276333965SjdpLOCAL FUNCTION
276433965Sjdp
276533965Sjdp	gnu_special -- special handling of gnu mangled strings
276633965Sjdp
276733965SjdpSYNOPSIS
276833965Sjdp
276933965Sjdp	static int
277033965Sjdp	gnu_special (struct work_stuff *work, const char **mangled,
277133965Sjdp		     string *declp);
277233965Sjdp
277333965Sjdp
277433965SjdpDESCRIPTION
277533965Sjdp
277633965Sjdp	Process some special GNU style mangling forms that don't fit
277733965Sjdp	the normal pattern.  For example:
277833965Sjdp
277933965Sjdp		_$_3foo		(destructor for class foo)
278033965Sjdp		_vt$foo		(foo virtual table)
278133965Sjdp		_vt$foo$bar	(foo::bar virtual table)
278233965Sjdp		__vt_foo	(foo virtual table, new style with thunks)
278333965Sjdp		_3foo$varname	(static data member)
278433965Sjdp		_Q22rs2tu$vw	(static data member)
278533965Sjdp		__t6vector1Zii	(constructor with template)
278633965Sjdp		__thunk_4__$_7ostream (virtual function thunk)
278733965Sjdp */
278833965Sjdp
278933965Sjdpstatic int
2790218822Sdimgnu_special (struct work_stuff *work, const char **mangled, string *declp)
279133965Sjdp{
279233965Sjdp  int n;
279333965Sjdp  int success = 1;
279433965Sjdp  const char *p;
279533965Sjdp
279633965Sjdp  if ((*mangled)[0] == '_'
279733965Sjdp      && strchr (cplus_markers, (*mangled)[1]) != NULL
279833965Sjdp      && (*mangled)[2] == '_')
279933965Sjdp    {
280033965Sjdp      /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
280133965Sjdp      (*mangled) += 3;
280233965Sjdp      work -> destructor += 1;
280333965Sjdp    }
280433965Sjdp  else if ((*mangled)[0] == '_'
280533965Sjdp	   && (((*mangled)[1] == '_'
280633965Sjdp		&& (*mangled)[2] == 'v'
280733965Sjdp		&& (*mangled)[3] == 't'
280833965Sjdp		&& (*mangled)[4] == '_')
280933965Sjdp	       || ((*mangled)[1] == 'v'
281033965Sjdp		   && (*mangled)[2] == 't'
281133965Sjdp		   && strchr (cplus_markers, (*mangled)[3]) != NULL)))
281233965Sjdp    {
281333965Sjdp      /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
281433965Sjdp         and create the decl.  Note that we consume the entire mangled
281533965Sjdp	 input string, which means that demangle_signature has no work
281633965Sjdp	 to do.  */
281733965Sjdp      if ((*mangled)[2] == 'v')
281833965Sjdp	(*mangled) += 5; /* New style, with thunks: "__vt_" */
281933965Sjdp      else
282033965Sjdp	(*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */
282133965Sjdp      while (**mangled != '\0')
282233965Sjdp	{
282333965Sjdp	  switch (**mangled)
282433965Sjdp	    {
282533965Sjdp	    case 'Q':
282660484Sobrien	    case 'K':
282733965Sjdp	      success = demangle_qualified (work, mangled, declp, 0, 1);
282833965Sjdp	      break;
282933965Sjdp	    case 't':
283060484Sobrien	      success = demangle_template (work, mangled, declp, 0, 1,
283160484Sobrien					   1);
283233965Sjdp	      break;
283333965Sjdp	    default:
283477298Sobrien	      if (ISDIGIT((unsigned char)*mangled[0]))
283533965Sjdp		{
283633965Sjdp		  n = consume_count(mangled);
283738889Sjdp		  /* We may be seeing a too-large size, or else a
283838889Sjdp		     ".<digits>" indicating a static local symbol.  In
283938889Sjdp		     any case, declare victory and move on; *don't* try
284038889Sjdp		     to use n to allocate.  */
284160484Sobrien		  if (n > (int) strlen (*mangled))
284238889Sjdp		    {
284338889Sjdp		      success = 1;
284438889Sjdp		      break;
284538889Sjdp		    }
284633965Sjdp		}
284733965Sjdp	      else
284833965Sjdp		{
284933965Sjdp		  n = strcspn (*mangled, cplus_markers);
285033965Sjdp		}
285133965Sjdp	      string_appendn (declp, *mangled, n);
285233965Sjdp	      (*mangled) += n;
285333965Sjdp	    }
285433965Sjdp
285560484Sobrien	  p = strpbrk (*mangled, cplus_markers);
285633965Sjdp	  if (success && ((p == NULL) || (p == *mangled)))
285733965Sjdp	    {
285833965Sjdp	      if (p != NULL)
285933965Sjdp		{
286060484Sobrien		  string_append (declp, SCOPE_STRING (work));
286133965Sjdp		  (*mangled)++;
286233965Sjdp		}
286333965Sjdp	    }
286433965Sjdp	  else
286533965Sjdp	    {
286633965Sjdp	      success = 0;
286733965Sjdp	      break;
286833965Sjdp	    }
286933965Sjdp	}
287033965Sjdp      if (success)
287133965Sjdp	string_append (declp, " virtual table");
287233965Sjdp    }
287333965Sjdp  else if ((*mangled)[0] == '_'
287433965Sjdp	   && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
287533965Sjdp	   && (p = strpbrk (*mangled, cplus_markers)) != NULL)
287633965Sjdp    {
287733965Sjdp      /* static data member, "_3foo$varname" for example */
287833965Sjdp      (*mangled)++;
287933965Sjdp      switch (**mangled)
288033965Sjdp	{
288133965Sjdp	case 'Q':
288260484Sobrien	case 'K':
288333965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
288433965Sjdp	  break;
288533965Sjdp	case 't':
288660484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
288733965Sjdp	  break;
288833965Sjdp	default:
288933965Sjdp	  n = consume_count (mangled);
289060484Sobrien	  if (n < 0 || n > (long) strlen (*mangled))
289160484Sobrien	    {
289260484Sobrien	      success = 0;
289360484Sobrien	      break;
289460484Sobrien	    }
289568765Sobrien
289668765Sobrien	  if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0
289768765Sobrien	      && (*mangled)[9] == 'N'
289868765Sobrien	      && (*mangled)[8] == (*mangled)[10]
289968765Sobrien	      && strchr (cplus_markers, (*mangled)[8]))
290068765Sobrien	    {
290168765Sobrien	      /* A member of the anonymous namespace.  There's information
290268765Sobrien		 about what identifier or filename it was keyed to, but
290368765Sobrien		 it's just there to make the mangled name unique; we just
290468765Sobrien		 step over it.  */
290568765Sobrien	      string_append (declp, "{anonymous}");
290668765Sobrien	      (*mangled) += n;
290768765Sobrien
290868765Sobrien	      /* Now p points to the marker before the N, so we need to
290968765Sobrien		 update it to the first marker after what we consumed.  */
291068765Sobrien	      p = strpbrk (*mangled, cplus_markers);
291168765Sobrien	      break;
291268765Sobrien	    }
291368765Sobrien
291433965Sjdp	  string_appendn (declp, *mangled, n);
291533965Sjdp	  (*mangled) += n;
291633965Sjdp	}
291733965Sjdp      if (success && (p == *mangled))
291833965Sjdp	{
291933965Sjdp	  /* Consumed everything up to the cplus_marker, append the
292033965Sjdp	     variable name.  */
292133965Sjdp	  (*mangled)++;
292260484Sobrien	  string_append (declp, SCOPE_STRING (work));
292333965Sjdp	  n = strlen (*mangled);
292433965Sjdp	  string_appendn (declp, *mangled, n);
292533965Sjdp	  (*mangled) += n;
292633965Sjdp	}
292733965Sjdp      else
292833965Sjdp	{
292933965Sjdp	  success = 0;
293033965Sjdp	}
293133965Sjdp    }
293233965Sjdp  else if (strncmp (*mangled, "__thunk_", 8) == 0)
293333965Sjdp    {
293460484Sobrien      int delta;
293560484Sobrien
293660484Sobrien      (*mangled) += 8;
293760484Sobrien      delta = consume_count (mangled);
293860484Sobrien      if (delta == -1)
293960484Sobrien	success = 0;
294033965Sjdp      else
294133965Sjdp	{
294260484Sobrien	  char *method = internal_cplus_demangle (work, ++*mangled);
294360484Sobrien
294460484Sobrien	  if (method)
294560484Sobrien	    {
294660484Sobrien	      char buf[50];
294760484Sobrien	      sprintf (buf, "virtual function thunk (delta:%d) for ", -delta);
294860484Sobrien	      string_append (declp, buf);
294960484Sobrien	      string_append (declp, method);
295060484Sobrien	      free (method);
295160484Sobrien	      n = strlen (*mangled);
295260484Sobrien	      (*mangled) += n;
295360484Sobrien	    }
295460484Sobrien	  else
295560484Sobrien	    {
295660484Sobrien	      success = 0;
295760484Sobrien	    }
295833965Sjdp	}
295933965Sjdp    }
296033965Sjdp  else if (strncmp (*mangled, "__t", 3) == 0
296133965Sjdp	   && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
296233965Sjdp    {
296333965Sjdp      p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
296433965Sjdp      (*mangled) += 4;
296533965Sjdp      switch (**mangled)
296633965Sjdp	{
296733965Sjdp	case 'Q':
296860484Sobrien	case 'K':
296933965Sjdp	  success = demangle_qualified (work, mangled, declp, 0, 1);
297033965Sjdp	  break;
297133965Sjdp	case 't':
297260484Sobrien	  success = demangle_template (work, mangled, declp, 0, 1, 1);
297333965Sjdp	  break;
297433965Sjdp	default:
297568765Sobrien	  success = do_type (work, mangled, declp);
297633965Sjdp	  break;
297733965Sjdp	}
297833965Sjdp      if (success && **mangled != '\0')
297933965Sjdp	success = 0;
298033965Sjdp      if (success)
298133965Sjdp	string_append (declp, p);
298233965Sjdp    }
298333965Sjdp  else
298433965Sjdp    {
298533965Sjdp      success = 0;
298633965Sjdp    }
298733965Sjdp  return (success);
298833965Sjdp}
298933965Sjdp
299060484Sobrienstatic void
2991218822Sdimrecursively_demangle(struct work_stuff *work, const char **mangled,
2992218822Sdim                     string *result, int namelength)
299360484Sobrien{
299460484Sobrien  char * recurse = (char *)NULL;
299560484Sobrien  char * recurse_dem = (char *)NULL;
299660484Sobrien
2997218822Sdim  recurse = XNEWVEC (char, namelength + 1);
299860484Sobrien  memcpy (recurse, *mangled, namelength);
299960484Sobrien  recurse[namelength] = '\000';
300060484Sobrien
300160484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
300260484Sobrien
300360484Sobrien  if (recurse_dem)
300460484Sobrien    {
300560484Sobrien      string_append (result, recurse_dem);
300660484Sobrien      free (recurse_dem);
300760484Sobrien    }
300860484Sobrien  else
300960484Sobrien    {
301060484Sobrien      string_appendn (result, *mangled, namelength);
301160484Sobrien    }
301260484Sobrien  free (recurse);
301360484Sobrien  *mangled += namelength;
301460484Sobrien}
301560484Sobrien
301633965Sjdp/*
301733965Sjdp
301833965SjdpLOCAL FUNCTION
301933965Sjdp
302033965Sjdp	arm_special -- special handling of ARM/lucid mangled strings
302133965Sjdp
302233965SjdpSYNOPSIS
302333965Sjdp
302433965Sjdp	static int
302560484Sobrien	arm_special (const char **mangled,
302660484Sobrien		     string *declp);
302733965Sjdp
302833965Sjdp
302933965SjdpDESCRIPTION
303033965Sjdp
303133965Sjdp	Process some special ARM style mangling forms that don't fit
303233965Sjdp	the normal pattern.  For example:
303333965Sjdp
303433965Sjdp		__vtbl__3foo		(foo virtual table)
303533965Sjdp		__vtbl__3foo__3bar	(bar::foo virtual table)
303633965Sjdp
303733965Sjdp */
303833965Sjdp
303933965Sjdpstatic int
3040218822Sdimarm_special (const char **mangled, string *declp)
304133965Sjdp{
304233965Sjdp  int n;
304333965Sjdp  int success = 1;
304433965Sjdp  const char *scan;
304533965Sjdp
304633965Sjdp  if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
304733965Sjdp    {
304833965Sjdp      /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
304933965Sjdp         and create the decl.  Note that we consume the entire mangled
305033965Sjdp	 input string, which means that demangle_signature has no work
305133965Sjdp	 to do.  */
305233965Sjdp      scan = *mangled + ARM_VTABLE_STRLEN;
305333965Sjdp      while (*scan != '\0')        /* first check it can be demangled */
305433965Sjdp        {
305533965Sjdp          n = consume_count (&scan);
305660484Sobrien          if (n == -1)
305733965Sjdp	    {
305833965Sjdp	      return (0);           /* no good */
305933965Sjdp	    }
306033965Sjdp          scan += n;
306133965Sjdp          if (scan[0] == '_' && scan[1] == '_')
306233965Sjdp	    {
306333965Sjdp	      scan += 2;
306433965Sjdp	    }
306533965Sjdp        }
306633965Sjdp      (*mangled) += ARM_VTABLE_STRLEN;
306733965Sjdp      while (**mangled != '\0')
306833965Sjdp	{
306933965Sjdp	  n = consume_count (mangled);
307060484Sobrien          if (n == -1
307160484Sobrien	      || n > (long) strlen (*mangled))
307260484Sobrien	    return 0;
307333965Sjdp	  string_prependn (declp, *mangled, n);
307433965Sjdp	  (*mangled) += n;
307533965Sjdp	  if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
307633965Sjdp	    {
307733965Sjdp	      string_prepend (declp, "::");
307833965Sjdp	      (*mangled) += 2;
307933965Sjdp	    }
308033965Sjdp	}
308133965Sjdp      string_append (declp, " virtual table");
308233965Sjdp    }
308333965Sjdp  else
308433965Sjdp    {
308533965Sjdp      success = 0;
308633965Sjdp    }
308733965Sjdp  return (success);
308833965Sjdp}
308933965Sjdp
309033965Sjdp/*
309133965Sjdp
309233965SjdpLOCAL FUNCTION
309333965Sjdp
309433965Sjdp	demangle_qualified -- demangle 'Q' qualified name strings
309533965Sjdp
309633965SjdpSYNOPSIS
309733965Sjdp
309833965Sjdp	static int
309933965Sjdp	demangle_qualified (struct work_stuff *, const char *mangled,
310033965Sjdp			    string *result, int isfuncname, int append);
310133965Sjdp
310233965SjdpDESCRIPTION
310333965Sjdp
310433965Sjdp	Demangle a qualified name, such as "Q25Outer5Inner" which is
310533965Sjdp	the mangled form of "Outer::Inner".  The demangled output is
310633965Sjdp	prepended or appended to the result string according to the
310733965Sjdp	state of the append flag.
310833965Sjdp
310933965Sjdp	If isfuncname is nonzero, then the qualified name we are building
311033965Sjdp	is going to be used as a member function name, so if it is a
311133965Sjdp	constructor or destructor function, append an appropriate
311233965Sjdp	constructor or destructor name.  I.E. for the above example,
311333965Sjdp	the result for use as a constructor is "Outer::Inner::Inner"
311433965Sjdp	and the result for use as a destructor is "Outer::Inner::~Inner".
311533965Sjdp
311633965SjdpBUGS
311733965Sjdp
311833965Sjdp	Numeric conversion is ASCII dependent (FIXME).
311933965Sjdp
312033965Sjdp */
312133965Sjdp
312233965Sjdpstatic int
3123218822Sdimdemangle_qualified (struct work_stuff *work, const char **mangled,
3124218822Sdim                    string *result, int isfuncname, int append)
312533965Sjdp{
312660484Sobrien  int qualifiers = 0;
312733965Sjdp  int success = 1;
312833965Sjdp  char num[2];
312933965Sjdp  string temp;
313060484Sobrien  string last_name;
313160484Sobrien  int bindex = register_Btype (work);
313233965Sjdp
313360484Sobrien  /* We only make use of ISFUNCNAME if the entity is a constructor or
313460484Sobrien     destructor.  */
313560484Sobrien  isfuncname = (isfuncname
313660484Sobrien		&& ((work->constructor & 1) || (work->destructor & 1)));
313760484Sobrien
313833965Sjdp  string_init (&temp);
313960484Sobrien  string_init (&last_name);
314060484Sobrien
314160484Sobrien  if ((*mangled)[0] == 'K')
314233965Sjdp    {
314360484Sobrien    /* Squangling qualified name reuse */
314460484Sobrien      int idx;
314560484Sobrien      (*mangled)++;
314660484Sobrien      idx = consume_count_with_underscores (mangled);
314760484Sobrien      if (idx == -1 || idx >= work -> numk)
314860484Sobrien        success = 0;
314960484Sobrien      else
315060484Sobrien        string_append (&temp, work -> ktypevec[idx]);
315160484Sobrien    }
315260484Sobrien  else
315360484Sobrien    switch ((*mangled)[1])
315460484Sobrien    {
315533965Sjdp    case '_':
315633965Sjdp      /* GNU mangled name with more than 9 classes.  The count is preceded
315733965Sjdp	 by an underscore (to distinguish it from the <= 9 case) and followed
315833965Sjdp	 by an underscore.  */
315960484Sobrien      (*mangled)++;
316060484Sobrien      qualifiers = consume_count_with_underscores (mangled);
316160484Sobrien      if (qualifiers == -1)
316233965Sjdp	success = 0;
316333965Sjdp      break;
316433965Sjdp
316533965Sjdp    case '1':
316633965Sjdp    case '2':
316733965Sjdp    case '3':
316833965Sjdp    case '4':
316933965Sjdp    case '5':
317033965Sjdp    case '6':
317133965Sjdp    case '7':
317233965Sjdp    case '8':
317333965Sjdp    case '9':
317433965Sjdp      /* The count is in a single digit.  */
317533965Sjdp      num[0] = (*mangled)[1];
317633965Sjdp      num[1] = '\0';
317733965Sjdp      qualifiers = atoi (num);
317833965Sjdp
317933965Sjdp      /* If there is an underscore after the digit, skip it.  This is
318033965Sjdp	 said to be for ARM-qualified names, but the ARM makes no
318133965Sjdp	 mention of such an underscore.  Perhaps cfront uses one.  */
318233965Sjdp      if ((*mangled)[2] == '_')
318333965Sjdp	{
318433965Sjdp	  (*mangled)++;
318533965Sjdp	}
318633965Sjdp      (*mangled) += 2;
318733965Sjdp      break;
318833965Sjdp
318933965Sjdp    case '0':
319033965Sjdp    default:
319133965Sjdp      success = 0;
319233965Sjdp    }
319333965Sjdp
319433965Sjdp  if (!success)
319533965Sjdp    return success;
319633965Sjdp
319733965Sjdp  /* Pick off the names and collect them in the temp buffer in the order
319833965Sjdp     in which they are found, separated by '::'.  */
319933965Sjdp
320033965Sjdp  while (qualifiers-- > 0)
320133965Sjdp    {
320260484Sobrien      int remember_K = 1;
320360484Sobrien      string_clear (&last_name);
320460484Sobrien
320560484Sobrien      if (*mangled[0] == '_')
320660484Sobrien	(*mangled)++;
320760484Sobrien
320833965Sjdp      if (*mangled[0] == 't')
320933965Sjdp	{
321060484Sobrien	  /* Here we always append to TEMP since we will want to use
321160484Sobrien	     the template name without the template parameters as a
321260484Sobrien	     constructor or destructor name.  The appropriate
321360484Sobrien	     (parameter-less) value is returned by demangle_template
321460484Sobrien	     in LAST_NAME.  We do not remember the template type here,
321560484Sobrien	     in order to match the G++ mangling algorithm.  */
321660484Sobrien	  success = demangle_template(work, mangled, &temp,
321760484Sobrien				      &last_name, 1, 0);
321860484Sobrien	  if (!success)
321960484Sobrien	    break;
322033965Sjdp	}
322160484Sobrien      else if (*mangled[0] == 'K')
322238889Sjdp	{
322360484Sobrien          int idx;
322460484Sobrien          (*mangled)++;
322560484Sobrien          idx = consume_count_with_underscores (mangled);
322660484Sobrien          if (idx == -1 || idx >= work->numk)
322760484Sobrien            success = 0;
322860484Sobrien          else
322960484Sobrien            string_append (&temp, work->ktypevec[idx]);
323060484Sobrien          remember_K = 0;
323160484Sobrien
323238889Sjdp	  if (!success) break;
323338889Sjdp	}
323433965Sjdp      else
323560484Sobrien	{
323660484Sobrien	  if (EDG_DEMANGLING)
323760484Sobrien            {
323860484Sobrien	      int namelength;
323960484Sobrien 	      /* Now recursively demangle the qualifier
324060484Sobrien 	       * This is necessary to deal with templates in
324160484Sobrien 	       * mangling styles like EDG */
324260484Sobrien	      namelength = consume_count (mangled);
324360484Sobrien	      if (namelength == -1)
324460484Sobrien		{
324560484Sobrien		  success = 0;
324660484Sobrien		  break;
324760484Sobrien		}
324860484Sobrien 	      recursively_demangle(work, mangled, &temp, namelength);
324960484Sobrien            }
325060484Sobrien          else
325160484Sobrien            {
3252130561Sobrien              string_delete (&last_name);
325360484Sobrien              success = do_type (work, mangled, &last_name);
325460484Sobrien              if (!success)
325560484Sobrien                break;
325660484Sobrien              string_appends (&temp, &last_name);
325760484Sobrien            }
325833965Sjdp	}
325960484Sobrien
326060484Sobrien      if (remember_K)
326160484Sobrien	remember_Ktype (work, temp.b, LEN_STRING (&temp));
326260484Sobrien
326333965Sjdp      if (qualifiers > 0)
326460484Sobrien	string_append (&temp, SCOPE_STRING (work));
326533965Sjdp    }
326633965Sjdp
326760484Sobrien  remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
326860484Sobrien
326933965Sjdp  /* If we are using the result as a function name, we need to append
327033965Sjdp     the appropriate '::' separated constructor or destructor name.
327133965Sjdp     We do this here because this is the most convenient place, where
327233965Sjdp     we already have a pointer to the name and the length of the name.  */
327333965Sjdp
327460484Sobrien  if (isfuncname)
327533965Sjdp    {
327660484Sobrien      string_append (&temp, SCOPE_STRING (work));
327733965Sjdp      if (work -> destructor & 1)
327860484Sobrien	string_append (&temp, "~");
327960484Sobrien      string_appends (&temp, &last_name);
328033965Sjdp    }
328133965Sjdp
328260484Sobrien  /* Now either prepend the temp buffer to the result, or append it,
328333965Sjdp     depending upon the state of the append flag.  */
328433965Sjdp
328533965Sjdp  if (append)
328660484Sobrien    string_appends (result, &temp);
328733965Sjdp  else
328833965Sjdp    {
328933965Sjdp      if (!STRING_EMPTY (result))
329060484Sobrien	string_append (&temp, SCOPE_STRING (work));
329133965Sjdp      string_prepends (result, &temp);
329233965Sjdp    }
329333965Sjdp
329460484Sobrien  string_delete (&last_name);
329533965Sjdp  string_delete (&temp);
329633965Sjdp  return (success);
329733965Sjdp}
329833965Sjdp
329933965Sjdp/*
330033965Sjdp
330133965SjdpLOCAL FUNCTION
330233965Sjdp
330333965Sjdp	get_count -- convert an ascii count to integer, consuming tokens
330433965Sjdp
330533965SjdpSYNOPSIS
330633965Sjdp
330733965Sjdp	static int
330833965Sjdp	get_count (const char **type, int *count)
330933965Sjdp
331033965SjdpDESCRIPTION
331133965Sjdp
331260484Sobrien	Assume that *type points at a count in a mangled name; set
331360484Sobrien	*count to its value, and set *type to the next character after
331460484Sobrien	the count.  There are some weird rules in effect here.
331560484Sobrien
331660484Sobrien	If *type does not point at a string of digits, return zero.
331760484Sobrien
331860484Sobrien	If *type points at a string of digits followed by an
331960484Sobrien	underscore, set *count to their value as an integer, advance
332060484Sobrien	*type to point *after the underscore, and return 1.
332160484Sobrien
332260484Sobrien	If *type points at a string of digits not followed by an
332360484Sobrien	underscore, consume only the first digit.  Set *count to its
332460484Sobrien	value as an integer, leave *type pointing after that digit,
332560484Sobrien	and return 1.
332660484Sobrien
332760484Sobrien        The excuse for this odd behavior: in the ARM and HP demangling
332860484Sobrien        styles, a type can be followed by a repeat count of the form
332960484Sobrien        `Nxy', where:
333060484Sobrien
333160484Sobrien        `x' is a single digit specifying how many additional copies
333260484Sobrien            of the type to append to the argument list, and
333360484Sobrien
333460484Sobrien        `y' is one or more digits, specifying the zero-based index of
333560484Sobrien            the first repeated argument in the list.  Yes, as you're
333660484Sobrien            unmangling the name you can figure this out yourself, but
333760484Sobrien            it's there anyway.
333860484Sobrien
333960484Sobrien        So, for example, in `bar__3fooFPiN51', the first argument is a
334060484Sobrien        pointer to an integer (`Pi'), and then the next five arguments
334160484Sobrien        are the same (`N5'), and the first repeat is the function's
334260484Sobrien        second argument (`1').
334333965Sjdp*/
334433965Sjdp
334533965Sjdpstatic int
3346218822Sdimget_count (const char **type, int *count)
334733965Sjdp{
334833965Sjdp  const char *p;
334933965Sjdp  int n;
335033965Sjdp
335177298Sobrien  if (!ISDIGIT ((unsigned char)**type))
335260484Sobrien    return (0);
335333965Sjdp  else
335433965Sjdp    {
335533965Sjdp      *count = **type - '0';
335633965Sjdp      (*type)++;
335777298Sobrien      if (ISDIGIT ((unsigned char)**type))
335833965Sjdp	{
335933965Sjdp	  p = *type;
336033965Sjdp	  n = *count;
336160484Sobrien	  do
336233965Sjdp	    {
336333965Sjdp	      n *= 10;
336433965Sjdp	      n += *p - '0';
336533965Sjdp	      p++;
336660484Sobrien	    }
336777298Sobrien	  while (ISDIGIT ((unsigned char)*p));
336833965Sjdp	  if (*p == '_')
336933965Sjdp	    {
337033965Sjdp	      *type = p + 1;
337133965Sjdp	      *count = n;
337233965Sjdp	    }
337333965Sjdp	}
337433965Sjdp    }
337533965Sjdp  return (1);
337633965Sjdp}
337733965Sjdp
337860484Sobrien/* RESULT will be initialised here; it will be freed on failure.  The
337960484Sobrien   value returned is really a type_kind_t.  */
338033965Sjdp
338133965Sjdpstatic int
3382218822Sdimdo_type (struct work_stuff *work, const char **mangled, string *result)
338333965Sjdp{
338433965Sjdp  int n;
338533965Sjdp  int done;
338633965Sjdp  int success;
338733965Sjdp  string decl;
338833965Sjdp  const char *remembered_type;
338960484Sobrien  int type_quals;
339060484Sobrien  type_kind_t tk = tk_none;
339133965Sjdp
339233965Sjdp  string_init (&decl);
339333965Sjdp  string_init (result);
339433965Sjdp
339533965Sjdp  done = 0;
339633965Sjdp  success = 1;
339733965Sjdp  while (success && !done)
339833965Sjdp    {
339933965Sjdp      int member;
340033965Sjdp      switch (**mangled)
340133965Sjdp	{
340233965Sjdp
340333965Sjdp	  /* A pointer type */
340433965Sjdp	case 'P':
340533965Sjdp	case 'p':
340633965Sjdp	  (*mangled)++;
340738889Sjdp	  if (! (work -> options & DMGL_JAVA))
340838889Sjdp	    string_prepend (&decl, "*");
340960484Sobrien	  if (tk == tk_none)
341060484Sobrien	    tk = tk_pointer;
341133965Sjdp	  break;
341233965Sjdp
341333965Sjdp	  /* A reference type */
341433965Sjdp	case 'R':
341533965Sjdp	  (*mangled)++;
341633965Sjdp	  string_prepend (&decl, "&");
341760484Sobrien	  if (tk == tk_none)
341860484Sobrien	    tk = tk_reference;
341933965Sjdp	  break;
342033965Sjdp
342133965Sjdp	  /* An array */
342233965Sjdp	case 'A':
342333965Sjdp	  {
342460484Sobrien	    ++(*mangled);
342560484Sobrien	    if (!STRING_EMPTY (&decl)
342660484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
342733965Sjdp	      {
342860484Sobrien		string_prepend (&decl, "(");
342960484Sobrien		string_append (&decl, ")");
343033965Sjdp	      }
343160484Sobrien	    string_append (&decl, "[");
343260484Sobrien	    if (**mangled != '_')
343360484Sobrien	      success = demangle_template_value_parm (work, mangled, &decl,
343460484Sobrien						      tk_integral);
343560484Sobrien	    if (**mangled == '_')
343660484Sobrien	      ++(*mangled);
343760484Sobrien	    string_append (&decl, "]");
343833965Sjdp	    break;
343933965Sjdp	  }
344033965Sjdp
344133965Sjdp	/* A back reference to a previously seen type */
344233965Sjdp	case 'T':
344333965Sjdp	  (*mangled)++;
344433965Sjdp	  if (!get_count (mangled, &n) || n >= work -> ntypes)
344533965Sjdp	    {
344633965Sjdp	      success = 0;
344733965Sjdp	    }
344833965Sjdp	  else
344933965Sjdp	    {
345033965Sjdp	      remembered_type = work -> typevec[n];
345133965Sjdp	      mangled = &remembered_type;
345233965Sjdp	    }
345333965Sjdp	  break;
345433965Sjdp
345533965Sjdp	  /* A function */
345633965Sjdp	case 'F':
345733965Sjdp	  (*mangled)++;
345860484Sobrien	    if (!STRING_EMPTY (&decl)
345960484Sobrien		&& (decl.b[0] == '*' || decl.b[0] == '&'))
346033965Sjdp	    {
346133965Sjdp	      string_prepend (&decl, "(");
346233965Sjdp	      string_append (&decl, ")");
346333965Sjdp	    }
346433965Sjdp	  /* After picking off the function args, we expect to either find the
346533965Sjdp	     function return type (preceded by an '_') or the end of the
346633965Sjdp	     string.  */
346760484Sobrien	  if (!demangle_nested_args (work, mangled, &decl)
346833965Sjdp	      || (**mangled != '_' && **mangled != '\0'))
346933965Sjdp	    {
347033965Sjdp	      success = 0;
347160484Sobrien	      break;
347233965Sjdp	    }
347333965Sjdp	  if (success && (**mangled == '_'))
347460484Sobrien	    (*mangled)++;
347533965Sjdp	  break;
347633965Sjdp
347733965Sjdp	case 'M':
347833965Sjdp	case 'O':
347933965Sjdp	  {
348060484Sobrien	    type_quals = TYPE_UNQUALIFIED;
348133965Sjdp
348233965Sjdp	    member = **mangled == 'M';
348333965Sjdp	    (*mangled)++;
348433965Sjdp
348533965Sjdp	    string_append (&decl, ")");
348660484Sobrien
348760484Sobrien	    /* We don't need to prepend `::' for a qualified name;
348860484Sobrien	       demangle_qualified will do that for us.  */
348960484Sobrien	    if (**mangled != 'Q')
349060484Sobrien	      string_prepend (&decl, SCOPE_STRING (work));
349160484Sobrien
349277298Sobrien	    if (ISDIGIT ((unsigned char)**mangled))
349333965Sjdp	      {
349433965Sjdp		n = consume_count (mangled);
349560484Sobrien		if (n == -1
349660484Sobrien		    || (int) strlen (*mangled) < n)
349733965Sjdp		  {
349833965Sjdp		    success = 0;
349933965Sjdp		    break;
350033965Sjdp		  }
350133965Sjdp		string_prependn (&decl, *mangled, n);
350233965Sjdp		*mangled += n;
350333965Sjdp	      }
350460484Sobrien	    else if (**mangled == 'X' || **mangled == 'Y')
350533965Sjdp	      {
350633965Sjdp		string temp;
350760484Sobrien		do_type (work, mangled, &temp);
350860484Sobrien		string_prepends (&decl, &temp);
3509130561Sobrien		string_delete (&temp);
351060484Sobrien	      }
351160484Sobrien	    else if (**mangled == 't')
351260484Sobrien	      {
351360484Sobrien		string temp;
351433965Sjdp		string_init (&temp);
351560484Sobrien		success = demangle_template (work, mangled, &temp,
351660484Sobrien					     NULL, 1, 1);
351733965Sjdp		if (success)
351833965Sjdp		  {
351933965Sjdp		    string_prependn (&decl, temp.b, temp.p - temp.b);
3520130561Sobrien		    string_delete (&temp);
352133965Sjdp		  }
352233965Sjdp		else
352333965Sjdp		  break;
352433965Sjdp	      }
352560484Sobrien	    else if (**mangled == 'Q')
352660484Sobrien	      {
352760484Sobrien		success = demangle_qualified (work, mangled, &decl,
352860484Sobrien					      /*isfuncnam=*/0,
352960484Sobrien					      /*append=*/0);
353060484Sobrien		if (!success)
353160484Sobrien		  break;
353260484Sobrien	      }
353360484Sobrien	    else
353460484Sobrien	      {
353560484Sobrien		success = 0;
353660484Sobrien		break;
353760484Sobrien	      }
353860484Sobrien
353933965Sjdp	    string_prepend (&decl, "(");
354033965Sjdp	    if (member)
354133965Sjdp	      {
354260484Sobrien		switch (**mangled)
354333965Sjdp		  {
354460484Sobrien		  case 'C':
354560484Sobrien		  case 'V':
354660484Sobrien		  case 'u':
354760484Sobrien		    type_quals |= code_for_qualifier (**mangled);
354833965Sjdp		    (*mangled)++;
354960484Sobrien		    break;
355060484Sobrien
355160484Sobrien		  default:
355260484Sobrien		    break;
355333965Sjdp		  }
355460484Sobrien
355533965Sjdp		if (*(*mangled)++ != 'F')
355633965Sjdp		  {
355733965Sjdp		    success = 0;
355833965Sjdp		    break;
355933965Sjdp		  }
356033965Sjdp	      }
356160484Sobrien	    if ((member && !demangle_nested_args (work, mangled, &decl))
356233965Sjdp		|| **mangled != '_')
356333965Sjdp	      {
356433965Sjdp		success = 0;
356533965Sjdp		break;
356633965Sjdp	      }
356733965Sjdp	    (*mangled)++;
356833965Sjdp	    if (! PRINT_ANSI_QUALIFIERS)
356933965Sjdp	      {
357033965Sjdp		break;
357133965Sjdp	      }
357260484Sobrien	    if (type_quals != TYPE_UNQUALIFIED)
357333965Sjdp	      {
357433965Sjdp		APPEND_BLANK (&decl);
357560484Sobrien		string_append (&decl, qualifier_string (type_quals));
357633965Sjdp	      }
357733965Sjdp	    break;
357833965Sjdp	  }
357933965Sjdp        case 'G':
358033965Sjdp	  (*mangled)++;
358133965Sjdp	  break;
358233965Sjdp
358333965Sjdp	case 'C':
358460484Sobrien	case 'V':
358560484Sobrien	case 'u':
358633965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
358733965Sjdp	    {
358833965Sjdp	      if (!STRING_EMPTY (&decl))
358960484Sobrien		string_prepend (&decl, " ");
359060484Sobrien
359160484Sobrien	      string_prepend (&decl, demangle_qualifier (**mangled));
359233965Sjdp	    }
359360484Sobrien	  (*mangled)++;
359433965Sjdp	  break;
359533965Sjdp	  /*
359633965Sjdp	    }
359733965Sjdp	    */
359833965Sjdp
359933965Sjdp	  /* fall through */
360033965Sjdp	default:
360133965Sjdp	  done = 1;
360233965Sjdp	  break;
360333965Sjdp	}
360433965Sjdp    }
360533965Sjdp
360660484Sobrien  if (success) switch (**mangled)
360733965Sjdp    {
360833965Sjdp      /* A qualified name, such as "Outer::Inner".  */
360933965Sjdp    case 'Q':
361060484Sobrien    case 'K':
361160484Sobrien      {
361260484Sobrien        success = demangle_qualified (work, mangled, result, 0, 1);
361360484Sobrien        break;
361460484Sobrien      }
361560484Sobrien
361660484Sobrien    /* A back reference to a previously seen squangled type */
361760484Sobrien    case 'B':
361860484Sobrien      (*mangled)++;
361960484Sobrien      if (!get_count (mangled, &n) || n >= work -> numb)
362060484Sobrien	success = 0;
362160484Sobrien      else
362260484Sobrien	string_append (result, work->btypevec[n]);
362333965Sjdp      break;
362433965Sjdp
362538889Sjdp    case 'X':
362638889Sjdp    case 'Y':
362738889Sjdp      /* A template parm.  We substitute the corresponding argument. */
362838889Sjdp      {
362938889Sjdp	int idx;
363038889Sjdp
363138889Sjdp	(*mangled)++;
363238889Sjdp	idx = consume_count_with_underscores (mangled);
363338889Sjdp
363460484Sobrien	if (idx == -1
363538889Sjdp	    || (work->tmpl_argvec && idx >= work->ntmpl_args)
363638889Sjdp	    || consume_count_with_underscores (mangled) == -1)
363738889Sjdp	  {
363838889Sjdp	    success = 0;
363938889Sjdp	    break;
364038889Sjdp	  }
364138889Sjdp
364238889Sjdp	if (work->tmpl_argvec)
364338889Sjdp	  string_append (result, work->tmpl_argvec[idx]);
364438889Sjdp	else
364560484Sobrien	  string_append_template_idx (result, idx);
364638889Sjdp
364738889Sjdp	success = 1;
364838889Sjdp      }
364938889Sjdp    break;
365038889Sjdp
365133965Sjdp    default:
365233965Sjdp      success = demangle_fund_type (work, mangled, result);
365360484Sobrien      if (tk == tk_none)
365460484Sobrien	tk = (type_kind_t) success;
365533965Sjdp      break;
365633965Sjdp    }
365733965Sjdp
365833965Sjdp  if (success)
365933965Sjdp    {
366033965Sjdp      if (!STRING_EMPTY (&decl))
366133965Sjdp	{
366233965Sjdp	  string_append (result, " ");
366333965Sjdp	  string_appends (result, &decl);
366433965Sjdp	}
366533965Sjdp    }
366633965Sjdp  else
366760484Sobrien    string_delete (result);
366833965Sjdp  string_delete (&decl);
366960484Sobrien
367060484Sobrien  if (success)
367160484Sobrien    /* Assume an integral type, if we're not sure.  */
367260484Sobrien    return (int) ((tk == tk_none) ? tk_integral : tk);
367360484Sobrien  else
367460484Sobrien    return 0;
367533965Sjdp}
367633965Sjdp
367733965Sjdp/* Given a pointer to a type string that represents a fundamental type
367833965Sjdp   argument (int, long, unsigned int, etc) in TYPE, a pointer to the
367933965Sjdp   string in which the demangled output is being built in RESULT, and
368033965Sjdp   the WORK structure, decode the types and add them to the result.
368133965Sjdp
368233965Sjdp   For example:
368333965Sjdp
368433965Sjdp   	"Ci"	=>	"const int"
368533965Sjdp	"Sl"	=>	"signed long"
368633965Sjdp	"CUs"	=>	"const unsigned short"
368733965Sjdp
368860484Sobrien   The value returned is really a type_kind_t.  */
368933965Sjdp
369033965Sjdpstatic int
3691218822Sdimdemangle_fund_type (struct work_stuff *work,
3692218822Sdim                    const char **mangled, string *result)
369333965Sjdp{
369433965Sjdp  int done = 0;
369533965Sjdp  int success = 1;
3696218822Sdim  char buf[INTBUF_SIZE + 5 /* 'int%u_t' */];
369768765Sobrien  unsigned int dec = 0;
369860484Sobrien  type_kind_t tk = tk_integral;
369933965Sjdp
370033965Sjdp  /* First pick off any type qualifiers.  There can be more than one.  */
370133965Sjdp
370233965Sjdp  while (!done)
370333965Sjdp    {
370433965Sjdp      switch (**mangled)
370533965Sjdp	{
370633965Sjdp	case 'C':
370760484Sobrien	case 'V':
370860484Sobrien	case 'u':
370933965Sjdp	  if (PRINT_ANSI_QUALIFIERS)
371033965Sjdp	    {
371160484Sobrien              if (!STRING_EMPTY (result))
371260484Sobrien                string_prepend (result, " ");
371360484Sobrien	      string_prepend (result, demangle_qualifier (**mangled));
371433965Sjdp	    }
371560484Sobrien	  (*mangled)++;
371633965Sjdp	  break;
371733965Sjdp	case 'U':
371833965Sjdp	  (*mangled)++;
371933965Sjdp	  APPEND_BLANK (result);
372033965Sjdp	  string_append (result, "unsigned");
372133965Sjdp	  break;
372233965Sjdp	case 'S': /* signed char only */
372333965Sjdp	  (*mangled)++;
372433965Sjdp	  APPEND_BLANK (result);
372533965Sjdp	  string_append (result, "signed");
372633965Sjdp	  break;
372738889Sjdp	case 'J':
372838889Sjdp	  (*mangled)++;
372938889Sjdp	  APPEND_BLANK (result);
373038889Sjdp	  string_append (result, "__complex");
373138889Sjdp	  break;
373233965Sjdp	default:
373333965Sjdp	  done = 1;
373433965Sjdp	  break;
373533965Sjdp	}
373633965Sjdp    }
373733965Sjdp
373833965Sjdp  /* Now pick off the fundamental type.  There can be only one.  */
373933965Sjdp
374033965Sjdp  switch (**mangled)
374133965Sjdp    {
374233965Sjdp    case '\0':
374333965Sjdp    case '_':
374433965Sjdp      break;
374533965Sjdp    case 'v':
374633965Sjdp      (*mangled)++;
374733965Sjdp      APPEND_BLANK (result);
374833965Sjdp      string_append (result, "void");
374933965Sjdp      break;
375033965Sjdp    case 'x':
375133965Sjdp      (*mangled)++;
375233965Sjdp      APPEND_BLANK (result);
375333965Sjdp      string_append (result, "long long");
375433965Sjdp      break;
375533965Sjdp    case 'l':
375633965Sjdp      (*mangled)++;
375733965Sjdp      APPEND_BLANK (result);
375833965Sjdp      string_append (result, "long");
375933965Sjdp      break;
376033965Sjdp    case 'i':
376133965Sjdp      (*mangled)++;
376233965Sjdp      APPEND_BLANK (result);
376333965Sjdp      string_append (result, "int");
376433965Sjdp      break;
376533965Sjdp    case 's':
376633965Sjdp      (*mangled)++;
376733965Sjdp      APPEND_BLANK (result);
376833965Sjdp      string_append (result, "short");
376933965Sjdp      break;
377033965Sjdp    case 'b':
377133965Sjdp      (*mangled)++;
377233965Sjdp      APPEND_BLANK (result);
377333965Sjdp      string_append (result, "bool");
377460484Sobrien      tk = tk_bool;
377533965Sjdp      break;
377633965Sjdp    case 'c':
377733965Sjdp      (*mangled)++;
377833965Sjdp      APPEND_BLANK (result);
377933965Sjdp      string_append (result, "char");
378060484Sobrien      tk = tk_char;
378133965Sjdp      break;
378233965Sjdp    case 'w':
378333965Sjdp      (*mangled)++;
378433965Sjdp      APPEND_BLANK (result);
378533965Sjdp      string_append (result, "wchar_t");
378660484Sobrien      tk = tk_char;
378733965Sjdp      break;
378833965Sjdp    case 'r':
378933965Sjdp      (*mangled)++;
379033965Sjdp      APPEND_BLANK (result);
379133965Sjdp      string_append (result, "long double");
379260484Sobrien      tk = tk_real;
379333965Sjdp      break;
379433965Sjdp    case 'd':
379533965Sjdp      (*mangled)++;
379633965Sjdp      APPEND_BLANK (result);
379733965Sjdp      string_append (result, "double");
379860484Sobrien      tk = tk_real;
379933965Sjdp      break;
380033965Sjdp    case 'f':
380133965Sjdp      (*mangled)++;
380233965Sjdp      APPEND_BLANK (result);
380333965Sjdp      string_append (result, "float");
380460484Sobrien      tk = tk_real;
380533965Sjdp      break;
380633965Sjdp    case 'G':
380733965Sjdp      (*mangled)++;
380877298Sobrien      if (!ISDIGIT ((unsigned char)**mangled))
380933965Sjdp	{
381033965Sjdp	  success = 0;
381133965Sjdp	  break;
381233965Sjdp	}
381360484Sobrien    case 'I':
381460484Sobrien      (*mangled)++;
381560484Sobrien      if (**mangled == '_')
381660484Sobrien	{
381760484Sobrien	  int i;
381860484Sobrien	  (*mangled)++;
381960484Sobrien	  for (i = 0;
382060484Sobrien	       i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_';
382160484Sobrien	       (*mangled)++, i++)
382260484Sobrien	    buf[i] = **mangled;
382360484Sobrien	  if (**mangled != '_')
382460484Sobrien	    {
382560484Sobrien	      success = 0;
382660484Sobrien	      break;
382760484Sobrien	    }
382860484Sobrien	  buf[i] = '\0';
382960484Sobrien	  (*mangled)++;
383060484Sobrien	}
383160484Sobrien      else
383260484Sobrien	{
383360484Sobrien	  strncpy (buf, *mangled, 2);
383460484Sobrien	  buf[2] = '\0';
383560484Sobrien	  *mangled += min (strlen (*mangled), 2);
383660484Sobrien	}
383760484Sobrien      sscanf (buf, "%x", &dec);
383868765Sobrien      sprintf (buf, "int%u_t", dec);
383960484Sobrien      APPEND_BLANK (result);
384060484Sobrien      string_append (result, buf);
384160484Sobrien      break;
384260484Sobrien
384333965Sjdp      /* fall through */
384433965Sjdp      /* An explicit type, such as "6mytype" or "7integer" */
384533965Sjdp    case '0':
384633965Sjdp    case '1':
384733965Sjdp    case '2':
384833965Sjdp    case '3':
384933965Sjdp    case '4':
385033965Sjdp    case '5':
385133965Sjdp    case '6':
385233965Sjdp    case '7':
385333965Sjdp    case '8':
385433965Sjdp    case '9':
385560484Sobrien      {
385660484Sobrien        int bindex = register_Btype (work);
385760484Sobrien        string btype;
385860484Sobrien        string_init (&btype);
385960484Sobrien        if (demangle_class_name (work, mangled, &btype)) {
386060484Sobrien          remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
386160484Sobrien          APPEND_BLANK (result);
386260484Sobrien          string_appends (result, &btype);
386360484Sobrien        }
386460484Sobrien        else
386560484Sobrien          success = 0;
386660484Sobrien        string_delete (&btype);
386760484Sobrien        break;
386833965Sjdp      }
386933965Sjdp    case 't':
387060484Sobrien      {
3871130561Sobrien        string btype;
3872130561Sobrien        string_init (&btype);
387360484Sobrien        success = demangle_template (work, mangled, &btype, 0, 1, 1);
387460484Sobrien        string_appends (result, &btype);
3875130561Sobrien        string_delete (&btype);
387660484Sobrien        break;
387760484Sobrien      }
387833965Sjdp    default:
387933965Sjdp      success = 0;
388033965Sjdp      break;
388133965Sjdp    }
388233965Sjdp
388360484Sobrien  return success ? ((int) tk) : 0;
388433965Sjdp}
388533965Sjdp
388633965Sjdp
388760484Sobrien/* Handle a template's value parameter for HP aCC (extension from ARM)
388860484Sobrien   **mangled points to 'S' or 'U' */
388960484Sobrien
389033965Sjdpstatic int
3891218822Sdimdo_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED,
3892218822Sdim                               const char **mangled, string *result)
389360484Sobrien{
389460484Sobrien  int unsigned_const;
389560484Sobrien
389660484Sobrien  if (**mangled != 'U' && **mangled != 'S')
389760484Sobrien    return 0;
389860484Sobrien
389960484Sobrien  unsigned_const = (**mangled == 'U');
390060484Sobrien
390160484Sobrien  (*mangled)++;
390260484Sobrien
390360484Sobrien  switch (**mangled)
390460484Sobrien    {
390560484Sobrien      case 'N':
390660484Sobrien        string_append (result, "-");
390760484Sobrien        /* fall through */
390860484Sobrien      case 'P':
390960484Sobrien        (*mangled)++;
391060484Sobrien        break;
391160484Sobrien      case 'M':
391260484Sobrien        /* special case for -2^31 */
391360484Sobrien        string_append (result, "-2147483648");
391460484Sobrien        (*mangled)++;
391560484Sobrien        return 1;
391660484Sobrien      default:
391760484Sobrien        return 0;
391860484Sobrien    }
391960484Sobrien
392060484Sobrien  /* We have to be looking at an integer now */
392177298Sobrien  if (!(ISDIGIT ((unsigned char)**mangled)))
392260484Sobrien    return 0;
392360484Sobrien
392460484Sobrien  /* We only deal with integral values for template
392560484Sobrien     parameters -- so it's OK to look only for digits */
392677298Sobrien  while (ISDIGIT ((unsigned char)**mangled))
392760484Sobrien    {
392860484Sobrien      char_str[0] = **mangled;
392960484Sobrien      string_append (result, char_str);
393060484Sobrien      (*mangled)++;
393160484Sobrien    }
393260484Sobrien
393360484Sobrien  if (unsigned_const)
393460484Sobrien    string_append (result, "U");
393560484Sobrien
393660484Sobrien  /* FIXME? Some day we may have 64-bit (or larger :-) ) constants
393760484Sobrien     with L or LL suffixes. pai/1997-09-03 */
393860484Sobrien
393960484Sobrien  return 1; /* success */
394060484Sobrien}
394160484Sobrien
394260484Sobrien/* Handle a template's literal parameter for HP aCC (extension from ARM)
394360484Sobrien   **mangled is pointing to the 'A' */
394460484Sobrien
394560484Sobrienstatic int
3946218822Sdimdo_hpacc_template_literal (struct work_stuff *work, const char **mangled,
3947218822Sdim                           string *result)
394860484Sobrien{
394960484Sobrien  int literal_len = 0;
395060484Sobrien  char * recurse;
395160484Sobrien  char * recurse_dem;
395260484Sobrien
395360484Sobrien  if (**mangled != 'A')
395460484Sobrien    return 0;
395560484Sobrien
395660484Sobrien  (*mangled)++;
395760484Sobrien
395860484Sobrien  literal_len = consume_count (mangled);
395960484Sobrien
396060484Sobrien  if (literal_len <= 0)
396160484Sobrien    return 0;
396260484Sobrien
396360484Sobrien  /* Literal parameters are names of arrays, functions, etc.  and the
396460484Sobrien     canonical representation uses the address operator */
396560484Sobrien  string_append (result, "&");
396660484Sobrien
396760484Sobrien  /* Now recursively demangle the literal name */
3968218822Sdim  recurse = XNEWVEC (char, literal_len + 1);
396960484Sobrien  memcpy (recurse, *mangled, literal_len);
397060484Sobrien  recurse[literal_len] = '\000';
397160484Sobrien
397260484Sobrien  recurse_dem = cplus_demangle (recurse, work->options);
397360484Sobrien
397460484Sobrien  if (recurse_dem)
397560484Sobrien    {
397660484Sobrien      string_append (result, recurse_dem);
397760484Sobrien      free (recurse_dem);
397860484Sobrien    }
397960484Sobrien  else
398060484Sobrien    {
398160484Sobrien      string_appendn (result, *mangled, literal_len);
398260484Sobrien    }
398360484Sobrien  (*mangled) += literal_len;
398460484Sobrien  free (recurse);
398560484Sobrien
398660484Sobrien  return 1;
398760484Sobrien}
398860484Sobrien
398960484Sobrienstatic int
3990218822Sdimsnarf_numeric_literal (const char **args, string *arg)
399160484Sobrien{
399260484Sobrien  if (**args == '-')
399360484Sobrien    {
399460484Sobrien      char_str[0] = '-';
399560484Sobrien      string_append (arg, char_str);
399660484Sobrien      (*args)++;
399760484Sobrien    }
399860484Sobrien  else if (**args == '+')
399960484Sobrien    (*args)++;
400060484Sobrien
400177298Sobrien  if (!ISDIGIT ((unsigned char)**args))
400260484Sobrien    return 0;
400360484Sobrien
400477298Sobrien  while (ISDIGIT ((unsigned char)**args))
400560484Sobrien    {
400660484Sobrien      char_str[0] = **args;
400760484Sobrien      string_append (arg, char_str);
400860484Sobrien      (*args)++;
400960484Sobrien    }
401060484Sobrien
401160484Sobrien  return 1;
401260484Sobrien}
401360484Sobrien
401460484Sobrien/* Demangle the next argument, given by MANGLED into RESULT, which
401560484Sobrien   *should be an uninitialized* string.  It will be initialized here,
401660484Sobrien   and free'd should anything go wrong.  */
401760484Sobrien
401860484Sobrienstatic int
4019218822Sdimdo_arg (struct work_stuff *work, const char **mangled, string *result)
402033965Sjdp{
402160484Sobrien  /* Remember where we started so that we can record the type, for
402260484Sobrien     non-squangling type remembering.  */
402333965Sjdp  const char *start = *mangled;
402433965Sjdp
402560484Sobrien  string_init (result);
402660484Sobrien
402760484Sobrien  if (work->nrepeats > 0)
402833965Sjdp    {
402960484Sobrien      --work->nrepeats;
403060484Sobrien
403160484Sobrien      if (work->previous_argument == 0)
403260484Sobrien	return 0;
403360484Sobrien
403460484Sobrien      /* We want to reissue the previous type in this argument list.  */
403560484Sobrien      string_appends (result, work->previous_argument);
403660484Sobrien      return 1;
403733965Sjdp    }
403860484Sobrien
403960484Sobrien  if (**mangled == 'n')
404060484Sobrien    {
404160484Sobrien      /* A squangling-style repeat.  */
404260484Sobrien      (*mangled)++;
404360484Sobrien      work->nrepeats = consume_count(mangled);
404460484Sobrien
404560484Sobrien      if (work->nrepeats <= 0)
404660484Sobrien	/* This was not a repeat count after all.  */
404760484Sobrien	return 0;
404860484Sobrien
404960484Sobrien      if (work->nrepeats > 9)
405060484Sobrien	{
405160484Sobrien	  if (**mangled != '_')
405260484Sobrien	    /* The repeat count should be followed by an '_' in this
405360484Sobrien	       case.  */
405460484Sobrien	    return 0;
405560484Sobrien	  else
405660484Sobrien	    (*mangled)++;
405760484Sobrien	}
405860484Sobrien
405960484Sobrien      /* Now, the repeat is all set up.  */
406060484Sobrien      return do_arg (work, mangled, result);
406160484Sobrien    }
406260484Sobrien
406360484Sobrien  /* Save the result in WORK->previous_argument so that we can find it
406460484Sobrien     if it's repeated.  Note that saving START is not good enough: we
406560484Sobrien     do not want to add additional types to the back-referenceable
406660484Sobrien     type vector when processing a repeated type.  */
406760484Sobrien  if (work->previous_argument)
4068130561Sobrien    string_delete (work->previous_argument);
406933965Sjdp  else
4070218822Sdim    work->previous_argument = XNEW (string);
407160484Sobrien
407260484Sobrien  if (!do_type (work, mangled, work->previous_argument))
407360484Sobrien    return 0;
407460484Sobrien
407560484Sobrien  string_appends (result, work->previous_argument);
407660484Sobrien
407760484Sobrien  remember_type (work, start, *mangled - start);
407860484Sobrien  return 1;
407933965Sjdp}
408033965Sjdp
408133965Sjdpstatic void
4082218822Sdimremember_type (struct work_stuff *work, const char *start, int len)
408333965Sjdp{
408433965Sjdp  char *tem;
408533965Sjdp
408660484Sobrien  if (work->forgetting_types)
408760484Sobrien    return;
408860484Sobrien
408933965Sjdp  if (work -> ntypes >= work -> typevec_size)
409033965Sjdp    {
409133965Sjdp      if (work -> typevec_size == 0)
409233965Sjdp	{
409333965Sjdp	  work -> typevec_size = 3;
4094218822Sdim	  work -> typevec = XNEWVEC (char *, work->typevec_size);
409533965Sjdp	}
409633965Sjdp      else
409733965Sjdp	{
409833965Sjdp	  work -> typevec_size *= 2;
409938889Sjdp	  work -> typevec
4100218822Sdim	    = XRESIZEVEC (char *, work->typevec, work->typevec_size);
410133965Sjdp	}
410233965Sjdp    }
4103218822Sdim  tem = XNEWVEC (char, len + 1);
410433965Sjdp  memcpy (tem, start, len);
410533965Sjdp  tem[len] = '\0';
410633965Sjdp  work -> typevec[work -> ntypes++] = tem;
410733965Sjdp}
410833965Sjdp
410960484Sobrien
411060484Sobrien/* Remember a K type class qualifier. */
411160484Sobrienstatic void
4112218822Sdimremember_Ktype (struct work_stuff *work, const char *start, int len)
411360484Sobrien{
411460484Sobrien  char *tem;
411560484Sobrien
411660484Sobrien  if (work -> numk >= work -> ksize)
411760484Sobrien    {
411860484Sobrien      if (work -> ksize == 0)
411960484Sobrien	{
412060484Sobrien	  work -> ksize = 5;
4121218822Sdim	  work -> ktypevec = XNEWVEC (char *, work->ksize);
412260484Sobrien	}
412360484Sobrien      else
412460484Sobrien	{
412560484Sobrien	  work -> ksize *= 2;
412660484Sobrien	  work -> ktypevec
4127218822Sdim	    = XRESIZEVEC (char *, work->ktypevec, work->ksize);
412860484Sobrien	}
412960484Sobrien    }
4130218822Sdim  tem = XNEWVEC (char, len + 1);
413160484Sobrien  memcpy (tem, start, len);
413260484Sobrien  tem[len] = '\0';
413360484Sobrien  work -> ktypevec[work -> numk++] = tem;
413460484Sobrien}
413560484Sobrien
413660484Sobrien/* Register a B code, and get an index for it. B codes are registered
413760484Sobrien   as they are seen, rather than as they are completed, so map<temp<char> >
413860484Sobrien   registers map<temp<char> > as B0, and temp<char> as B1 */
413960484Sobrien
414060484Sobrienstatic int
4141218822Sdimregister_Btype (struct work_stuff *work)
414260484Sobrien{
414360484Sobrien  int ret;
414460484Sobrien
414560484Sobrien  if (work -> numb >= work -> bsize)
414660484Sobrien    {
414760484Sobrien      if (work -> bsize == 0)
414860484Sobrien	{
414960484Sobrien	  work -> bsize = 5;
4150218822Sdim	  work -> btypevec = XNEWVEC (char *, work->bsize);
415160484Sobrien	}
415260484Sobrien      else
415360484Sobrien	{
415460484Sobrien	  work -> bsize *= 2;
415560484Sobrien	  work -> btypevec
4156218822Sdim	    = XRESIZEVEC (char *, work->btypevec, work->bsize);
415760484Sobrien	}
415860484Sobrien    }
415960484Sobrien  ret = work -> numb++;
416060484Sobrien  work -> btypevec[ret] = NULL;
416160484Sobrien  return(ret);
416260484Sobrien}
416360484Sobrien
416460484Sobrien/* Store a value into a previously registered B code type. */
416560484Sobrien
416660484Sobrienstatic void
4167218822Sdimremember_Btype (struct work_stuff *work, const char *start,
4168218822Sdim                int len, int index)
416960484Sobrien{
417060484Sobrien  char *tem;
417160484Sobrien
4172218822Sdim  tem = XNEWVEC (char, len + 1);
417360484Sobrien  memcpy (tem, start, len);
417460484Sobrien  tem[len] = '\0';
417560484Sobrien  work -> btypevec[index] = tem;
417660484Sobrien}
417760484Sobrien
417860484Sobrien/* Lose all the info related to B and K type codes. */
417960484Sobrienstatic void
4180218822Sdimforget_B_and_K_types (struct work_stuff *work)
418160484Sobrien{
418260484Sobrien  int i;
418360484Sobrien
418460484Sobrien  while (work -> numk > 0)
418560484Sobrien    {
418660484Sobrien      i = --(work -> numk);
418760484Sobrien      if (work -> ktypevec[i] != NULL)
418860484Sobrien	{
418960484Sobrien	  free (work -> ktypevec[i]);
419060484Sobrien	  work -> ktypevec[i] = NULL;
419160484Sobrien	}
419260484Sobrien    }
419360484Sobrien
419460484Sobrien  while (work -> numb > 0)
419560484Sobrien    {
419660484Sobrien      i = --(work -> numb);
419760484Sobrien      if (work -> btypevec[i] != NULL)
419860484Sobrien	{
419960484Sobrien	  free (work -> btypevec[i]);
420060484Sobrien	  work -> btypevec[i] = NULL;
420160484Sobrien	}
420260484Sobrien    }
420360484Sobrien}
420433965Sjdp/* Forget the remembered types, but not the type vector itself.  */
420533965Sjdp
420633965Sjdpstatic void
4207218822Sdimforget_types (struct work_stuff *work)
420833965Sjdp{
420933965Sjdp  int i;
421033965Sjdp
421133965Sjdp  while (work -> ntypes > 0)
421233965Sjdp    {
421333965Sjdp      i = --(work -> ntypes);
421433965Sjdp      if (work -> typevec[i] != NULL)
421533965Sjdp	{
421633965Sjdp	  free (work -> typevec[i]);
421733965Sjdp	  work -> typevec[i] = NULL;
421833965Sjdp	}
421933965Sjdp    }
422033965Sjdp}
422133965Sjdp
422233965Sjdp/* Process the argument list part of the signature, after any class spec
422333965Sjdp   has been consumed, as well as the first 'F' character (if any).  For
422433965Sjdp   example:
422533965Sjdp
422633965Sjdp   "__als__3fooRT0"		=>	process "RT0"
422733965Sjdp   "complexfunc5__FPFPc_PFl_i"	=>	process "PFPc_PFl_i"
422833965Sjdp
422933965Sjdp   DECLP must be already initialised, usually non-empty.  It won't be freed
423033965Sjdp   on failure.
423133965Sjdp
423233965Sjdp   Note that g++ differs significantly from ARM and lucid style mangling
423333965Sjdp   with regards to references to previously seen types.  For example, given
423433965Sjdp   the source fragment:
423533965Sjdp
423633965Sjdp     class foo {
423733965Sjdp       public:
423833965Sjdp       foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
423933965Sjdp     };
424033965Sjdp
424133965Sjdp     foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
424233965Sjdp     void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
424333965Sjdp
424433965Sjdp   g++ produces the names:
424533965Sjdp
424633965Sjdp     __3fooiRT0iT2iT2
424733965Sjdp     foo__FiR3fooiT1iT1
424833965Sjdp
424933965Sjdp   while lcc (and presumably other ARM style compilers as well) produces:
425033965Sjdp
425133965Sjdp     foo__FiR3fooT1T2T1T2
425233965Sjdp     __ct__3fooFiR3fooT1T2T1T2
425333965Sjdp
425460484Sobrien   Note that g++ bases its type numbers starting at zero and counts all
425560484Sobrien   previously seen types, while lucid/ARM bases its type numbers starting
425633965Sjdp   at one and only considers types after it has seen the 'F' character
425733965Sjdp   indicating the start of the function args.  For lucid/ARM style, we
425833965Sjdp   account for this difference by discarding any previously seen types when
425933965Sjdp   we see the 'F' character, and subtracting one from the type number
426033965Sjdp   reference.
426133965Sjdp
426233965Sjdp */
426333965Sjdp
426433965Sjdpstatic int
4265218822Sdimdemangle_args (struct work_stuff *work, const char **mangled,
4266218822Sdim               string *declp)
426733965Sjdp{
426833965Sjdp  string arg;
426933965Sjdp  int need_comma = 0;
427033965Sjdp  int r;
427133965Sjdp  int t;
427233965Sjdp  const char *tem;
427333965Sjdp  char temptype;
427433965Sjdp
427533965Sjdp  if (PRINT_ARG_TYPES)
427633965Sjdp    {
427733965Sjdp      string_append (declp, "(");
427833965Sjdp      if (**mangled == '\0')
427933965Sjdp	{
428033965Sjdp	  string_append (declp, "void");
428133965Sjdp	}
428233965Sjdp    }
428333965Sjdp
428460484Sobrien  while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
428560484Sobrien	 || work->nrepeats > 0)
428633965Sjdp    {
428733965Sjdp      if ((**mangled == 'N') || (**mangled == 'T'))
428833965Sjdp	{
428933965Sjdp	  temptype = *(*mangled)++;
429060484Sobrien
429133965Sjdp	  if (temptype == 'N')
429233965Sjdp	    {
429333965Sjdp	      if (!get_count (mangled, &r))
429433965Sjdp		{
429533965Sjdp		  return (0);
429633965Sjdp		}
429733965Sjdp	    }
429833965Sjdp	  else
429933965Sjdp	    {
430033965Sjdp	      r = 1;
430133965Sjdp	    }
430260484Sobrien          if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10)
430333965Sjdp            {
430433965Sjdp              /* If we have 10 or more types we might have more than a 1 digit
430533965Sjdp                 index so we'll have to consume the whole count here. This
430633965Sjdp                 will lose if the next thing is a type name preceded by a
430733965Sjdp                 count but it's impossible to demangle that case properly
430833965Sjdp                 anyway. Eg if we already have 12 types is T12Pc "(..., type1,
430933965Sjdp                 Pc, ...)"  or "(..., type12, char *, ...)" */
431060484Sobrien              if ((t = consume_count(mangled)) <= 0)
431133965Sjdp                {
431233965Sjdp                  return (0);
431333965Sjdp                }
431433965Sjdp            }
431533965Sjdp          else
431633965Sjdp	    {
431733965Sjdp	      if (!get_count (mangled, &t))
431833965Sjdp	    	{
431933965Sjdp	          return (0);
432033965Sjdp	    	}
432133965Sjdp	    }
432260484Sobrien	  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
432333965Sjdp	    {
432433965Sjdp	      t--;
432533965Sjdp	    }
432633965Sjdp	  /* Validate the type index.  Protect against illegal indices from
432733965Sjdp	     malformed type strings.  */
432833965Sjdp	  if ((t < 0) || (t >= work -> ntypes))
432933965Sjdp	    {
433033965Sjdp	      return (0);
433133965Sjdp	    }
433260484Sobrien	  while (work->nrepeats > 0 || --r >= 0)
433333965Sjdp	    {
433433965Sjdp	      tem = work -> typevec[t];
433533965Sjdp	      if (need_comma && PRINT_ARG_TYPES)
433633965Sjdp		{
433733965Sjdp		  string_append (declp, ", ");
433833965Sjdp		}
433933965Sjdp	      if (!do_arg (work, &tem, &arg))
434033965Sjdp		{
434133965Sjdp		  return (0);
434233965Sjdp		}
434333965Sjdp	      if (PRINT_ARG_TYPES)
434433965Sjdp		{
434533965Sjdp		  string_appends (declp, &arg);
434633965Sjdp		}
434733965Sjdp	      string_delete (&arg);
434833965Sjdp	      need_comma = 1;
434933965Sjdp	    }
435033965Sjdp	}
435133965Sjdp      else
435233965Sjdp	{
435360484Sobrien	  if (need_comma && PRINT_ARG_TYPES)
435460484Sobrien	    string_append (declp, ", ");
435533965Sjdp	  if (!do_arg (work, mangled, &arg))
435660484Sobrien	    return (0);
435733965Sjdp	  if (PRINT_ARG_TYPES)
435860484Sobrien	    string_appends (declp, &arg);
435933965Sjdp	  string_delete (&arg);
436033965Sjdp	  need_comma = 1;
436133965Sjdp	}
436233965Sjdp    }
436333965Sjdp
436433965Sjdp  if (**mangled == 'e')
436533965Sjdp    {
436633965Sjdp      (*mangled)++;
436733965Sjdp      if (PRINT_ARG_TYPES)
436833965Sjdp	{
436933965Sjdp	  if (need_comma)
437033965Sjdp	    {
437133965Sjdp	      string_append (declp, ",");
437233965Sjdp	    }
437333965Sjdp	  string_append (declp, "...");
437433965Sjdp	}
437533965Sjdp    }
437633965Sjdp
437733965Sjdp  if (PRINT_ARG_TYPES)
437833965Sjdp    {
437933965Sjdp      string_append (declp, ")");
438033965Sjdp    }
438133965Sjdp  return (1);
438233965Sjdp}
438333965Sjdp
438460484Sobrien/* Like demangle_args, but for demangling the argument lists of function
438560484Sobrien   and method pointers or references, not top-level declarations.  */
438660484Sobrien
438760484Sobrienstatic int
4388218822Sdimdemangle_nested_args (struct work_stuff *work, const char **mangled,
4389218822Sdim                      string *declp)
439060484Sobrien{
439160484Sobrien  string* saved_previous_argument;
439260484Sobrien  int result;
439360484Sobrien  int saved_nrepeats;
439460484Sobrien
439560484Sobrien  /* The G++ name-mangling algorithm does not remember types on nested
439660484Sobrien     argument lists, unless -fsquangling is used, and in that case the
439760484Sobrien     type vector updated by remember_type is not used.  So, we turn
439860484Sobrien     off remembering of types here.  */
439960484Sobrien  ++work->forgetting_types;
440060484Sobrien
440160484Sobrien  /* For the repeat codes used with -fsquangling, we must keep track of
440260484Sobrien     the last argument.  */
440360484Sobrien  saved_previous_argument = work->previous_argument;
440460484Sobrien  saved_nrepeats = work->nrepeats;
440560484Sobrien  work->previous_argument = 0;
440660484Sobrien  work->nrepeats = 0;
440760484Sobrien
440860484Sobrien  /* Actually demangle the arguments.  */
440960484Sobrien  result = demangle_args (work, mangled, declp);
441060484Sobrien
441160484Sobrien  /* Restore the previous_argument field.  */
441260484Sobrien  if (work->previous_argument)
4413130561Sobrien    {
4414130561Sobrien      string_delete (work->previous_argument);
4415130561Sobrien      free ((char *) work->previous_argument);
4416130561Sobrien    }
441760484Sobrien  work->previous_argument = saved_previous_argument;
441860484Sobrien  --work->forgetting_types;
441960484Sobrien  work->nrepeats = saved_nrepeats;
442060484Sobrien
442160484Sobrien  return result;
442260484Sobrien}
442360484Sobrien
442433965Sjdpstatic void
4425218822Sdimdemangle_function_name (struct work_stuff *work, const char **mangled,
4426218822Sdim                        string *declp, const char *scan)
442733965Sjdp{
442860484Sobrien  size_t i;
442933965Sjdp  string type;
443033965Sjdp  const char *tem;
443133965Sjdp
443233965Sjdp  string_appendn (declp, (*mangled), scan - (*mangled));
443333965Sjdp  string_need (declp, 1);
443433965Sjdp  *(declp -> p) = '\0';
443533965Sjdp
443633965Sjdp  /* Consume the function name, including the "__" separating the name
443733965Sjdp     from the signature.  We are guaranteed that SCAN points to the
443833965Sjdp     separator.  */
443933965Sjdp
444033965Sjdp  (*mangled) = scan + 2;
444160484Sobrien  /* We may be looking at an instantiation of a template function:
444260484Sobrien     foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a
444360484Sobrien     following _F marks the start of the function arguments.  Handle
444460484Sobrien     the template arguments first. */
444533965Sjdp
444660484Sobrien  if (HP_DEMANGLING && (**mangled == 'X'))
444733965Sjdp    {
444860484Sobrien      demangle_arm_hp_template (work, mangled, 0, declp);
444960484Sobrien      /* This leaves MANGLED pointing to the 'F' marking func args */
445060484Sobrien    }
445133965Sjdp
445260484Sobrien  if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)
445360484Sobrien    {
445460484Sobrien
445533965Sjdp      /* See if we have an ARM style constructor or destructor operator.
445633965Sjdp	 If so, then just record it, clear the decl, and return.
445733965Sjdp	 We can't build the actual constructor/destructor decl until later,
445833965Sjdp	 when we recover the class name from the signature.  */
445933965Sjdp
446033965Sjdp      if (strcmp (declp -> b, "__ct") == 0)
446133965Sjdp	{
446233965Sjdp	  work -> constructor += 1;
446333965Sjdp	  string_clear (declp);
446433965Sjdp	  return;
446533965Sjdp	}
446633965Sjdp      else if (strcmp (declp -> b, "__dt") == 0)
446733965Sjdp	{
446833965Sjdp	  work -> destructor += 1;
446933965Sjdp	  string_clear (declp);
447033965Sjdp	  return;
447133965Sjdp	}
447233965Sjdp    }
447333965Sjdp
447460484Sobrien  if (declp->p - declp->b >= 3
447533965Sjdp      && declp->b[0] == 'o'
447633965Sjdp      && declp->b[1] == 'p'
447733965Sjdp      && strchr (cplus_markers, declp->b[2]) != NULL)
447833965Sjdp    {
447933965Sjdp      /* see if it's an assignment expression */
448033965Sjdp      if (declp->p - declp->b >= 10 /* op$assign_ */
448133965Sjdp	  && memcmp (declp->b + 3, "assign_", 7) == 0)
448233965Sjdp	{
448377298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
448433965Sjdp	    {
448560484Sobrien	      int len = declp->p - declp->b - 10;
448660484Sobrien	      if ((int) strlen (optable[i].in) == len
448733965Sjdp		  && memcmp (optable[i].in, declp->b + 10, len) == 0)
448833965Sjdp		{
448933965Sjdp		  string_clear (declp);
449033965Sjdp		  string_append (declp, "operator");
449133965Sjdp		  string_append (declp, optable[i].out);
449233965Sjdp		  string_append (declp, "=");
449333965Sjdp		  break;
449433965Sjdp		}
449533965Sjdp	    }
449633965Sjdp	}
449733965Sjdp      else
449833965Sjdp	{
449977298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
450033965Sjdp	    {
450133965Sjdp	      int len = declp->p - declp->b - 3;
450260484Sobrien	      if ((int) strlen (optable[i].in) == len
450333965Sjdp		  && memcmp (optable[i].in, declp->b + 3, len) == 0)
450433965Sjdp		{
450533965Sjdp		  string_clear (declp);
450633965Sjdp		  string_append (declp, "operator");
450733965Sjdp		  string_append (declp, optable[i].out);
450833965Sjdp		  break;
450933965Sjdp		}
451033965Sjdp	    }
451133965Sjdp	}
451233965Sjdp    }
451333965Sjdp  else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0
451433965Sjdp	   && strchr (cplus_markers, declp->b[4]) != NULL)
451533965Sjdp    {
451633965Sjdp      /* type conversion operator */
451733965Sjdp      tem = declp->b + 5;
451833965Sjdp      if (do_type (work, &tem, &type))
451933965Sjdp	{
452033965Sjdp	  string_clear (declp);
452133965Sjdp	  string_append (declp, "operator ");
452233965Sjdp	  string_appends (declp, &type);
452333965Sjdp	  string_delete (&type);
452433965Sjdp	}
452533965Sjdp    }
452633965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
452733965Sjdp	   && declp->b[2] == 'o' && declp->b[3] == 'p')
452833965Sjdp    {
452933965Sjdp      /* ANSI.  */
453033965Sjdp      /* type conversion operator.  */
453133965Sjdp      tem = declp->b + 4;
453233965Sjdp      if (do_type (work, &tem, &type))
453333965Sjdp	{
453433965Sjdp	  string_clear (declp);
453533965Sjdp	  string_append (declp, "operator ");
453633965Sjdp	  string_appends (declp, &type);
453733965Sjdp	  string_delete (&type);
453833965Sjdp	}
453933965Sjdp    }
454033965Sjdp  else if (declp->b[0] == '_' && declp->b[1] == '_'
454177298Sobrien	   && ISLOWER((unsigned char)declp->b[2])
454277298Sobrien	   && ISLOWER((unsigned char)declp->b[3]))
454333965Sjdp    {
454433965Sjdp      if (declp->b[4] == '\0')
454533965Sjdp	{
454633965Sjdp	  /* Operator.  */
454777298Sobrien	  for (i = 0; i < ARRAY_SIZE (optable); i++)
454833965Sjdp	    {
454933965Sjdp	      if (strlen (optable[i].in) == 2
455033965Sjdp		  && memcmp (optable[i].in, declp->b + 2, 2) == 0)
455133965Sjdp		{
455233965Sjdp		  string_clear (declp);
455333965Sjdp		  string_append (declp, "operator");
455433965Sjdp		  string_append (declp, optable[i].out);
455533965Sjdp		  break;
455633965Sjdp		}
455733965Sjdp	    }
455833965Sjdp	}
455933965Sjdp      else
456033965Sjdp	{
456133965Sjdp	  if (declp->b[2] == 'a' && declp->b[5] == '\0')
456233965Sjdp	    {
456333965Sjdp	      /* Assignment.  */
456477298Sobrien	      for (i = 0; i < ARRAY_SIZE (optable); i++)
456533965Sjdp		{
456633965Sjdp		  if (strlen (optable[i].in) == 3
456733965Sjdp		      && memcmp (optable[i].in, declp->b + 2, 3) == 0)
456833965Sjdp		    {
456933965Sjdp		      string_clear (declp);
457033965Sjdp		      string_append (declp, "operator");
457133965Sjdp		      string_append (declp, optable[i].out);
457233965Sjdp		      break;
457360484Sobrien		    }
457433965Sjdp		}
457533965Sjdp	    }
457633965Sjdp	}
457733965Sjdp    }
457833965Sjdp}
457933965Sjdp
458033965Sjdp/* a mini string-handling package */
458133965Sjdp
458233965Sjdpstatic void
4583218822Sdimstring_need (string *s, int n)
458433965Sjdp{
458533965Sjdp  int tem;
458633965Sjdp
458733965Sjdp  if (s->b == NULL)
458833965Sjdp    {
458933965Sjdp      if (n < 32)
459033965Sjdp	{
459133965Sjdp	  n = 32;
459233965Sjdp	}
4593218822Sdim      s->p = s->b = XNEWVEC (char, n);
459433965Sjdp      s->e = s->b + n;
459533965Sjdp    }
459633965Sjdp  else if (s->e - s->p < n)
459733965Sjdp    {
459833965Sjdp      tem = s->p - s->b;
459933965Sjdp      n += tem;
460033965Sjdp      n *= 2;
4601218822Sdim      s->b = XRESIZEVEC (char, s->b, n);
460233965Sjdp      s->p = s->b + tem;
460333965Sjdp      s->e = s->b + n;
460433965Sjdp    }
460533965Sjdp}
460633965Sjdp
460733965Sjdpstatic void
4608218822Sdimstring_delete (string *s)
460933965Sjdp{
461033965Sjdp  if (s->b != NULL)
461133965Sjdp    {
461233965Sjdp      free (s->b);
461333965Sjdp      s->b = s->e = s->p = NULL;
461433965Sjdp    }
461533965Sjdp}
461633965Sjdp
461733965Sjdpstatic void
4618218822Sdimstring_init (string *s)
461933965Sjdp{
462033965Sjdp  s->b = s->p = s->e = NULL;
462133965Sjdp}
462233965Sjdp
462360484Sobrienstatic void
4624218822Sdimstring_clear (string *s)
462533965Sjdp{
462633965Sjdp  s->p = s->b;
462733965Sjdp}
462833965Sjdp
462933965Sjdp#if 0
463033965Sjdp
463133965Sjdpstatic int
4632218822Sdimstring_empty (string *s)
463333965Sjdp{
463433965Sjdp  return (s->b == s->p);
463533965Sjdp}
463633965Sjdp
463733965Sjdp#endif
463833965Sjdp
463933965Sjdpstatic void
4640218822Sdimstring_append (string *p, const char *s)
464133965Sjdp{
464233965Sjdp  int n;
464333965Sjdp  if (s == NULL || *s == '\0')
464433965Sjdp    return;
464533965Sjdp  n = strlen (s);
464633965Sjdp  string_need (p, n);
464733965Sjdp  memcpy (p->p, s, n);
464833965Sjdp  p->p += n;
464933965Sjdp}
465033965Sjdp
465133965Sjdpstatic void
4652218822Sdimstring_appends (string *p, string *s)
465333965Sjdp{
465433965Sjdp  int n;
465533965Sjdp
465633965Sjdp  if (s->b != s->p)
465733965Sjdp    {
465833965Sjdp      n = s->p - s->b;
465933965Sjdp      string_need (p, n);
466033965Sjdp      memcpy (p->p, s->b, n);
466133965Sjdp      p->p += n;
466233965Sjdp    }
466333965Sjdp}
466433965Sjdp
466533965Sjdpstatic void
4666218822Sdimstring_appendn (string *p, const char *s, int n)
466733965Sjdp{
466833965Sjdp  if (n != 0)
466933965Sjdp    {
467033965Sjdp      string_need (p, n);
467133965Sjdp      memcpy (p->p, s, n);
467233965Sjdp      p->p += n;
467333965Sjdp    }
467433965Sjdp}
467533965Sjdp
467633965Sjdpstatic void
4677218822Sdimstring_prepend (string *p, const char *s)
467833965Sjdp{
467933965Sjdp  if (s != NULL && *s != '\0')
468033965Sjdp    {
468133965Sjdp      string_prependn (p, s, strlen (s));
468233965Sjdp    }
468333965Sjdp}
468433965Sjdp
468533965Sjdpstatic void
4686218822Sdimstring_prepends (string *p, string *s)
468733965Sjdp{
468833965Sjdp  if (s->b != s->p)
468933965Sjdp    {
469033965Sjdp      string_prependn (p, s->b, s->p - s->b);
469133965Sjdp    }
469233965Sjdp}
469333965Sjdp
469433965Sjdpstatic void
4695218822Sdimstring_prependn (string *p, const char *s, int n)
469633965Sjdp{
469733965Sjdp  char *q;
469833965Sjdp
469933965Sjdp  if (n != 0)
470033965Sjdp    {
470133965Sjdp      string_need (p, n);
470233965Sjdp      for (q = p->p - 1; q >= p->b; q--)
470333965Sjdp	{
470433965Sjdp	  q[n] = q[0];
470533965Sjdp	}
470633965Sjdp      memcpy (p->b, s, n);
470733965Sjdp      p->p += n;
470833965Sjdp    }
470933965Sjdp}
471033965Sjdp
471160484Sobrienstatic void
4712218822Sdimstring_append_template_idx (string *s, int idx)
471360484Sobrien{
471460484Sobrien  char buf[INTBUF_SIZE + 1 /* 'T' */];
471560484Sobrien  sprintf(buf, "T%d", idx);
471660484Sobrien  string_append (s, buf);
471760484Sobrien}
4718