OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [libiberty/] [cp-demangle.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* Demangler for g++ V3 ABI.
/* Demangler for g++ V3 ABI.
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Written by Ian Lance Taylor <ian@wasabisystems.com>.
   Written by Ian Lance Taylor <ian@wasabisystems.com>.
 
 
   This file is part of the libiberty library, which is part of GCC.
   This file is part of the libiberty library, which is part of GCC.
 
 
   This file is free software; you can redistribute it and/or modify
   This file is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   In addition to the permissions in the GNU General Public License, the
   In addition to the permissions in the GNU General Public License, the
   Free Software Foundation gives you unlimited permission to link the
   Free Software Foundation gives you unlimited permission to link the
   compiled version of this file into combinations with other programs,
   compiled version of this file into combinations with other programs,
   and to distribute those combinations without any restriction coming
   and to distribute those combinations without any restriction coming
   from the use of this file.  (The General Public License restrictions
   from the use of this file.  (The General Public License restrictions
   do apply in other respects; for example, they cover modification of
   do apply in other respects; for example, they cover modification of
   the file, and distribution when not linked into a combined
   the file, and distribution when not linked into a combined
   executable.)
   executable.)
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
*/
 
 
/* This code implements a demangler for the g++ V3 ABI.  The ABI is
/* This code implements a demangler for the g++ V3 ABI.  The ABI is
   described on this web page:
   described on this web page:
       http://www.codesourcery.com/cxx-abi/abi.html#mangling
       http://www.codesourcery.com/cxx-abi/abi.html#mangling
 
 
   This code was written while looking at the demangler written by
   This code was written while looking at the demangler written by
   Alex Samuel <samuel@codesourcery.com>.
   Alex Samuel <samuel@codesourcery.com>.
 
 
   This code first pulls the mangled name apart into a list of
   This code first pulls the mangled name apart into a list of
   components, and then walks the list generating the demangled
   components, and then walks the list generating the demangled
   name.
   name.
 
 
   This file will normally define the following functions, q.v.:
   This file will normally define the following functions, q.v.:
      char *cplus_demangle_v3(const char *mangled, int options)
      char *cplus_demangle_v3(const char *mangled, int options)
      char *java_demangle_v3(const char *mangled)
      char *java_demangle_v3(const char *mangled)
      int cplus_demangle_v3_callback(const char *mangled, int options,
      int cplus_demangle_v3_callback(const char *mangled, int options,
                                     demangle_callbackref callback)
                                     demangle_callbackref callback)
      int java_demangle_v3_callback(const char *mangled,
      int java_demangle_v3_callback(const char *mangled,
                                    demangle_callbackref callback)
                                    demangle_callbackref callback)
      enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
      enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
      enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
      enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
 
 
   Also, the interface to the component list is public, and defined in
   Also, the interface to the component list is public, and defined in
   demangle.h.  The interface consists of these types, which are
   demangle.h.  The interface consists of these types, which are
   defined in demangle.h:
   defined in demangle.h:
      enum demangle_component_type
      enum demangle_component_type
      struct demangle_component
      struct demangle_component
      demangle_callbackref
      demangle_callbackref
   and these functions defined in this file:
   and these functions defined in this file:
      cplus_demangle_fill_name
      cplus_demangle_fill_name
      cplus_demangle_fill_extended_operator
      cplus_demangle_fill_extended_operator
      cplus_demangle_fill_ctor
      cplus_demangle_fill_ctor
      cplus_demangle_fill_dtor
      cplus_demangle_fill_dtor
      cplus_demangle_print
      cplus_demangle_print
      cplus_demangle_print_callback
      cplus_demangle_print_callback
   and other functions defined in the file cp-demint.c.
   and other functions defined in the file cp-demint.c.
 
 
   This file also defines some other functions and variables which are
   This file also defines some other functions and variables which are
   only to be used by the file cp-demint.c.
   only to be used by the file cp-demint.c.
 
 
   Preprocessor macros you can define while compiling this file:
   Preprocessor macros you can define while compiling this file:
 
 
   IN_LIBGCC2
   IN_LIBGCC2
      If defined, this file defines the following functions, q.v.:
      If defined, this file defines the following functions, q.v.:
         char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
         char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
                               int *status)
                               int *status)
         int __gcclibcxx_demangle_callback (const char *,
         int __gcclibcxx_demangle_callback (const char *,
                                            void (*)
                                            void (*)
                                              (const char *, size_t, void *),
                                              (const char *, size_t, void *),
                                            void *)
                                            void *)
      instead of cplus_demangle_v3[_callback]() and
      instead of cplus_demangle_v3[_callback]() and
      java_demangle_v3[_callback]().
      java_demangle_v3[_callback]().
 
 
   IN_GLIBCPP_V3
   IN_GLIBCPP_V3
      If defined, this file defines only __cxa_demangle() and
      If defined, this file defines only __cxa_demangle() and
      __gcclibcxx_demangle_callback(), and no other publically visible
      __gcclibcxx_demangle_callback(), and no other publically visible
      functions or variables.
      functions or variables.
 
 
   STANDALONE_DEMANGLER
   STANDALONE_DEMANGLER
      If defined, this file defines a main() function which demangles
      If defined, this file defines a main() function which demangles
      any arguments, or, if none, demangles stdin.
      any arguments, or, if none, demangles stdin.
 
 
   CP_DEMANGLE_DEBUG
   CP_DEMANGLE_DEBUG
      If defined, turns on debugging mode, which prints information on
      If defined, turns on debugging mode, which prints information on
      stdout about the mangled string.  This is not generally useful.
      stdout about the mangled string.  This is not generally useful.
*/
*/
 
 
#if defined (_AIX) && !defined (__GNUC__)
#if defined (_AIX) && !defined (__GNUC__)
 #pragma alloca
 #pragma alloca
#endif
#endif
 
 
#ifdef HAVE_CONFIG_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config.h"
#endif
#endif
 
 
#include <stdio.h>
#include <stdio.h>
 
 
#ifdef HAVE_STDLIB_H
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <stdlib.h>
#endif
#endif
#ifdef HAVE_STRING_H
#ifdef HAVE_STRING_H
#include <string.h>
#include <string.h>
#endif
#endif
 
 
#ifdef HAVE_ALLOCA_H
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
# include <alloca.h>
#else
#else
# ifndef alloca
# ifndef alloca
#  ifdef __GNUC__
#  ifdef __GNUC__
#   define alloca __builtin_alloca
#   define alloca __builtin_alloca
#  else
#  else
extern char *alloca ();
extern char *alloca ();
#  endif /* __GNUC__ */
#  endif /* __GNUC__ */
# endif /* alloca */
# endif /* alloca */
#endif /* HAVE_ALLOCA_H */
#endif /* HAVE_ALLOCA_H */
 
 
#include "ansidecl.h"
#include "ansidecl.h"
#include "libiberty.h"
#include "libiberty.h"
#include "demangle.h"
#include "demangle.h"
#include "cp-demangle.h"
#include "cp-demangle.h"
 
 
/* If IN_GLIBCPP_V3 is defined, some functions are made static.  We
/* If IN_GLIBCPP_V3 is defined, some functions are made static.  We
   also rename them via #define to avoid compiler errors when the
   also rename them via #define to avoid compiler errors when the
   static definition conflicts with the extern declaration in a header
   static definition conflicts with the extern declaration in a header
   file.  */
   file.  */
#ifdef IN_GLIBCPP_V3
#ifdef IN_GLIBCPP_V3
 
 
#define CP_STATIC_IF_GLIBCPP_V3 static
#define CP_STATIC_IF_GLIBCPP_V3 static
 
 
#define cplus_demangle_fill_name d_fill_name
#define cplus_demangle_fill_name d_fill_name
static int d_fill_name (struct demangle_component *, const char *, int);
static int d_fill_name (struct demangle_component *, const char *, int);
 
 
#define cplus_demangle_fill_extended_operator d_fill_extended_operator
#define cplus_demangle_fill_extended_operator d_fill_extended_operator
static int
static int
d_fill_extended_operator (struct demangle_component *, int,
d_fill_extended_operator (struct demangle_component *, int,
                          struct demangle_component *);
                          struct demangle_component *);
 
 
#define cplus_demangle_fill_ctor d_fill_ctor
#define cplus_demangle_fill_ctor d_fill_ctor
static int
static int
d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds,
d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds,
             struct demangle_component *);
             struct demangle_component *);
 
 
#define cplus_demangle_fill_dtor d_fill_dtor
#define cplus_demangle_fill_dtor d_fill_dtor
static int
static int
d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds,
d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds,
             struct demangle_component *);
             struct demangle_component *);
 
 
#define cplus_demangle_mangled_name d_mangled_name
#define cplus_demangle_mangled_name d_mangled_name
static struct demangle_component *d_mangled_name (struct d_info *, int);
static struct demangle_component *d_mangled_name (struct d_info *, int);
 
 
#define cplus_demangle_type d_type
#define cplus_demangle_type d_type
static struct demangle_component *d_type (struct d_info *);
static struct demangle_component *d_type (struct d_info *);
 
 
#define cplus_demangle_print d_print
#define cplus_demangle_print d_print
static char *d_print (int, const struct demangle_component *, int, size_t *);
static char *d_print (int, const struct demangle_component *, int, size_t *);
 
 
#define cplus_demangle_print_callback d_print_callback
#define cplus_demangle_print_callback d_print_callback
static int d_print_callback (int, const struct demangle_component *,
static int d_print_callback (int, const struct demangle_component *,
                             demangle_callbackref, void *);
                             demangle_callbackref, void *);
 
 
#define cplus_demangle_init_info d_init_info
#define cplus_demangle_init_info d_init_info
static void d_init_info (const char *, int, size_t, struct d_info *);
static void d_init_info (const char *, int, size_t, struct d_info *);
 
 
#else /* ! defined(IN_GLIBCPP_V3) */
#else /* ! defined(IN_GLIBCPP_V3) */
#define CP_STATIC_IF_GLIBCPP_V3
#define CP_STATIC_IF_GLIBCPP_V3
#endif /* ! defined(IN_GLIBCPP_V3) */
#endif /* ! defined(IN_GLIBCPP_V3) */
 
 
/* See if the compiler supports dynamic arrays.  */
/* See if the compiler supports dynamic arrays.  */
 
 
#ifdef __GNUC__
#ifdef __GNUC__
#define CP_DYNAMIC_ARRAYS
#define CP_DYNAMIC_ARRAYS
#else
#else
#ifdef __STDC__
#ifdef __STDC__
#ifdef __STDC_VERSION__
#ifdef __STDC_VERSION__
#if __STDC_VERSION__ >= 199901L
#if __STDC_VERSION__ >= 199901L
#define CP_DYNAMIC_ARRAYS
#define CP_DYNAMIC_ARRAYS
#endif /* __STDC__VERSION >= 199901L */
#endif /* __STDC__VERSION >= 199901L */
#endif /* defined (__STDC_VERSION__) */
#endif /* defined (__STDC_VERSION__) */
#endif /* defined (__STDC__) */
#endif /* defined (__STDC__) */
#endif /* ! defined (__GNUC__) */
#endif /* ! defined (__GNUC__) */
 
 
/* We avoid pulling in the ctype tables, to prevent pulling in
/* We avoid pulling in the ctype tables, to prevent pulling in
   additional unresolved symbols when this code is used in a library.
   additional unresolved symbols when this code is used in a library.
   FIXME: Is this really a valid reason?  This comes from the original
   FIXME: Is this really a valid reason?  This comes from the original
   V3 demangler code.
   V3 demangler code.
 
 
   As of this writing this file has the following undefined references
   As of this writing this file has the following undefined references
   when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy,
   when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy,
   strcat, strlen.  */
   strcat, strlen.  */
 
 
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
 
 
/* The prefix prepended by GCC to an identifier represnting the
/* The prefix prepended by GCC to an identifier represnting the
   anonymous namespace.  */
   anonymous namespace.  */
#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
#define ANONYMOUS_NAMESPACE_PREFIX_LEN \
#define ANONYMOUS_NAMESPACE_PREFIX_LEN \
  (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1)
  (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1)
 
 
/* Information we keep for the standard substitutions.  */
/* Information we keep for the standard substitutions.  */
 
 
struct d_standard_sub_info
struct d_standard_sub_info
{
{
  /* The code for this substitution.  */
  /* The code for this substitution.  */
  char code;
  char code;
  /* The simple string it expands to.  */
  /* The simple string it expands to.  */
  const char *simple_expansion;
  const char *simple_expansion;
  /* The length of the simple expansion.  */
  /* The length of the simple expansion.  */
  int simple_len;
  int simple_len;
  /* The results of a full, verbose, expansion.  This is used when
  /* The results of a full, verbose, expansion.  This is used when
     qualifying a constructor/destructor, or when in verbose mode.  */
     qualifying a constructor/destructor, or when in verbose mode.  */
  const char *full_expansion;
  const char *full_expansion;
  /* The length of the full expansion.  */
  /* The length of the full expansion.  */
  int full_len;
  int full_len;
  /* What to set the last_name field of d_info to; NULL if we should
  /* What to set the last_name field of d_info to; NULL if we should
     not set it.  This is only relevant when qualifying a
     not set it.  This is only relevant when qualifying a
     constructor/destructor.  */
     constructor/destructor.  */
  const char *set_last_name;
  const char *set_last_name;
  /* The length of set_last_name.  */
  /* The length of set_last_name.  */
  int set_last_name_len;
  int set_last_name_len;
};
};
 
 
/* Accessors for subtrees of struct demangle_component.  */
/* Accessors for subtrees of struct demangle_component.  */
 
 
#define d_left(dc) ((dc)->u.s_binary.left)
#define d_left(dc) ((dc)->u.s_binary.left)
#define d_right(dc) ((dc)->u.s_binary.right)
#define d_right(dc) ((dc)->u.s_binary.right)
 
 
/* A list of templates.  This is used while printing.  */
/* A list of templates.  This is used while printing.  */
 
 
struct d_print_template
struct d_print_template
{
{
  /* Next template on the list.  */
  /* Next template on the list.  */
  struct d_print_template *next;
  struct d_print_template *next;
  /* This template.  */
  /* This template.  */
  const struct demangle_component *template_decl;
  const struct demangle_component *template_decl;
};
};
 
 
/* A list of type modifiers.  This is used while printing.  */
/* A list of type modifiers.  This is used while printing.  */
 
 
struct d_print_mod
struct d_print_mod
{
{
  /* Next modifier on the list.  These are in the reverse of the order
  /* Next modifier on the list.  These are in the reverse of the order
     in which they appeared in the mangled string.  */
     in which they appeared in the mangled string.  */
  struct d_print_mod *next;
  struct d_print_mod *next;
  /* The modifier.  */
  /* The modifier.  */
  const struct demangle_component *mod;
  const struct demangle_component *mod;
  /* Whether this modifier was printed.  */
  /* Whether this modifier was printed.  */
  int printed;
  int printed;
  /* The list of templates which applies to this modifier.  */
  /* The list of templates which applies to this modifier.  */
  struct d_print_template *templates;
  struct d_print_template *templates;
};
};
 
 
/* We use these structures to hold information during printing.  */
/* We use these structures to hold information during printing.  */
 
 
struct d_growable_string
struct d_growable_string
{
{
  /* Buffer holding the result.  */
  /* Buffer holding the result.  */
  char *buf;
  char *buf;
  /* Current length of data in buffer.  */
  /* Current length of data in buffer.  */
  size_t len;
  size_t len;
  /* Allocated size of buffer.  */
  /* Allocated size of buffer.  */
  size_t alc;
  size_t alc;
  /* Set to 1 if we had a memory allocation failure.  */
  /* Set to 1 if we had a memory allocation failure.  */
  int allocation_failure;
  int allocation_failure;
};
};
 
 
enum { D_PRINT_BUFFER_LENGTH = 256 };
enum { D_PRINT_BUFFER_LENGTH = 256 };
struct d_print_info
struct d_print_info
{
{
  /* The options passed to the demangler.  */
  /* The options passed to the demangler.  */
  int options;
  int options;
  /* Fixed-length allocated buffer for demangled data, flushed to the
  /* Fixed-length allocated buffer for demangled data, flushed to the
     callback with a NUL termination once full.  */
     callback with a NUL termination once full.  */
  char buf[D_PRINT_BUFFER_LENGTH];
  char buf[D_PRINT_BUFFER_LENGTH];
  /* Current length of data in buffer.  */
  /* Current length of data in buffer.  */
  size_t len;
  size_t len;
  /* The last character printed, saved individually so that it survives
  /* The last character printed, saved individually so that it survives
     any buffer flush.  */
     any buffer flush.  */
  char last_char;
  char last_char;
  /* Callback function to handle demangled buffer flush.  */
  /* Callback function to handle demangled buffer flush.  */
  demangle_callbackref callback;
  demangle_callbackref callback;
  /* Opaque callback argument.  */
  /* Opaque callback argument.  */
  void *opaque;
  void *opaque;
  /* The current list of templates, if any.  */
  /* The current list of templates, if any.  */
  struct d_print_template *templates;
  struct d_print_template *templates;
  /* The current list of modifiers (e.g., pointer, reference, etc.),
  /* The current list of modifiers (e.g., pointer, reference, etc.),
     if any.  */
     if any.  */
  struct d_print_mod *modifiers;
  struct d_print_mod *modifiers;
  /* Set to 1 if we saw a demangling error.  */
  /* Set to 1 if we saw a demangling error.  */
  int demangle_failure;
  int demangle_failure;
  /* The current index into any template argument packs we are using
  /* The current index into any template argument packs we are using
     for printing.  */
     for printing.  */
  int pack_index;
  int pack_index;
};
};
 
 
#ifdef CP_DEMANGLE_DEBUG
#ifdef CP_DEMANGLE_DEBUG
static void d_dump (struct demangle_component *, int);
static void d_dump (struct demangle_component *, int);
#endif
#endif
 
 
static struct demangle_component *
static struct demangle_component *
d_make_empty (struct d_info *);
d_make_empty (struct d_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_comp (struct d_info *, enum demangle_component_type,
d_make_comp (struct d_info *, enum demangle_component_type,
             struct demangle_component *,
             struct demangle_component *,
             struct demangle_component *);
             struct demangle_component *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_name (struct d_info *, const char *, int);
d_make_name (struct d_info *, const char *, int);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_builtin_type (struct d_info *,
d_make_builtin_type (struct d_info *,
                     const struct demangle_builtin_type_info *);
                     const struct demangle_builtin_type_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_operator (struct d_info *,
d_make_operator (struct d_info *,
                 const struct demangle_operator_info *);
                 const struct demangle_operator_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_extended_operator (struct d_info *, int,
d_make_extended_operator (struct d_info *, int,
                          struct demangle_component *);
                          struct demangle_component *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds,
d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds,
             struct demangle_component *);
             struct demangle_component *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds,
d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds,
             struct demangle_component *);
             struct demangle_component *);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_template_param (struct d_info *, long);
d_make_template_param (struct d_info *, long);
 
 
static struct demangle_component *
static struct demangle_component *
d_make_sub (struct d_info *, const char *, int);
d_make_sub (struct d_info *, const char *, int);
 
 
static int
static int
has_return_type (struct demangle_component *);
has_return_type (struct demangle_component *);
 
 
static int
static int
is_ctor_dtor_or_conversion (struct demangle_component *);
is_ctor_dtor_or_conversion (struct demangle_component *);
 
 
static struct demangle_component *d_encoding (struct d_info *, int);
static struct demangle_component *d_encoding (struct d_info *, int);
 
 
static struct demangle_component *d_name (struct d_info *);
static struct demangle_component *d_name (struct d_info *);
 
 
static struct demangle_component *d_nested_name (struct d_info *);
static struct demangle_component *d_nested_name (struct d_info *);
 
 
static struct demangle_component *d_prefix (struct d_info *);
static struct demangle_component *d_prefix (struct d_info *);
 
 
static struct demangle_component *d_unqualified_name (struct d_info *);
static struct demangle_component *d_unqualified_name (struct d_info *);
 
 
static struct demangle_component *d_source_name (struct d_info *);
static struct demangle_component *d_source_name (struct d_info *);
 
 
static long d_number (struct d_info *);
static long d_number (struct d_info *);
 
 
static struct demangle_component *d_identifier (struct d_info *, int);
static struct demangle_component *d_identifier (struct d_info *, int);
 
 
static struct demangle_component *d_operator_name (struct d_info *);
static struct demangle_component *d_operator_name (struct d_info *);
 
 
static struct demangle_component *d_special_name (struct d_info *);
static struct demangle_component *d_special_name (struct d_info *);
 
 
static int d_call_offset (struct d_info *, int);
static int d_call_offset (struct d_info *, int);
 
 
static struct demangle_component *d_ctor_dtor_name (struct d_info *);
static struct demangle_component *d_ctor_dtor_name (struct d_info *);
 
 
static struct demangle_component **
static struct demangle_component **
d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
 
 
static struct demangle_component *
static struct demangle_component *
d_function_type (struct d_info *);
d_function_type (struct d_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_bare_function_type (struct d_info *, int);
d_bare_function_type (struct d_info *, int);
 
 
static struct demangle_component *
static struct demangle_component *
d_class_enum_type (struct d_info *);
d_class_enum_type (struct d_info *);
 
 
static struct demangle_component *d_array_type (struct d_info *);
static struct demangle_component *d_array_type (struct d_info *);
 
 
static struct demangle_component *d_vector_type (struct d_info *);
static struct demangle_component *d_vector_type (struct d_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_pointer_to_member_type (struct d_info *);
d_pointer_to_member_type (struct d_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_template_param (struct d_info *);
d_template_param (struct d_info *);
 
 
static struct demangle_component *d_template_args (struct d_info *);
static struct demangle_component *d_template_args (struct d_info *);
 
 
static struct demangle_component *
static struct demangle_component *
d_template_arg (struct d_info *);
d_template_arg (struct d_info *);
 
 
static struct demangle_component *d_expression (struct d_info *);
static struct demangle_component *d_expression (struct d_info *);
 
 
static struct demangle_component *d_expr_primary (struct d_info *);
static struct demangle_component *d_expr_primary (struct d_info *);
 
 
static struct demangle_component *d_local_name (struct d_info *);
static struct demangle_component *d_local_name (struct d_info *);
 
 
static int d_discriminator (struct d_info *);
static int d_discriminator (struct d_info *);
 
 
static struct demangle_component *d_lambda (struct d_info *);
static struct demangle_component *d_lambda (struct d_info *);
 
 
static struct demangle_component *d_unnamed_type (struct d_info *);
static struct demangle_component *d_unnamed_type (struct d_info *);
 
 
static int
static int
d_add_substitution (struct d_info *, struct demangle_component *);
d_add_substitution (struct d_info *, struct demangle_component *);
 
 
static struct demangle_component *d_substitution (struct d_info *, int);
static struct demangle_component *d_substitution (struct d_info *, int);
 
 
static void d_growable_string_init (struct d_growable_string *, size_t);
static void d_growable_string_init (struct d_growable_string *, size_t);
 
 
static inline void
static inline void
d_growable_string_resize (struct d_growable_string *, size_t);
d_growable_string_resize (struct d_growable_string *, size_t);
 
 
static inline void
static inline void
d_growable_string_append_buffer (struct d_growable_string *,
d_growable_string_append_buffer (struct d_growable_string *,
                                 const char *, size_t);
                                 const char *, size_t);
static void
static void
d_growable_string_callback_adapter (const char *, size_t, void *);
d_growable_string_callback_adapter (const char *, size_t, void *);
 
 
static void
static void
d_print_init (struct d_print_info *, int, demangle_callbackref, void *);
d_print_init (struct d_print_info *, int, demangle_callbackref, void *);
 
 
static inline void d_print_error (struct d_print_info *);
static inline void d_print_error (struct d_print_info *);
 
 
static inline int d_print_saw_error (struct d_print_info *);
static inline int d_print_saw_error (struct d_print_info *);
 
 
static inline void d_print_flush (struct d_print_info *);
static inline void d_print_flush (struct d_print_info *);
 
 
static inline void d_append_char (struct d_print_info *, char);
static inline void d_append_char (struct d_print_info *, char);
 
 
static inline void d_append_buffer (struct d_print_info *,
static inline void d_append_buffer (struct d_print_info *,
                                    const char *, size_t);
                                    const char *, size_t);
 
 
static inline void d_append_string (struct d_print_info *, const char *);
static inline void d_append_string (struct d_print_info *, const char *);
 
 
static inline char d_last_char (struct d_print_info *);
static inline char d_last_char (struct d_print_info *);
 
 
static void
static void
d_print_comp (struct d_print_info *, const struct demangle_component *);
d_print_comp (struct d_print_info *, const struct demangle_component *);
 
 
static void
static void
d_print_java_identifier (struct d_print_info *, const char *, int);
d_print_java_identifier (struct d_print_info *, const char *, int);
 
 
static void
static void
d_print_mod_list (struct d_print_info *, struct d_print_mod *, int);
d_print_mod_list (struct d_print_info *, struct d_print_mod *, int);
 
 
static void
static void
d_print_mod (struct d_print_info *, const struct demangle_component *);
d_print_mod (struct d_print_info *, const struct demangle_component *);
 
 
static void
static void
d_print_function_type (struct d_print_info *,
d_print_function_type (struct d_print_info *,
                       const struct demangle_component *,
                       const struct demangle_component *,
                       struct d_print_mod *);
                       struct d_print_mod *);
 
 
static void
static void
d_print_array_type (struct d_print_info *,
d_print_array_type (struct d_print_info *,
                    const struct demangle_component *,
                    const struct demangle_component *,
                    struct d_print_mod *);
                    struct d_print_mod *);
 
 
static void
static void
d_print_expr_op (struct d_print_info *, const struct demangle_component *);
d_print_expr_op (struct d_print_info *, const struct demangle_component *);
 
 
static void
static void
d_print_cast (struct d_print_info *, const struct demangle_component *);
d_print_cast (struct d_print_info *, const struct demangle_component *);
 
 
static int d_demangle_callback (const char *, int,
static int d_demangle_callback (const char *, int,
                                demangle_callbackref, void *);
                                demangle_callbackref, void *);
static char *d_demangle (const char *, int, size_t *);
static char *d_demangle (const char *, int, size_t *);
 
 
#ifdef CP_DEMANGLE_DEBUG
#ifdef CP_DEMANGLE_DEBUG
 
 
static void
static void
d_dump (struct demangle_component *dc, int indent)
d_dump (struct demangle_component *dc, int indent)
{
{
  int i;
  int i;
 
 
  if (dc == NULL)
  if (dc == NULL)
    {
    {
      if (indent == 0)
      if (indent == 0)
        printf ("failed demangling\n");
        printf ("failed demangling\n");
      return;
      return;
    }
    }
 
 
  for (i = 0; i < indent; ++i)
  for (i = 0; i < indent; ++i)
    putchar (' ');
    putchar (' ');
 
 
  switch (dc->type)
  switch (dc->type)
    {
    {
    case DEMANGLE_COMPONENT_NAME:
    case DEMANGLE_COMPONENT_NAME:
      printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
      printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
      return;
      return;
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
      printf ("template parameter %ld\n", dc->u.s_number.number);
      printf ("template parameter %ld\n", dc->u.s_number.number);
      return;
      return;
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_CTOR:
      printf ("constructor %d\n", (int) dc->u.s_ctor.kind);
      printf ("constructor %d\n", (int) dc->u.s_ctor.kind);
      d_dump (dc->u.s_ctor.name, indent + 2);
      d_dump (dc->u.s_ctor.name, indent + 2);
      return;
      return;
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_DTOR:
      printf ("destructor %d\n", (int) dc->u.s_dtor.kind);
      printf ("destructor %d\n", (int) dc->u.s_dtor.kind);
      d_dump (dc->u.s_dtor.name, indent + 2);
      d_dump (dc->u.s_dtor.name, indent + 2);
      return;
      return;
    case DEMANGLE_COMPONENT_SUB_STD:
    case DEMANGLE_COMPONENT_SUB_STD:
      printf ("standard substitution %s\n", dc->u.s_string.string);
      printf ("standard substitution %s\n", dc->u.s_string.string);
      return;
      return;
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
      printf ("builtin type %s\n", dc->u.s_builtin.type->name);
      printf ("builtin type %s\n", dc->u.s_builtin.type->name);
      return;
      return;
    case DEMANGLE_COMPONENT_OPERATOR:
    case DEMANGLE_COMPONENT_OPERATOR:
      printf ("operator %s\n", dc->u.s_operator.op->name);
      printf ("operator %s\n", dc->u.s_operator.op->name);
      return;
      return;
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
      printf ("extended operator with %d args\n",
      printf ("extended operator with %d args\n",
              dc->u.s_extended_operator.args);
              dc->u.s_extended_operator.args);
      d_dump (dc->u.s_extended_operator.name, indent + 2);
      d_dump (dc->u.s_extended_operator.name, indent + 2);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_QUAL_NAME:
      printf ("qualified name\n");
      printf ("qualified name\n");
      break;
      break;
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
      printf ("local name\n");
      printf ("local name\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
      printf ("typed name\n");
      printf ("typed name\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_TEMPLATE:
      printf ("template\n");
      printf ("template\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VTABLE:
    case DEMANGLE_COMPONENT_VTABLE:
      printf ("vtable\n");
      printf ("vtable\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VTT:
    case DEMANGLE_COMPONENT_VTT:
      printf ("VTT\n");
      printf ("VTT\n");
      break;
      break;
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
      printf ("construction vtable\n");
      printf ("construction vtable\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TYPEINFO:
    case DEMANGLE_COMPONENT_TYPEINFO:
      printf ("typeinfo\n");
      printf ("typeinfo\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
      printf ("typeinfo name\n");
      printf ("typeinfo name\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
      printf ("typeinfo function\n");
      printf ("typeinfo function\n");
      break;
      break;
    case DEMANGLE_COMPONENT_THUNK:
    case DEMANGLE_COMPONENT_THUNK:
      printf ("thunk\n");
      printf ("thunk\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
      printf ("virtual thunk\n");
      printf ("virtual thunk\n");
      break;
      break;
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
      printf ("covariant thunk\n");
      printf ("covariant thunk\n");
      break;
      break;
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
      printf ("java class\n");
      printf ("java class\n");
      break;
      break;
    case DEMANGLE_COMPONENT_GUARD:
    case DEMANGLE_COMPONENT_GUARD:
      printf ("guard\n");
      printf ("guard\n");
      break;
      break;
    case DEMANGLE_COMPONENT_REFTEMP:
    case DEMANGLE_COMPONENT_REFTEMP:
      printf ("reference temporary\n");
      printf ("reference temporary\n");
      break;
      break;
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
      printf ("hidden alias\n");
      printf ("hidden alias\n");
      break;
      break;
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT:
      printf ("restrict\n");
      printf ("restrict\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE:
      printf ("volatile\n");
      printf ("volatile\n");
      break;
      break;
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST:
      printf ("const\n");
      printf ("const\n");
      break;
      break;
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
      printf ("restrict this\n");
      printf ("restrict this\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
      printf ("volatile this\n");
      printf ("volatile this\n");
      break;
      break;
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
      printf ("const this\n");
      printf ("const this\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
      printf ("vendor type qualifier\n");
      printf ("vendor type qualifier\n");
      break;
      break;
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_POINTER:
      printf ("pointer\n");
      printf ("pointer\n");
      break;
      break;
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_REFERENCE:
      printf ("reference\n");
      printf ("reference\n");
      break;
      break;
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
      printf ("rvalue reference\n");
      printf ("rvalue reference\n");
      break;
      break;
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_COMPLEX:
      printf ("complex\n");
      printf ("complex\n");
      break;
      break;
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_IMAGINARY:
      printf ("imaginary\n");
      printf ("imaginary\n");
      break;
      break;
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
      printf ("vendor type\n");
      printf ("vendor type\n");
      break;
      break;
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
      printf ("function type\n");
      printf ("function type\n");
      break;
      break;
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
      printf ("array type\n");
      printf ("array type\n");
      break;
      break;
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
      printf ("pointer to member type\n");
      printf ("pointer to member type\n");
      break;
      break;
    case DEMANGLE_COMPONENT_FIXED_TYPE:
    case DEMANGLE_COMPONENT_FIXED_TYPE:
      printf ("fixed-point type\n");
      printf ("fixed-point type\n");
      break;
      break;
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_ARGLIST:
      printf ("argument list\n");
      printf ("argument list\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
      printf ("template argument list\n");
      printf ("template argument list\n");
      break;
      break;
    case DEMANGLE_COMPONENT_CAST:
    case DEMANGLE_COMPONENT_CAST:
      printf ("cast\n");
      printf ("cast\n");
      break;
      break;
    case DEMANGLE_COMPONENT_UNARY:
    case DEMANGLE_COMPONENT_UNARY:
      printf ("unary operator\n");
      printf ("unary operator\n");
      break;
      break;
    case DEMANGLE_COMPONENT_BINARY:
    case DEMANGLE_COMPONENT_BINARY:
      printf ("binary operator\n");
      printf ("binary operator\n");
      break;
      break;
    case DEMANGLE_COMPONENT_BINARY_ARGS:
    case DEMANGLE_COMPONENT_BINARY_ARGS:
      printf ("binary operator arguments\n");
      printf ("binary operator arguments\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TRINARY:
    case DEMANGLE_COMPONENT_TRINARY:
      printf ("trinary operator\n");
      printf ("trinary operator\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
      printf ("trinary operator arguments 1\n");
      printf ("trinary operator arguments 1\n");
      break;
      break;
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
      printf ("trinary operator arguments 1\n");
      printf ("trinary operator arguments 1\n");
      break;
      break;
    case DEMANGLE_COMPONENT_LITERAL:
    case DEMANGLE_COMPONENT_LITERAL:
      printf ("literal\n");
      printf ("literal\n");
      break;
      break;
    case DEMANGLE_COMPONENT_LITERAL_NEG:
    case DEMANGLE_COMPONENT_LITERAL_NEG:
      printf ("negative literal\n");
      printf ("negative literal\n");
      break;
      break;
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
      printf ("java resource\n");
      printf ("java resource\n");
      break;
      break;
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
      printf ("compound name\n");
      printf ("compound name\n");
      break;
      break;
    case DEMANGLE_COMPONENT_CHARACTER:
    case DEMANGLE_COMPONENT_CHARACTER:
      printf ("character '%c'\n",  dc->u.s_character.character);
      printf ("character '%c'\n",  dc->u.s_character.character);
      return;
      return;
    case DEMANGLE_COMPONENT_DECLTYPE:
    case DEMANGLE_COMPONENT_DECLTYPE:
      printf ("decltype\n");
      printf ("decltype\n");
      break;
      break;
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
      printf ("pack expansion\n");
      printf ("pack expansion\n");
      break;
      break;
    }
    }
 
 
  d_dump (d_left (dc), indent + 2);
  d_dump (d_left (dc), indent + 2);
  d_dump (d_right (dc), indent + 2);
  d_dump (d_right (dc), indent + 2);
}
}
 
 
#endif /* CP_DEMANGLE_DEBUG */
#endif /* CP_DEMANGLE_DEBUG */
 
 
/* Fill in a DEMANGLE_COMPONENT_NAME.  */
/* Fill in a DEMANGLE_COMPONENT_NAME.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
int
int
cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len)
cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len)
{
{
  if (p == NULL || s == NULL || len == 0)
  if (p == NULL || s == NULL || len == 0)
    return 0;
    return 0;
  p->type = DEMANGLE_COMPONENT_NAME;
  p->type = DEMANGLE_COMPONENT_NAME;
  p->u.s_name.s = s;
  p->u.s_name.s = s;
  p->u.s_name.len = len;
  p->u.s_name.len = len;
  return 1;
  return 1;
}
}
 
 
/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR.  */
/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
int
int
cplus_demangle_fill_extended_operator (struct demangle_component *p, int args,
cplus_demangle_fill_extended_operator (struct demangle_component *p, int args,
                                       struct demangle_component *name)
                                       struct demangle_component *name)
{
{
  if (p == NULL || args < 0 || name == NULL)
  if (p == NULL || args < 0 || name == NULL)
    return 0;
    return 0;
  p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
  p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
  p->u.s_extended_operator.args = args;
  p->u.s_extended_operator.args = args;
  p->u.s_extended_operator.name = name;
  p->u.s_extended_operator.name = name;
  return 1;
  return 1;
}
}
 
 
/* Fill in a DEMANGLE_COMPONENT_CTOR.  */
/* Fill in a DEMANGLE_COMPONENT_CTOR.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
int
int
cplus_demangle_fill_ctor (struct demangle_component *p,
cplus_demangle_fill_ctor (struct demangle_component *p,
                          enum gnu_v3_ctor_kinds kind,
                          enum gnu_v3_ctor_kinds kind,
                          struct demangle_component *name)
                          struct demangle_component *name)
{
{
  if (p == NULL
  if (p == NULL
      || name == NULL
      || name == NULL
      || (int) kind < gnu_v3_complete_object_ctor
      || (int) kind < gnu_v3_complete_object_ctor
      || (int) kind > gnu_v3_complete_object_allocating_ctor)
      || (int) kind > gnu_v3_complete_object_allocating_ctor)
    return 0;
    return 0;
  p->type = DEMANGLE_COMPONENT_CTOR;
  p->type = DEMANGLE_COMPONENT_CTOR;
  p->u.s_ctor.kind = kind;
  p->u.s_ctor.kind = kind;
  p->u.s_ctor.name = name;
  p->u.s_ctor.name = name;
  return 1;
  return 1;
}
}
 
 
/* Fill in a DEMANGLE_COMPONENT_DTOR.  */
/* Fill in a DEMANGLE_COMPONENT_DTOR.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
int
int
cplus_demangle_fill_dtor (struct demangle_component *p,
cplus_demangle_fill_dtor (struct demangle_component *p,
                          enum gnu_v3_dtor_kinds kind,
                          enum gnu_v3_dtor_kinds kind,
                          struct demangle_component *name)
                          struct demangle_component *name)
{
{
  if (p == NULL
  if (p == NULL
      || name == NULL
      || name == NULL
      || (int) kind < gnu_v3_deleting_dtor
      || (int) kind < gnu_v3_deleting_dtor
      || (int) kind > gnu_v3_base_object_dtor)
      || (int) kind > gnu_v3_base_object_dtor)
    return 0;
    return 0;
  p->type = DEMANGLE_COMPONENT_DTOR;
  p->type = DEMANGLE_COMPONENT_DTOR;
  p->u.s_dtor.kind = kind;
  p->u.s_dtor.kind = kind;
  p->u.s_dtor.name = name;
  p->u.s_dtor.name = name;
  return 1;
  return 1;
}
}
 
 
/* Add a new component.  */
/* Add a new component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_empty (struct d_info *di)
d_make_empty (struct d_info *di)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  if (di->next_comp >= di->num_comps)
  if (di->next_comp >= di->num_comps)
    return NULL;
    return NULL;
  p = &di->comps[di->next_comp];
  p = &di->comps[di->next_comp];
  ++di->next_comp;
  ++di->next_comp;
  return p;
  return p;
}
}
 
 
/* Add a new generic component.  */
/* Add a new generic component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_comp (struct d_info *di, enum demangle_component_type type,
d_make_comp (struct d_info *di, enum demangle_component_type type,
             struct demangle_component *left,
             struct demangle_component *left,
             struct demangle_component *right)
             struct demangle_component *right)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  /* We check for errors here.  A typical error would be a NULL return
  /* We check for errors here.  A typical error would be a NULL return
     from a subroutine.  We catch those here, and return NULL
     from a subroutine.  We catch those here, and return NULL
     upward.  */
     upward.  */
  switch (type)
  switch (type)
    {
    {
      /* These types require two parameters.  */
      /* These types require two parameters.  */
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_UNARY:
    case DEMANGLE_COMPONENT_UNARY:
    case DEMANGLE_COMPONENT_BINARY:
    case DEMANGLE_COMPONENT_BINARY:
    case DEMANGLE_COMPONENT_BINARY_ARGS:
    case DEMANGLE_COMPONENT_BINARY_ARGS:
    case DEMANGLE_COMPONENT_TRINARY:
    case DEMANGLE_COMPONENT_TRINARY:
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
    case DEMANGLE_COMPONENT_LITERAL:
    case DEMANGLE_COMPONENT_LITERAL:
    case DEMANGLE_COMPONENT_LITERAL_NEG:
    case DEMANGLE_COMPONENT_LITERAL_NEG:
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
      if (left == NULL || right == NULL)
      if (left == NULL || right == NULL)
        return NULL;
        return NULL;
      break;
      break;
 
 
      /* These types only require one parameter.  */
      /* These types only require one parameter.  */
    case DEMANGLE_COMPONENT_VTABLE:
    case DEMANGLE_COMPONENT_VTABLE:
    case DEMANGLE_COMPONENT_VTT:
    case DEMANGLE_COMPONENT_VTT:
    case DEMANGLE_COMPONENT_TYPEINFO:
    case DEMANGLE_COMPONENT_TYPEINFO:
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
    case DEMANGLE_COMPONENT_THUNK:
    case DEMANGLE_COMPONENT_THUNK:
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_GUARD:
    case DEMANGLE_COMPONENT_GUARD:
    case DEMANGLE_COMPONENT_REFTEMP:
    case DEMANGLE_COMPONENT_REFTEMP:
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_CAST:
    case DEMANGLE_COMPONENT_CAST:
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
    case DEMANGLE_COMPONENT_DECLTYPE:
    case DEMANGLE_COMPONENT_DECLTYPE:
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
    case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
    case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
    case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
    case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
      if (left == NULL)
      if (left == NULL)
        return NULL;
        return NULL;
      break;
      break;
 
 
      /* This needs a right parameter, but the left parameter can be
      /* This needs a right parameter, but the left parameter can be
         empty.  */
         empty.  */
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
      if (right == NULL)
      if (right == NULL)
        return NULL;
        return NULL;
      break;
      break;
 
 
      /* These are allowed to have no parameters--in some cases they
      /* These are allowed to have no parameters--in some cases they
         will be filled in later.  */
         will be filled in later.  */
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
      break;
      break;
 
 
      /* Other types should not be seen here.  */
      /* Other types should not be seen here.  */
    default:
    default:
      return NULL;
      return NULL;
    }
    }
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = type;
      p->type = type;
      p->u.s_binary.left = left;
      p->u.s_binary.left = left;
      p->u.s_binary.right = right;
      p->u.s_binary.right = right;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new name component.  */
/* Add a new name component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_name (struct d_info *di, const char *s, int len)
d_make_name (struct d_info *di, const char *s, int len)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (! cplus_demangle_fill_name (p, s, len))
  if (! cplus_demangle_fill_name (p, s, len))
    return NULL;
    return NULL;
  return p;
  return p;
}
}
 
 
/* Add a new builtin type component.  */
/* Add a new builtin type component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_builtin_type (struct d_info *di,
d_make_builtin_type (struct d_info *di,
                     const struct demangle_builtin_type_info *type)
                     const struct demangle_builtin_type_info *type)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  if (type == NULL)
  if (type == NULL)
    return NULL;
    return NULL;
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
      p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
      p->u.s_builtin.type = type;
      p->u.s_builtin.type = type;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new operator component.  */
/* Add a new operator component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_operator (struct d_info *di, const struct demangle_operator_info *op)
d_make_operator (struct d_info *di, const struct demangle_operator_info *op)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_OPERATOR;
      p->type = DEMANGLE_COMPONENT_OPERATOR;
      p->u.s_operator.op = op;
      p->u.s_operator.op = op;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new extended operator component.  */
/* Add a new extended operator component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_extended_operator (struct d_info *di, int args,
d_make_extended_operator (struct d_info *di, int args,
                          struct demangle_component *name)
                          struct demangle_component *name)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (! cplus_demangle_fill_extended_operator (p, args, name))
  if (! cplus_demangle_fill_extended_operator (p, args, name))
    return NULL;
    return NULL;
  return p;
  return p;
}
}
 
 
static struct demangle_component *
static struct demangle_component *
d_make_default_arg (struct d_info *di, int num,
d_make_default_arg (struct d_info *di, int num,
                    struct demangle_component *sub)
                    struct demangle_component *sub)
{
{
  struct demangle_component *p = d_make_empty (di);
  struct demangle_component *p = d_make_empty (di);
  if (p)
  if (p)
    {
    {
      p->type = DEMANGLE_COMPONENT_DEFAULT_ARG;
      p->type = DEMANGLE_COMPONENT_DEFAULT_ARG;
      p->u.s_unary_num.num = num;
      p->u.s_unary_num.num = num;
      p->u.s_unary_num.sub = sub;
      p->u.s_unary_num.sub = sub;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new constructor component.  */
/* Add a new constructor component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind,
d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind,
             struct demangle_component *name)
             struct demangle_component *name)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (! cplus_demangle_fill_ctor (p, kind, name))
  if (! cplus_demangle_fill_ctor (p, kind, name))
    return NULL;
    return NULL;
  return p;
  return p;
}
}
 
 
/* Add a new destructor component.  */
/* Add a new destructor component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind,
d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind,
             struct demangle_component *name)
             struct demangle_component *name)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (! cplus_demangle_fill_dtor (p, kind, name))
  if (! cplus_demangle_fill_dtor (p, kind, name))
    return NULL;
    return NULL;
  return p;
  return p;
}
}
 
 
/* Add a new template parameter.  */
/* Add a new template parameter.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_template_param (struct d_info *di, long i)
d_make_template_param (struct d_info *di, long i)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM;
      p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM;
      p->u.s_number.number = i;
      p->u.s_number.number = i;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new function parameter.  */
/* Add a new function parameter.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_function_param (struct d_info *di, long i)
d_make_function_param (struct d_info *di, long i)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM;
      p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM;
      p->u.s_number.number = i;
      p->u.s_number.number = i;
    }
    }
  return p;
  return p;
}
}
 
 
/* Add a new standard substitution component.  */
/* Add a new standard substitution component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_make_sub (struct d_info *di, const char *name, int len)
d_make_sub (struct d_info *di, const char *name, int len)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
 
 
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_SUB_STD;
      p->type = DEMANGLE_COMPONENT_SUB_STD;
      p->u.s_string.string = name;
      p->u.s_string.string = name;
      p->u.s_string.len = len;
      p->u.s_string.len = len;
    }
    }
  return p;
  return p;
}
}
 
 
/* <mangled-name> ::= _Z <encoding>
/* <mangled-name> ::= _Z <encoding>
 
 
   TOP_LEVEL is non-zero when called at the top level.  */
   TOP_LEVEL is non-zero when called at the top level.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
struct demangle_component *
cplus_demangle_mangled_name (struct d_info *di, int top_level)
cplus_demangle_mangled_name (struct d_info *di, int top_level)
{
{
  if (! d_check_char (di, '_')
  if (! d_check_char (di, '_')
      /* Allow missing _ if not at toplevel to work around a
      /* Allow missing _ if not at toplevel to work around a
         bug in G++ abi-version=2 mangling; see the comment in
         bug in G++ abi-version=2 mangling; see the comment in
         write_template_arg.  */
         write_template_arg.  */
      && top_level)
      && top_level)
    return NULL;
    return NULL;
  if (! d_check_char (di, 'Z'))
  if (! d_check_char (di, 'Z'))
    return NULL;
    return NULL;
  return d_encoding (di, top_level);
  return d_encoding (di, top_level);
}
}
 
 
/* Return whether a function should have a return type.  The argument
/* Return whether a function should have a return type.  The argument
   is the function name, which may be qualified in various ways.  The
   is the function name, which may be qualified in various ways.  The
   rules are that template functions have return types with some
   rules are that template functions have return types with some
   exceptions, function types which are not part of a function name
   exceptions, function types which are not part of a function name
   mangling have return types with some exceptions, and non-template
   mangling have return types with some exceptions, and non-template
   function names do not have return types.  The exceptions are that
   function names do not have return types.  The exceptions are that
   constructors, destructors, and conversion operators do not have
   constructors, destructors, and conversion operators do not have
   return types.  */
   return types.  */
 
 
static int
static int
has_return_type (struct demangle_component *dc)
has_return_type (struct demangle_component *dc)
{
{
  if (dc == NULL)
  if (dc == NULL)
    return 0;
    return 0;
  switch (dc->type)
  switch (dc->type)
    {
    {
    default:
    default:
      return 0;
      return 0;
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_TEMPLATE:
      return ! is_ctor_dtor_or_conversion (d_left (dc));
      return ! is_ctor_dtor_or_conversion (d_left (dc));
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
      return has_return_type (d_left (dc));
      return has_return_type (d_left (dc));
    }
    }
}
}
 
 
/* Return whether a name is a constructor, a destructor, or a
/* Return whether a name is a constructor, a destructor, or a
   conversion operator.  */
   conversion operator.  */
 
 
static int
static int
is_ctor_dtor_or_conversion (struct demangle_component *dc)
is_ctor_dtor_or_conversion (struct demangle_component *dc)
{
{
  if (dc == NULL)
  if (dc == NULL)
    return 0;
    return 0;
  switch (dc->type)
  switch (dc->type)
    {
    {
    default:
    default:
      return 0;
      return 0;
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
      return is_ctor_dtor_or_conversion (d_right (dc));
      return is_ctor_dtor_or_conversion (d_right (dc));
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_CAST:
    case DEMANGLE_COMPONENT_CAST:
      return 1;
      return 1;
    }
    }
}
}
 
 
/* <encoding> ::= <(function) name> <bare-function-type>
/* <encoding> ::= <(function) name> <bare-function-type>
              ::= <(data) name>
              ::= <(data) name>
              ::= <special-name>
              ::= <special-name>
 
 
   TOP_LEVEL is non-zero when called at the top level, in which case
   TOP_LEVEL is non-zero when called at the top level, in which case
   if DMGL_PARAMS is not set we do not demangle the function
   if DMGL_PARAMS is not set we do not demangle the function
   parameters.  We only set this at the top level, because otherwise
   parameters.  We only set this at the top level, because otherwise
   we would not correctly demangle names in local scopes.  */
   we would not correctly demangle names in local scopes.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_encoding (struct d_info *di, int top_level)
d_encoding (struct d_info *di, int top_level)
{
{
  char peek = d_peek_char (di);
  char peek = d_peek_char (di);
 
 
  if (peek == 'G' || peek == 'T')
  if (peek == 'G' || peek == 'T')
    return d_special_name (di);
    return d_special_name (di);
  else
  else
    {
    {
      struct demangle_component *dc;
      struct demangle_component *dc;
 
 
      dc = d_name (di);
      dc = d_name (di);
 
 
      if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
      if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
        {
        {
          /* Strip off any initial CV-qualifiers, as they really apply
          /* Strip off any initial CV-qualifiers, as they really apply
             to the `this' parameter, and they were not output by the
             to the `this' parameter, and they were not output by the
             v2 demangler without DMGL_PARAMS.  */
             v2 demangler without DMGL_PARAMS.  */
          while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
          while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
                 || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                 || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                 || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
                 || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
            dc = d_left (dc);
            dc = d_left (dc);
 
 
          /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
          /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
             there may be CV-qualifiers on its right argument which
             there may be CV-qualifiers on its right argument which
             really apply here; this happens when parsing a class
             really apply here; this happens when parsing a class
             which is local to a function.  */
             which is local to a function.  */
          if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
          if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
            {
            {
              struct demangle_component *dcr;
              struct demangle_component *dcr;
 
 
              dcr = d_right (dc);
              dcr = d_right (dc);
              while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
              while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
                     || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                     || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                     || dcr->type == DEMANGLE_COMPONENT_CONST_THIS)
                     || dcr->type == DEMANGLE_COMPONENT_CONST_THIS)
                dcr = d_left (dcr);
                dcr = d_left (dcr);
              dc->u.s_binary.right = dcr;
              dc->u.s_binary.right = dcr;
            }
            }
 
 
          return dc;
          return dc;
        }
        }
 
 
      peek = d_peek_char (di);
      peek = d_peek_char (di);
      if (dc == NULL || peek == '\0' || peek == 'E')
      if (dc == NULL || peek == '\0' || peek == 'E')
        return dc;
        return dc;
      return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc,
      return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc,
                          d_bare_function_type (di, has_return_type (dc)));
                          d_bare_function_type (di, has_return_type (dc)));
    }
    }
}
}
 
 
/* <name> ::= <nested-name>
/* <name> ::= <nested-name>
          ::= <unscoped-name>
          ::= <unscoped-name>
          ::= <unscoped-template-name> <template-args>
          ::= <unscoped-template-name> <template-args>
          ::= <local-name>
          ::= <local-name>
 
 
   <unscoped-name> ::= <unqualified-name>
   <unscoped-name> ::= <unqualified-name>
                   ::= St <unqualified-name>
                   ::= St <unqualified-name>
 
 
   <unscoped-template-name> ::= <unscoped-name>
   <unscoped-template-name> ::= <unscoped-name>
                            ::= <substitution>
                            ::= <substitution>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_name (struct d_info *di)
d_name (struct d_info *di)
{
{
  char peek = d_peek_char (di);
  char peek = d_peek_char (di);
  struct demangle_component *dc;
  struct demangle_component *dc;
 
 
  switch (peek)
  switch (peek)
    {
    {
    case 'N':
    case 'N':
      return d_nested_name (di);
      return d_nested_name (di);
 
 
    case 'Z':
    case 'Z':
      return d_local_name (di);
      return d_local_name (di);
 
 
    case 'L':
    case 'L':
    case 'U':
    case 'U':
      return d_unqualified_name (di);
      return d_unqualified_name (di);
 
 
    case 'S':
    case 'S':
      {
      {
        int subst;
        int subst;
 
 
        if (d_peek_next_char (di) != 't')
        if (d_peek_next_char (di) != 't')
          {
          {
            dc = d_substitution (di, 0);
            dc = d_substitution (di, 0);
            subst = 1;
            subst = 1;
          }
          }
        else
        else
          {
          {
            d_advance (di, 2);
            d_advance (di, 2);
            dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME,
            dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME,
                              d_make_name (di, "std", 3),
                              d_make_name (di, "std", 3),
                              d_unqualified_name (di));
                              d_unqualified_name (di));
            di->expansion += 3;
            di->expansion += 3;
            subst = 0;
            subst = 0;
          }
          }
 
 
        if (d_peek_char (di) != 'I')
        if (d_peek_char (di) != 'I')
          {
          {
            /* The grammar does not permit this case to occur if we
            /* The grammar does not permit this case to occur if we
               called d_substitution() above (i.e., subst == 1).  We
               called d_substitution() above (i.e., subst == 1).  We
               don't bother to check.  */
               don't bother to check.  */
          }
          }
        else
        else
          {
          {
            /* This is <template-args>, which means that we just saw
            /* This is <template-args>, which means that we just saw
               <unscoped-template-name>, which is a substitution
               <unscoped-template-name>, which is a substitution
               candidate if we didn't just get it from a
               candidate if we didn't just get it from a
               substitution.  */
               substitution.  */
            if (! subst)
            if (! subst)
              {
              {
                if (! d_add_substitution (di, dc))
                if (! d_add_substitution (di, dc))
                  return NULL;
                  return NULL;
              }
              }
            dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
            dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
                              d_template_args (di));
                              d_template_args (di));
          }
          }
 
 
        return dc;
        return dc;
      }
      }
 
 
    default:
    default:
      dc = d_unqualified_name (di);
      dc = d_unqualified_name (di);
      if (d_peek_char (di) == 'I')
      if (d_peek_char (di) == 'I')
        {
        {
          /* This is <template-args>, which means that we just saw
          /* This is <template-args>, which means that we just saw
             <unscoped-template-name>, which is a substitution
             <unscoped-template-name>, which is a substitution
             candidate.  */
             candidate.  */
          if (! d_add_substitution (di, dc))
          if (! d_add_substitution (di, dc))
            return NULL;
            return NULL;
          dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
          dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
                            d_template_args (di));
                            d_template_args (di));
        }
        }
      return dc;
      return dc;
    }
    }
}
}
 
 
/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
                 ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
                 ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_nested_name (struct d_info *di)
d_nested_name (struct d_info *di)
{
{
  struct demangle_component *ret;
  struct demangle_component *ret;
  struct demangle_component **pret;
  struct demangle_component **pret;
 
 
  if (! d_check_char (di, 'N'))
  if (! d_check_char (di, 'N'))
    return NULL;
    return NULL;
 
 
  pret = d_cv_qualifiers (di, &ret, 1);
  pret = d_cv_qualifiers (di, &ret, 1);
  if (pret == NULL)
  if (pret == NULL)
    return NULL;
    return NULL;
 
 
  *pret = d_prefix (di);
  *pret = d_prefix (di);
  if (*pret == NULL)
  if (*pret == NULL)
    return NULL;
    return NULL;
 
 
  if (! d_check_char (di, 'E'))
  if (! d_check_char (di, 'E'))
    return NULL;
    return NULL;
 
 
  return ret;
  return ret;
}
}
 
 
/* <prefix> ::= <prefix> <unqualified-name>
/* <prefix> ::= <prefix> <unqualified-name>
            ::= <template-prefix> <template-args>
            ::= <template-prefix> <template-args>
            ::= <template-param>
            ::= <template-param>
            ::=
            ::=
            ::= <substitution>
            ::= <substitution>
 
 
   <template-prefix> ::= <prefix> <(template) unqualified-name>
   <template-prefix> ::= <prefix> <(template) unqualified-name>
                     ::= <template-param>
                     ::= <template-param>
                     ::= <substitution>
                     ::= <substitution>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_prefix (struct d_info *di)
d_prefix (struct d_info *di)
{
{
  struct demangle_component *ret = NULL;
  struct demangle_component *ret = NULL;
 
 
  while (1)
  while (1)
    {
    {
      char peek;
      char peek;
      enum demangle_component_type comb_type;
      enum demangle_component_type comb_type;
      struct demangle_component *dc;
      struct demangle_component *dc;
 
 
      peek = d_peek_char (di);
      peek = d_peek_char (di);
      if (peek == '\0')
      if (peek == '\0')
        return NULL;
        return NULL;
 
 
      /* The older code accepts a <local-name> here, but I don't see
      /* The older code accepts a <local-name> here, but I don't see
         that in the grammar.  The older code does not accept a
         that in the grammar.  The older code does not accept a
         <template-param> here.  */
         <template-param> here.  */
 
 
      comb_type = DEMANGLE_COMPONENT_QUAL_NAME;
      comb_type = DEMANGLE_COMPONENT_QUAL_NAME;
      if (IS_DIGIT (peek)
      if (IS_DIGIT (peek)
          || IS_LOWER (peek)
          || IS_LOWER (peek)
          || peek == 'C'
          || peek == 'C'
          || peek == 'D'
          || peek == 'D'
          || peek == 'U'
          || peek == 'U'
          || peek == 'L')
          || peek == 'L')
        dc = d_unqualified_name (di);
        dc = d_unqualified_name (di);
      else if (peek == 'S')
      else if (peek == 'S')
        dc = d_substitution (di, 1);
        dc = d_substitution (di, 1);
      else if (peek == 'I')
      else if (peek == 'I')
        {
        {
          if (ret == NULL)
          if (ret == NULL)
            return NULL;
            return NULL;
          comb_type = DEMANGLE_COMPONENT_TEMPLATE;
          comb_type = DEMANGLE_COMPONENT_TEMPLATE;
          dc = d_template_args (di);
          dc = d_template_args (di);
        }
        }
      else if (peek == 'T')
      else if (peek == 'T')
        dc = d_template_param (di);
        dc = d_template_param (di);
      else if (peek == 'E')
      else if (peek == 'E')
        return ret;
        return ret;
      else if (peek == 'M')
      else if (peek == 'M')
        {
        {
          /* Initializer scope for a lambda.  We don't need to represent
          /* Initializer scope for a lambda.  We don't need to represent
             this; the normal code will just treat the variable as a type
             this; the normal code will just treat the variable as a type
             scope, which gives appropriate output.  */
             scope, which gives appropriate output.  */
          if (ret == NULL)
          if (ret == NULL)
            return NULL;
            return NULL;
          d_advance (di, 1);
          d_advance (di, 1);
          continue;
          continue;
        }
        }
      else
      else
        return NULL;
        return NULL;
 
 
      if (ret == NULL)
      if (ret == NULL)
        ret = dc;
        ret = dc;
      else
      else
        ret = d_make_comp (di, comb_type, ret, dc);
        ret = d_make_comp (di, comb_type, ret, dc);
 
 
      if (peek != 'S' && d_peek_char (di) != 'E')
      if (peek != 'S' && d_peek_char (di) != 'E')
        {
        {
          if (! d_add_substitution (di, ret))
          if (! d_add_substitution (di, ret))
            return NULL;
            return NULL;
        }
        }
    }
    }
}
}
 
 
/* <unqualified-name> ::= <operator-name>
/* <unqualified-name> ::= <operator-name>
                      ::= <ctor-dtor-name>
                      ::= <ctor-dtor-name>
                      ::= <source-name>
                      ::= <source-name>
                      ::= <local-source-name>
                      ::= <local-source-name>
 
 
    <local-source-name> ::= L <source-name> <discriminator>
    <local-source-name> ::= L <source-name> <discriminator>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_unqualified_name (struct d_info *di)
d_unqualified_name (struct d_info *di)
{
{
  char peek;
  char peek;
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (IS_DIGIT (peek))
  if (IS_DIGIT (peek))
    return d_source_name (di);
    return d_source_name (di);
  else if (IS_LOWER (peek))
  else if (IS_LOWER (peek))
    {
    {
      struct demangle_component *ret;
      struct demangle_component *ret;
 
 
      ret = d_operator_name (di);
      ret = d_operator_name (di);
      if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
      if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
        di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
        di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
      return ret;
      return ret;
    }
    }
  else if (peek == 'C' || peek == 'D')
  else if (peek == 'C' || peek == 'D')
    return d_ctor_dtor_name (di);
    return d_ctor_dtor_name (di);
  else if (peek == 'L')
  else if (peek == 'L')
    {
    {
      struct demangle_component * ret;
      struct demangle_component * ret;
 
 
      d_advance (di, 1);
      d_advance (di, 1);
 
 
      ret = d_source_name (di);
      ret = d_source_name (di);
      if (ret == NULL)
      if (ret == NULL)
        return NULL;
        return NULL;
      if (! d_discriminator (di))
      if (! d_discriminator (di))
        return NULL;
        return NULL;
      return ret;
      return ret;
    }
    }
  else if (peek == 'U')
  else if (peek == 'U')
    {
    {
      switch (d_peek_next_char (di))
      switch (d_peek_next_char (di))
        {
        {
        case 'l':
        case 'l':
          return d_lambda (di);
          return d_lambda (di);
        case 't':
        case 't':
          return d_unnamed_type (di);
          return d_unnamed_type (di);
        default:
        default:
          return NULL;
          return NULL;
        }
        }
    }
    }
  else
  else
    return NULL;
    return NULL;
}
}
 
 
/* <source-name> ::= <(positive length) number> <identifier>  */
/* <source-name> ::= <(positive length) number> <identifier>  */
 
 
static struct demangle_component *
static struct demangle_component *
d_source_name (struct d_info *di)
d_source_name (struct d_info *di)
{
{
  long len;
  long len;
  struct demangle_component *ret;
  struct demangle_component *ret;
 
 
  len = d_number (di);
  len = d_number (di);
  if (len <= 0)
  if (len <= 0)
    return NULL;
    return NULL;
  ret = d_identifier (di, len);
  ret = d_identifier (di, len);
  di->last_name = ret;
  di->last_name = ret;
  return ret;
  return ret;
}
}
 
 
/* number ::= [n] <(non-negative decimal integer)>  */
/* number ::= [n] <(non-negative decimal integer)>  */
 
 
static long
static long
d_number (struct d_info *di)
d_number (struct d_info *di)
{
{
  int negative;
  int negative;
  char peek;
  char peek;
  long ret;
  long ret;
 
 
  negative = 0;
  negative = 0;
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == 'n')
  if (peek == 'n')
    {
    {
      negative = 1;
      negative = 1;
      d_advance (di, 1);
      d_advance (di, 1);
      peek = d_peek_char (di);
      peek = d_peek_char (di);
    }
    }
 
 
  ret = 0;
  ret = 0;
  while (1)
  while (1)
    {
    {
      if (! IS_DIGIT (peek))
      if (! IS_DIGIT (peek))
        {
        {
          if (negative)
          if (negative)
            ret = - ret;
            ret = - ret;
          return ret;
          return ret;
        }
        }
      ret = ret * 10 + peek - '0';
      ret = ret * 10 + peek - '0';
      d_advance (di, 1);
      d_advance (di, 1);
      peek = d_peek_char (di);
      peek = d_peek_char (di);
    }
    }
}
}
 
 
/* Like d_number, but returns a demangle_component.  */
/* Like d_number, but returns a demangle_component.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_number_component (struct d_info *di)
d_number_component (struct d_info *di)
{
{
  struct demangle_component *ret = d_make_empty (di);
  struct demangle_component *ret = d_make_empty (di);
  if (ret)
  if (ret)
    {
    {
      ret->type = DEMANGLE_COMPONENT_NUMBER;
      ret->type = DEMANGLE_COMPONENT_NUMBER;
      ret->u.s_number.number = d_number (di);
      ret->u.s_number.number = d_number (di);
    }
    }
  return ret;
  return ret;
}
}
 
 
/* identifier ::= <(unqualified source code identifier)>  */
/* identifier ::= <(unqualified source code identifier)>  */
 
 
static struct demangle_component *
static struct demangle_component *
d_identifier (struct d_info *di, int len)
d_identifier (struct d_info *di, int len)
{
{
  const char *name;
  const char *name;
 
 
  name = d_str (di);
  name = d_str (di);
 
 
  if (di->send - name < len)
  if (di->send - name < len)
    return NULL;
    return NULL;
 
 
  d_advance (di, len);
  d_advance (di, len);
 
 
  /* A Java mangled name may have a trailing '$' if it is a C++
  /* A Java mangled name may have a trailing '$' if it is a C++
     keyword.  This '$' is not included in the length count.  We just
     keyword.  This '$' is not included in the length count.  We just
     ignore the '$'.  */
     ignore the '$'.  */
  if ((di->options & DMGL_JAVA) != 0
  if ((di->options & DMGL_JAVA) != 0
      && d_peek_char (di) == '$')
      && d_peek_char (di) == '$')
    d_advance (di, 1);
    d_advance (di, 1);
 
 
  /* Look for something which looks like a gcc encoding of an
  /* Look for something which looks like a gcc encoding of an
     anonymous namespace, and replace it with a more user friendly
     anonymous namespace, and replace it with a more user friendly
     name.  */
     name.  */
  if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
  if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
      && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
      && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
                 ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
                 ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
    {
    {
      const char *s;
      const char *s;
 
 
      s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN;
      s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN;
      if ((*s == '.' || *s == '_' || *s == '$')
      if ((*s == '.' || *s == '_' || *s == '$')
          && s[1] == 'N')
          && s[1] == 'N')
        {
        {
          di->expansion -= len - sizeof "(anonymous namespace)";
          di->expansion -= len - sizeof "(anonymous namespace)";
          return d_make_name (di, "(anonymous namespace)",
          return d_make_name (di, "(anonymous namespace)",
                              sizeof "(anonymous namespace)" - 1);
                              sizeof "(anonymous namespace)" - 1);
        }
        }
    }
    }
 
 
  return d_make_name (di, name, len);
  return d_make_name (di, name, len);
}
}
 
 
/* operator_name ::= many different two character encodings.
/* operator_name ::= many different two character encodings.
                 ::= cv <type>
                 ::= cv <type>
                 ::= v <digit> <source-name>
                 ::= v <digit> <source-name>
*/
*/
 
 
#define NL(s) s, (sizeof s) - 1
#define NL(s) s, (sizeof s) - 1
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
const struct demangle_operator_info cplus_demangle_operators[] =
const struct demangle_operator_info cplus_demangle_operators[] =
{
{
  { "aN", NL ("&="),        2 },
  { "aN", NL ("&="),        2 },
  { "aS", NL ("="),         2 },
  { "aS", NL ("="),         2 },
  { "aa", NL ("&&"),        2 },
  { "aa", NL ("&&"),        2 },
  { "ad", NL ("&"),         1 },
  { "ad", NL ("&"),         1 },
  { "an", NL ("&"),         2 },
  { "an", NL ("&"),         2 },
  { "cl", NL ("()"),        2 },
  { "cl", NL ("()"),        2 },
  { "cm", NL (","),         2 },
  { "cm", NL (","),         2 },
  { "co", NL ("~"),         1 },
  { "co", NL ("~"),         1 },
  { "dV", NL ("/="),        2 },
  { "dV", NL ("/="),        2 },
  { "da", NL ("delete[]"),  1 },
  { "da", NL ("delete[]"),  1 },
  { "de", NL ("*"),         1 },
  { "de", NL ("*"),         1 },
  { "dl", NL ("delete"),    1 },
  { "dl", NL ("delete"),    1 },
  { "dt", NL ("."),         2 },
  { "dt", NL ("."),         2 },
  { "dv", NL ("/"),         2 },
  { "dv", NL ("/"),         2 },
  { "eO", NL ("^="),        2 },
  { "eO", NL ("^="),        2 },
  { "eo", NL ("^"),         2 },
  { "eo", NL ("^"),         2 },
  { "eq", NL ("=="),        2 },
  { "eq", NL ("=="),        2 },
  { "ge", NL (">="),        2 },
  { "ge", NL (">="),        2 },
  { "gt", NL (">"),         2 },
  { "gt", NL (">"),         2 },
  { "ix", NL ("[]"),        2 },
  { "ix", NL ("[]"),        2 },
  { "lS", NL ("<<="),       2 },
  { "lS", NL ("<<="),       2 },
  { "le", NL ("<="),        2 },
  { "le", NL ("<="),        2 },
  { "ls", NL ("<<"),        2 },
  { "ls", NL ("<<"),        2 },
  { "lt", NL ("<"),         2 },
  { "lt", NL ("<"),         2 },
  { "mI", NL ("-="),        2 },
  { "mI", NL ("-="),        2 },
  { "mL", NL ("*="),        2 },
  { "mL", NL ("*="),        2 },
  { "mi", NL ("-"),         2 },
  { "mi", NL ("-"),         2 },
  { "ml", NL ("*"),         2 },
  { "ml", NL ("*"),         2 },
  { "mm", NL ("--"),        1 },
  { "mm", NL ("--"),        1 },
  { "na", NL ("new[]"),     1 },
  { "na", NL ("new[]"),     1 },
  { "ne", NL ("!="),        2 },
  { "ne", NL ("!="),        2 },
  { "ng", NL ("-"),         1 },
  { "ng", NL ("-"),         1 },
  { "nt", NL ("!"),         1 },
  { "nt", NL ("!"),         1 },
  { "nw", NL ("new"),       1 },
  { "nw", NL ("new"),       1 },
  { "oR", NL ("|="),        2 },
  { "oR", NL ("|="),        2 },
  { "oo", NL ("||"),        2 },
  { "oo", NL ("||"),        2 },
  { "or", NL ("|"),         2 },
  { "or", NL ("|"),         2 },
  { "pL", NL ("+="),        2 },
  { "pL", NL ("+="),        2 },
  { "pl", NL ("+"),         2 },
  { "pl", NL ("+"),         2 },
  { "pm", NL ("->*"),       2 },
  { "pm", NL ("->*"),       2 },
  { "pp", NL ("++"),        1 },
  { "pp", NL ("++"),        1 },
  { "ps", NL ("+"),         1 },
  { "ps", NL ("+"),         1 },
  { "pt", NL ("->"),        2 },
  { "pt", NL ("->"),        2 },
  { "qu", NL ("?"),         3 },
  { "qu", NL ("?"),         3 },
  { "rM", NL ("%="),        2 },
  { "rM", NL ("%="),        2 },
  { "rS", NL (">>="),       2 },
  { "rS", NL (">>="),       2 },
  { "rm", NL ("%"),         2 },
  { "rm", NL ("%"),         2 },
  { "rs", NL (">>"),        2 },
  { "rs", NL (">>"),        2 },
  { "st", NL ("sizeof "),   1 },
  { "st", NL ("sizeof "),   1 },
  { "sz", NL ("sizeof "),   1 },
  { "sz", NL ("sizeof "),   1 },
  { "at", NL ("alignof "),   1 },
  { "at", NL ("alignof "),   1 },
  { "az", NL ("alignof "),   1 },
  { "az", NL ("alignof "),   1 },
  { NULL, NULL, 0,          0 }
  { NULL, NULL, 0,          0 }
};
};
 
 
static struct demangle_component *
static struct demangle_component *
d_operator_name (struct d_info *di)
d_operator_name (struct d_info *di)
{
{
  char c1;
  char c1;
  char c2;
  char c2;
 
 
  c1 = d_next_char (di);
  c1 = d_next_char (di);
  c2 = d_next_char (di);
  c2 = d_next_char (di);
  if (c1 == 'v' && IS_DIGIT (c2))
  if (c1 == 'v' && IS_DIGIT (c2))
    return d_make_extended_operator (di, c2 - '0', d_source_name (di));
    return d_make_extended_operator (di, c2 - '0', d_source_name (di));
  else if (c1 == 'c' && c2 == 'v')
  else if (c1 == 'c' && c2 == 'v')
    return d_make_comp (di, DEMANGLE_COMPONENT_CAST,
    return d_make_comp (di, DEMANGLE_COMPONENT_CAST,
                        cplus_demangle_type (di), NULL);
                        cplus_demangle_type (di), NULL);
  else
  else
    {
    {
      /* LOW is the inclusive lower bound.  */
      /* LOW is the inclusive lower bound.  */
      int low = 0;
      int low = 0;
      /* HIGH is the exclusive upper bound.  We subtract one to ignore
      /* HIGH is the exclusive upper bound.  We subtract one to ignore
         the sentinel at the end of the array.  */
         the sentinel at the end of the array.  */
      int high = ((sizeof (cplus_demangle_operators)
      int high = ((sizeof (cplus_demangle_operators)
                   / sizeof (cplus_demangle_operators[0]))
                   / sizeof (cplus_demangle_operators[0]))
                  - 1);
                  - 1);
 
 
      while (1)
      while (1)
        {
        {
          int i;
          int i;
          const struct demangle_operator_info *p;
          const struct demangle_operator_info *p;
 
 
          i = low + (high - low) / 2;
          i = low + (high - low) / 2;
          p = cplus_demangle_operators + i;
          p = cplus_demangle_operators + i;
 
 
          if (c1 == p->code[0] && c2 == p->code[1])
          if (c1 == p->code[0] && c2 == p->code[1])
            return d_make_operator (di, p);
            return d_make_operator (di, p);
 
 
          if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1]))
          if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1]))
            high = i;
            high = i;
          else
          else
            low = i + 1;
            low = i + 1;
          if (low == high)
          if (low == high)
            return NULL;
            return NULL;
        }
        }
    }
    }
}
}
 
 
static struct demangle_component *
static struct demangle_component *
d_make_character (struct d_info *di, int c)
d_make_character (struct d_info *di, int c)
{
{
  struct demangle_component *p;
  struct demangle_component *p;
  p = d_make_empty (di);
  p = d_make_empty (di);
  if (p != NULL)
  if (p != NULL)
    {
    {
      p->type = DEMANGLE_COMPONENT_CHARACTER;
      p->type = DEMANGLE_COMPONENT_CHARACTER;
      p->u.s_character.character = c;
      p->u.s_character.character = c;
    }
    }
  return p;
  return p;
}
}
 
 
static struct demangle_component *
static struct demangle_component *
d_java_resource (struct d_info *di)
d_java_resource (struct d_info *di)
{
{
  struct demangle_component *p = NULL;
  struct demangle_component *p = NULL;
  struct demangle_component *next = NULL;
  struct demangle_component *next = NULL;
  long len, i;
  long len, i;
  char c;
  char c;
  const char *str;
  const char *str;
 
 
  len = d_number (di);
  len = d_number (di);
  if (len <= 1)
  if (len <= 1)
    return NULL;
    return NULL;
 
 
  /* Eat the leading '_'.  */
  /* Eat the leading '_'.  */
  if (d_next_char (di) != '_')
  if (d_next_char (di) != '_')
    return NULL;
    return NULL;
  len--;
  len--;
 
 
  str = d_str (di);
  str = d_str (di);
  i = 0;
  i = 0;
 
 
  while (len > 0)
  while (len > 0)
    {
    {
      c = str[i];
      c = str[i];
      if (!c)
      if (!c)
        return NULL;
        return NULL;
 
 
      /* Each chunk is either a '$' escape...  */
      /* Each chunk is either a '$' escape...  */
      if (c == '$')
      if (c == '$')
        {
        {
          i++;
          i++;
          switch (str[i++])
          switch (str[i++])
            {
            {
            case 'S':
            case 'S':
              c = '/';
              c = '/';
              break;
              break;
            case '_':
            case '_':
              c = '.';
              c = '.';
              break;
              break;
            case '$':
            case '$':
              c = '$';
              c = '$';
              break;
              break;
            default:
            default:
              return NULL;
              return NULL;
            }
            }
          next = d_make_character (di, c);
          next = d_make_character (di, c);
          d_advance (di, i);
          d_advance (di, i);
          str = d_str (di);
          str = d_str (di);
          len -= i;
          len -= i;
          i = 0;
          i = 0;
          if (next == NULL)
          if (next == NULL)
            return NULL;
            return NULL;
        }
        }
      /* ... or a sequence of characters.  */
      /* ... or a sequence of characters.  */
      else
      else
        {
        {
          while (i < len && str[i] && str[i] != '$')
          while (i < len && str[i] && str[i] != '$')
            i++;
            i++;
 
 
          next = d_make_name (di, str, i);
          next = d_make_name (di, str, i);
          d_advance (di, i);
          d_advance (di, i);
          str = d_str (di);
          str = d_str (di);
          len -= i;
          len -= i;
          i = 0;
          i = 0;
          if (next == NULL)
          if (next == NULL)
            return NULL;
            return NULL;
        }
        }
 
 
      if (p == NULL)
      if (p == NULL)
        p = next;
        p = next;
      else
      else
        {
        {
          p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
          p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
          if (p == NULL)
          if (p == NULL)
            return NULL;
            return NULL;
        }
        }
    }
    }
 
 
  p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
  p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
 
 
  return p;
  return p;
}
}
 
 
/* <special-name> ::= TV <type>
/* <special-name> ::= TV <type>
                  ::= TT <type>
                  ::= TT <type>
                  ::= TI <type>
                  ::= TI <type>
                  ::= TS <type>
                  ::= TS <type>
                  ::= GV <(object) name>
                  ::= GV <(object) name>
                  ::= T <call-offset> <(base) encoding>
                  ::= T <call-offset> <(base) encoding>
                  ::= Tc <call-offset> <call-offset> <(base) encoding>
                  ::= Tc <call-offset> <call-offset> <(base) encoding>
   Also g++ extensions:
   Also g++ extensions:
                  ::= TC <type> <(offset) number> _ <(base) type>
                  ::= TC <type> <(offset) number> _ <(base) type>
                  ::= TF <type>
                  ::= TF <type>
                  ::= TJ <type>
                  ::= TJ <type>
                  ::= GR <name>
                  ::= GR <name>
                  ::= GA <encoding>
                  ::= GA <encoding>
                  ::= Gr <resource name>
                  ::= Gr <resource name>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_special_name (struct d_info *di)
d_special_name (struct d_info *di)
{
{
  di->expansion += 20;
  di->expansion += 20;
  if (d_check_char (di, 'T'))
  if (d_check_char (di, 'T'))
    {
    {
      switch (d_next_char (di))
      switch (d_next_char (di))
        {
        {
        case 'V':
        case 'V':
          di->expansion -= 5;
          di->expansion -= 5;
          return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE,
          return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
        case 'T':
        case 'T':
          di->expansion -= 10;
          di->expansion -= 10;
          return d_make_comp (di, DEMANGLE_COMPONENT_VTT,
          return d_make_comp (di, DEMANGLE_COMPONENT_VTT,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
        case 'I':
        case 'I':
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO,
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
        case 'S':
        case 'S':
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME,
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
 
 
        case 'h':
        case 'h':
          if (! d_call_offset (di, 'h'))
          if (! d_call_offset (di, 'h'))
            return NULL;
            return NULL;
          return d_make_comp (di, DEMANGLE_COMPONENT_THUNK,
          return d_make_comp (di, DEMANGLE_COMPONENT_THUNK,
                              d_encoding (di, 0), NULL);
                              d_encoding (di, 0), NULL);
 
 
        case 'v':
        case 'v':
          if (! d_call_offset (di, 'v'))
          if (! d_call_offset (di, 'v'))
            return NULL;
            return NULL;
          return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK,
          return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK,
                              d_encoding (di, 0), NULL);
                              d_encoding (di, 0), NULL);
 
 
        case 'c':
        case 'c':
          if (! d_call_offset (di, '\0'))
          if (! d_call_offset (di, '\0'))
            return NULL;
            return NULL;
          if (! d_call_offset (di, '\0'))
          if (! d_call_offset (di, '\0'))
            return NULL;
            return NULL;
          return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK,
          return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK,
                              d_encoding (di, 0), NULL);
                              d_encoding (di, 0), NULL);
 
 
        case 'C':
        case 'C':
          {
          {
            struct demangle_component *derived_type;
            struct demangle_component *derived_type;
            long offset;
            long offset;
            struct demangle_component *base_type;
            struct demangle_component *base_type;
 
 
            derived_type = cplus_demangle_type (di);
            derived_type = cplus_demangle_type (di);
            offset = d_number (di);
            offset = d_number (di);
            if (offset < 0)
            if (offset < 0)
              return NULL;
              return NULL;
            if (! d_check_char (di, '_'))
            if (! d_check_char (di, '_'))
              return NULL;
              return NULL;
            base_type = cplus_demangle_type (di);
            base_type = cplus_demangle_type (di);
            /* We don't display the offset.  FIXME: We should display
            /* We don't display the offset.  FIXME: We should display
               it in verbose mode.  */
               it in verbose mode.  */
            di->expansion += 5;
            di->expansion += 5;
            return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
            return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
                                base_type, derived_type);
                                base_type, derived_type);
          }
          }
 
 
        case 'F':
        case 'F':
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN,
          return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
        case 'J':
        case 'J':
          return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
          return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
                              cplus_demangle_type (di), NULL);
                              cplus_demangle_type (di), NULL);
 
 
        default:
        default:
          return NULL;
          return NULL;
        }
        }
    }
    }
  else if (d_check_char (di, 'G'))
  else if (d_check_char (di, 'G'))
    {
    {
      switch (d_next_char (di))
      switch (d_next_char (di))
        {
        {
        case 'V':
        case 'V':
          return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
          return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
 
 
        case 'R':
        case 'R':
          return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
          return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
                              NULL);
                              NULL);
 
 
        case 'A':
        case 'A':
          return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
          return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
                              d_encoding (di, 0), NULL);
                              d_encoding (di, 0), NULL);
 
 
        case 'r':
        case 'r':
          return d_java_resource (di);
          return d_java_resource (di);
 
 
        default:
        default:
          return NULL;
          return NULL;
        }
        }
    }
    }
  else
  else
    return NULL;
    return NULL;
}
}
 
 
/* <call-offset> ::= h <nv-offset> _
/* <call-offset> ::= h <nv-offset> _
                 ::= v <v-offset> _
                 ::= v <v-offset> _
 
 
   <nv-offset> ::= <(offset) number>
   <nv-offset> ::= <(offset) number>
 
 
   <v-offset> ::= <(offset) number> _ <(virtual offset) number>
   <v-offset> ::= <(offset) number> _ <(virtual offset) number>
 
 
   The C parameter, if not '\0', is a character we just read which is
   The C parameter, if not '\0', is a character we just read which is
   the start of the <call-offset>.
   the start of the <call-offset>.
 
 
   We don't display the offset information anywhere.  FIXME: We should
   We don't display the offset information anywhere.  FIXME: We should
   display it in verbose mode.  */
   display it in verbose mode.  */
 
 
static int
static int
d_call_offset (struct d_info *di, int c)
d_call_offset (struct d_info *di, int c)
{
{
  if (c == '\0')
  if (c == '\0')
    c = d_next_char (di);
    c = d_next_char (di);
 
 
  if (c == 'h')
  if (c == 'h')
    d_number (di);
    d_number (di);
  else if (c == 'v')
  else if (c == 'v')
    {
    {
      d_number (di);
      d_number (di);
      if (! d_check_char (di, '_'))
      if (! d_check_char (di, '_'))
        return 0;
        return 0;
      d_number (di);
      d_number (di);
    }
    }
  else
  else
    return 0;
    return 0;
 
 
  if (! d_check_char (di, '_'))
  if (! d_check_char (di, '_'))
    return 0;
    return 0;
 
 
  return 1;
  return 1;
}
}
 
 
/* <ctor-dtor-name> ::= C1
/* <ctor-dtor-name> ::= C1
                    ::= C2
                    ::= C2
                    ::= C3
                    ::= C3
                    ::= D0
                    ::= D0
                    ::= D1
                    ::= D1
                    ::= D2
                    ::= D2
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_ctor_dtor_name (struct d_info *di)
d_ctor_dtor_name (struct d_info *di)
{
{
  if (di->last_name != NULL)
  if (di->last_name != NULL)
    {
    {
      if (di->last_name->type == DEMANGLE_COMPONENT_NAME)
      if (di->last_name->type == DEMANGLE_COMPONENT_NAME)
        di->expansion += di->last_name->u.s_name.len;
        di->expansion += di->last_name->u.s_name.len;
      else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
      else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
        di->expansion += di->last_name->u.s_string.len;
        di->expansion += di->last_name->u.s_string.len;
    }
    }
  switch (d_peek_char (di))
  switch (d_peek_char (di))
    {
    {
    case 'C':
    case 'C':
      {
      {
        enum gnu_v3_ctor_kinds kind;
        enum gnu_v3_ctor_kinds kind;
 
 
        switch (d_peek_next_char (di))
        switch (d_peek_next_char (di))
          {
          {
          case '1':
          case '1':
            kind = gnu_v3_complete_object_ctor;
            kind = gnu_v3_complete_object_ctor;
            break;
            break;
          case '2':
          case '2':
            kind = gnu_v3_base_object_ctor;
            kind = gnu_v3_base_object_ctor;
            break;
            break;
          case '3':
          case '3':
            kind = gnu_v3_complete_object_allocating_ctor;
            kind = gnu_v3_complete_object_allocating_ctor;
            break;
            break;
          default:
          default:
            return NULL;
            return NULL;
          }
          }
        d_advance (di, 2);
        d_advance (di, 2);
        return d_make_ctor (di, kind, di->last_name);
        return d_make_ctor (di, kind, di->last_name);
      }
      }
 
 
    case 'D':
    case 'D':
      {
      {
        enum gnu_v3_dtor_kinds kind;
        enum gnu_v3_dtor_kinds kind;
 
 
        switch (d_peek_next_char (di))
        switch (d_peek_next_char (di))
          {
          {
          case '0':
          case '0':
            kind = gnu_v3_deleting_dtor;
            kind = gnu_v3_deleting_dtor;
            break;
            break;
          case '1':
          case '1':
            kind = gnu_v3_complete_object_dtor;
            kind = gnu_v3_complete_object_dtor;
            break;
            break;
          case '2':
          case '2':
            kind = gnu_v3_base_object_dtor;
            kind = gnu_v3_base_object_dtor;
            break;
            break;
          default:
          default:
            return NULL;
            return NULL;
          }
          }
        d_advance (di, 2);
        d_advance (di, 2);
        return d_make_dtor (di, kind, di->last_name);
        return d_make_dtor (di, kind, di->last_name);
      }
      }
 
 
    default:
    default:
      return NULL;
      return NULL;
    }
    }
}
}
 
 
/* <type> ::= <builtin-type>
/* <type> ::= <builtin-type>
          ::= <function-type>
          ::= <function-type>
          ::= <class-enum-type>
          ::= <class-enum-type>
          ::= <array-type>
          ::= <array-type>
          ::= <pointer-to-member-type>
          ::= <pointer-to-member-type>
          ::= <template-param>
          ::= <template-param>
          ::= <template-template-param> <template-args>
          ::= <template-template-param> <template-args>
          ::= <substitution>
          ::= <substitution>
          ::= <CV-qualifiers> <type>
          ::= <CV-qualifiers> <type>
          ::= P <type>
          ::= P <type>
          ::= R <type>
          ::= R <type>
          ::= O <type> (C++0x)
          ::= O <type> (C++0x)
          ::= C <type>
          ::= C <type>
          ::= G <type>
          ::= G <type>
          ::= U <source-name> <type>
          ::= U <source-name> <type>
 
 
   <builtin-type> ::= various one letter codes
   <builtin-type> ::= various one letter codes
                  ::= u <source-name>
                  ::= u <source-name>
*/
*/
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info
const struct demangle_builtin_type_info
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
{
{
  /* a */ { NL ("signed char"), NL ("signed char"),     D_PRINT_DEFAULT },
  /* a */ { NL ("signed char"), NL ("signed char"),     D_PRINT_DEFAULT },
  /* b */ { NL ("bool"),        NL ("boolean"),         D_PRINT_BOOL },
  /* b */ { NL ("bool"),        NL ("boolean"),         D_PRINT_BOOL },
  /* c */ { NL ("char"),        NL ("byte"),            D_PRINT_DEFAULT },
  /* c */ { NL ("char"),        NL ("byte"),            D_PRINT_DEFAULT },
  /* d */ { NL ("double"),      NL ("double"),          D_PRINT_FLOAT },
  /* d */ { NL ("double"),      NL ("double"),          D_PRINT_FLOAT },
  /* e */ { NL ("long double"), NL ("long double"),     D_PRINT_FLOAT },
  /* e */ { NL ("long double"), NL ("long double"),     D_PRINT_FLOAT },
  /* f */ { NL ("float"),       NL ("float"),           D_PRINT_FLOAT },
  /* f */ { NL ("float"),       NL ("float"),           D_PRINT_FLOAT },
  /* g */ { NL ("__float128"),  NL ("__float128"),      D_PRINT_FLOAT },
  /* g */ { NL ("__float128"),  NL ("__float128"),      D_PRINT_FLOAT },
  /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT },
  /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT },
  /* i */ { NL ("int"),         NL ("int"),             D_PRINT_INT },
  /* i */ { NL ("int"),         NL ("int"),             D_PRINT_INT },
  /* j */ { NL ("unsigned int"), NL ("unsigned"),       D_PRINT_UNSIGNED },
  /* j */ { NL ("unsigned int"), NL ("unsigned"),       D_PRINT_UNSIGNED },
  /* k */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* k */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* l */ { NL ("long"),        NL ("long"),            D_PRINT_LONG },
  /* l */ { NL ("long"),        NL ("long"),            D_PRINT_LONG },
  /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG },
  /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG },
  /* n */ { NL ("__int128"),    NL ("__int128"),        D_PRINT_DEFAULT },
  /* n */ { NL ("__int128"),    NL ("__int128"),        D_PRINT_DEFAULT },
  /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"),
  /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"),
            D_PRINT_DEFAULT },
            D_PRINT_DEFAULT },
  /* p */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* p */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* q */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* q */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* r */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* r */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* s */ { NL ("short"),       NL ("short"),           D_PRINT_DEFAULT },
  /* s */ { NL ("short"),       NL ("short"),           D_PRINT_DEFAULT },
  /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT },
  /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT },
  /* u */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* u */ { NULL, 0,             NULL, 0,         D_PRINT_DEFAULT },
  /* v */ { NL ("void"),        NL ("void"),            D_PRINT_VOID },
  /* v */ { NL ("void"),        NL ("void"),            D_PRINT_VOID },
  /* w */ { NL ("wchar_t"),     NL ("char"),            D_PRINT_DEFAULT },
  /* w */ { NL ("wchar_t"),     NL ("char"),            D_PRINT_DEFAULT },
  /* x */ { NL ("long long"),   NL ("long"),            D_PRINT_LONG_LONG },
  /* x */ { NL ("long long"),   NL ("long"),            D_PRINT_LONG_LONG },
  /* y */ { NL ("unsigned long long"), NL ("unsigned long long"),
  /* y */ { NL ("unsigned long long"), NL ("unsigned long long"),
            D_PRINT_UNSIGNED_LONG_LONG },
            D_PRINT_UNSIGNED_LONG_LONG },
  /* z */ { NL ("..."),         NL ("..."),             D_PRINT_DEFAULT },
  /* z */ { NL ("..."),         NL ("..."),             D_PRINT_DEFAULT },
  /* 26 */ { NL ("decimal32"),  NL ("decimal32"),       D_PRINT_DEFAULT },
  /* 26 */ { NL ("decimal32"),  NL ("decimal32"),       D_PRINT_DEFAULT },
  /* 27 */ { NL ("decimal64"),  NL ("decimal64"),       D_PRINT_DEFAULT },
  /* 27 */ { NL ("decimal64"),  NL ("decimal64"),       D_PRINT_DEFAULT },
  /* 28 */ { NL ("decimal128"), NL ("decimal128"),      D_PRINT_DEFAULT },
  /* 28 */ { NL ("decimal128"), NL ("decimal128"),      D_PRINT_DEFAULT },
  /* 29 */ { NL ("half"),       NL ("half"),            D_PRINT_FLOAT },
  /* 29 */ { NL ("half"),       NL ("half"),            D_PRINT_FLOAT },
  /* 30 */ { NL ("char16_t"),   NL ("char16_t"),        D_PRINT_DEFAULT },
  /* 30 */ { NL ("char16_t"),   NL ("char16_t"),        D_PRINT_DEFAULT },
  /* 31 */ { NL ("char32_t"),   NL ("char32_t"),        D_PRINT_DEFAULT },
  /* 31 */ { NL ("char32_t"),   NL ("char32_t"),        D_PRINT_DEFAULT },
};
};
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
struct demangle_component *
cplus_demangle_type (struct d_info *di)
cplus_demangle_type (struct d_info *di)
{
{
  char peek;
  char peek;
  struct demangle_component *ret;
  struct demangle_component *ret;
  int can_subst;
  int can_subst;
 
 
  /* The ABI specifies that when CV-qualifiers are used, the base type
  /* The ABI specifies that when CV-qualifiers are used, the base type
     is substitutable, and the fully qualified type is substitutable,
     is substitutable, and the fully qualified type is substitutable,
     but the base type with a strict subset of the CV-qualifiers is
     but the base type with a strict subset of the CV-qualifiers is
     not substitutable.  The natural recursive implementation of the
     not substitutable.  The natural recursive implementation of the
     CV-qualifiers would cause subsets to be substitutable, so instead
     CV-qualifiers would cause subsets to be substitutable, so instead
     we pull them all off now.
     we pull them all off now.
 
 
     FIXME: The ABI says that order-insensitive vendor qualifiers
     FIXME: The ABI says that order-insensitive vendor qualifiers
     should be handled in the same way, but we have no way to tell
     should be handled in the same way, but we have no way to tell
     which vendor qualifiers are order-insensitive and which are
     which vendor qualifiers are order-insensitive and which are
     order-sensitive.  So we just assume that they are all
     order-sensitive.  So we just assume that they are all
     order-sensitive.  g++ 3.4 supports only one vendor qualifier,
     order-sensitive.  g++ 3.4 supports only one vendor qualifier,
     __vector, and it treats it as order-sensitive when mangling
     __vector, and it treats it as order-sensitive when mangling
     names.  */
     names.  */
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == 'r' || peek == 'V' || peek == 'K')
  if (peek == 'r' || peek == 'V' || peek == 'K')
    {
    {
      struct demangle_component **pret;
      struct demangle_component **pret;
 
 
      pret = d_cv_qualifiers (di, &ret, 0);
      pret = d_cv_qualifiers (di, &ret, 0);
      if (pret == NULL)
      if (pret == NULL)
        return NULL;
        return NULL;
      *pret = cplus_demangle_type (di);
      *pret = cplus_demangle_type (di);
      if (! *pret || ! d_add_substitution (di, ret))
      if (! *pret || ! d_add_substitution (di, ret))
        return NULL;
        return NULL;
      return ret;
      return ret;
    }
    }
 
 
  can_subst = 1;
  can_subst = 1;
 
 
  switch (peek)
  switch (peek)
    {
    {
    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
    case 'h': case 'i': case 'j':           case 'l': case 'm': case 'n':
    case 'h': case 'i': case 'j':           case 'l': case 'm': case 'n':
    case 'o':                               case 's': case 't':
    case 'o':                               case 's': case 't':
    case 'v': case 'w': case 'x': case 'y': case 'z':
    case 'v': case 'w': case 'x': case 'y': case 'z':
      ret = d_make_builtin_type (di,
      ret = d_make_builtin_type (di,
                                 &cplus_demangle_builtin_types[peek - 'a']);
                                 &cplus_demangle_builtin_types[peek - 'a']);
      di->expansion += ret->u.s_builtin.type->len;
      di->expansion += ret->u.s_builtin.type->len;
      can_subst = 0;
      can_subst = 0;
      d_advance (di, 1);
      d_advance (di, 1);
      break;
      break;
 
 
    case 'u':
    case 'u':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE,
                         d_source_name (di), NULL);
                         d_source_name (di), NULL);
      break;
      break;
 
 
    case 'F':
    case 'F':
      ret = d_function_type (di);
      ret = d_function_type (di);
      break;
      break;
 
 
    case '0': case '1': case '2': case '3': case '4':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    case '5': case '6': case '7': case '8': case '9':
    case 'N':
    case 'N':
    case 'Z':
    case 'Z':
      ret = d_class_enum_type (di);
      ret = d_class_enum_type (di);
      break;
      break;
 
 
    case 'A':
    case 'A':
      ret = d_array_type (di);
      ret = d_array_type (di);
      break;
      break;
 
 
    case 'M':
    case 'M':
      ret = d_pointer_to_member_type (di);
      ret = d_pointer_to_member_type (di);
      break;
      break;
 
 
    case 'T':
    case 'T':
      ret = d_template_param (di);
      ret = d_template_param (di);
      if (d_peek_char (di) == 'I')
      if (d_peek_char (di) == 'I')
        {
        {
          /* This is <template-template-param> <template-args>.  The
          /* This is <template-template-param> <template-args>.  The
             <template-template-param> part is a substitution
             <template-template-param> part is a substitution
             candidate.  */
             candidate.  */
          if (! d_add_substitution (di, ret))
          if (! d_add_substitution (di, ret))
            return NULL;
            return NULL;
          ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
          ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
                             d_template_args (di));
                             d_template_args (di));
        }
        }
      break;
      break;
 
 
    case 'S':
    case 'S':
      /* If this is a special substitution, then it is the start of
      /* If this is a special substitution, then it is the start of
         <class-enum-type>.  */
         <class-enum-type>.  */
      {
      {
        char peek_next;
        char peek_next;
 
 
        peek_next = d_peek_next_char (di);
        peek_next = d_peek_next_char (di);
        if (IS_DIGIT (peek_next)
        if (IS_DIGIT (peek_next)
            || peek_next == '_'
            || peek_next == '_'
            || IS_UPPER (peek_next))
            || IS_UPPER (peek_next))
          {
          {
            ret = d_substitution (di, 0);
            ret = d_substitution (di, 0);
            /* The substituted name may have been a template name and
            /* The substituted name may have been a template name and
               may be followed by tepmlate args.  */
               may be followed by tepmlate args.  */
            if (d_peek_char (di) == 'I')
            if (d_peek_char (di) == 'I')
              ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
              ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
                                 d_template_args (di));
                                 d_template_args (di));
            else
            else
              can_subst = 0;
              can_subst = 0;
          }
          }
        else
        else
          {
          {
            ret = d_class_enum_type (di);
            ret = d_class_enum_type (di);
            /* If the substitution was a complete type, then it is not
            /* If the substitution was a complete type, then it is not
               a new substitution candidate.  However, if the
               a new substitution candidate.  However, if the
               substitution was followed by template arguments, then
               substitution was followed by template arguments, then
               the whole thing is a substitution candidate.  */
               the whole thing is a substitution candidate.  */
            if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD)
            if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD)
              can_subst = 0;
              can_subst = 0;
          }
          }
      }
      }
      break;
      break;
 
 
    case 'O':
    case 'O':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE,
                         cplus_demangle_type (di), NULL);
                         cplus_demangle_type (di), NULL);
      break;
      break;
 
 
    case 'P':
    case 'P':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
                         cplus_demangle_type (di), NULL);
                         cplus_demangle_type (di), NULL);
      break;
      break;
 
 
    case 'R':
    case 'R':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE,
                         cplus_demangle_type (di), NULL);
                         cplus_demangle_type (di), NULL);
      break;
      break;
 
 
    case 'C':
    case 'C':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
                         cplus_demangle_type (di), NULL);
                         cplus_demangle_type (di), NULL);
      break;
      break;
 
 
    case 'G':
    case 'G':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
                         cplus_demangle_type (di), NULL);
                         cplus_demangle_type (di), NULL);
      break;
      break;
 
 
    case 'U':
    case 'U':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_source_name (di);
      ret = d_source_name (di);
      ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
      ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
                         cplus_demangle_type (di), ret);
                         cplus_demangle_type (di), ret);
      break;
      break;
 
 
    case 'D':
    case 'D':
      can_subst = 0;
      can_subst = 0;
      d_advance (di, 1);
      d_advance (di, 1);
      peek = d_next_char (di);
      peek = d_next_char (di);
      switch (peek)
      switch (peek)
        {
        {
        case 'T':
        case 'T':
        case 't':
        case 't':
          /* decltype (expression) */
          /* decltype (expression) */
          ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE,
          ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE,
                             d_expression (di), NULL);
                             d_expression (di), NULL);
          if (ret && d_next_char (di) != 'E')
          if (ret && d_next_char (di) != 'E')
            ret = NULL;
            ret = NULL;
          break;
          break;
 
 
        case 'p':
        case 'p':
          /* Pack expansion.  */
          /* Pack expansion.  */
          ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
          ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
                             cplus_demangle_type (di), NULL);
                             cplus_demangle_type (di), NULL);
          break;
          break;
 
 
        case 'f':
        case 'f':
          /* 32-bit decimal floating point */
          /* 32-bit decimal floating point */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
        case 'd':
        case 'd':
          /* 64-bit DFP */
          /* 64-bit DFP */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
        case 'e':
        case 'e':
          /* 128-bit DFP */
          /* 128-bit DFP */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
        case 'h':
        case 'h':
          /* 16-bit half-precision FP */
          /* 16-bit half-precision FP */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
        case 's':
        case 's':
          /* char16_t */
          /* char16_t */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
        case 'i':
        case 'i':
          /* char32_t */
          /* char32_t */
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
          ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
          di->expansion += ret->u.s_builtin.type->len;
          di->expansion += ret->u.s_builtin.type->len;
          break;
          break;
 
 
        case 'F':
        case 'F':
          /* Fixed point types. DF<int bits><length><fract bits><sat>  */
          /* Fixed point types. DF<int bits><length><fract bits><sat>  */
          ret = d_make_empty (di);
          ret = d_make_empty (di);
          ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
          ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
          if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
          if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
            /* For demangling we don't care about the bits.  */
            /* For demangling we don't care about the bits.  */
            d_number (di);
            d_number (di);
          ret->u.s_fixed.length = cplus_demangle_type (di);
          ret->u.s_fixed.length = cplus_demangle_type (di);
          if (ret->u.s_fixed.length == NULL)
          if (ret->u.s_fixed.length == NULL)
            return NULL;
            return NULL;
          d_number (di);
          d_number (di);
          peek = d_next_char (di);
          peek = d_next_char (di);
          ret->u.s_fixed.sat = (peek == 's');
          ret->u.s_fixed.sat = (peek == 's');
          break;
          break;
 
 
        case 'v':
        case 'v':
          ret = d_vector_type (di);
          ret = d_vector_type (di);
          break;
          break;
 
 
        default:
        default:
          return NULL;
          return NULL;
        }
        }
      break;
      break;
 
 
    default:
    default:
      return NULL;
      return NULL;
    }
    }
 
 
  if (can_subst)
  if (can_subst)
    {
    {
      if (! d_add_substitution (di, ret))
      if (! d_add_substitution (di, ret))
        return NULL;
        return NULL;
    }
    }
 
 
  return ret;
  return ret;
}
}
 
 
/* <CV-qualifiers> ::= [r] [V] [K]  */
/* <CV-qualifiers> ::= [r] [V] [K]  */
 
 
static struct demangle_component **
static struct demangle_component **
d_cv_qualifiers (struct d_info *di,
d_cv_qualifiers (struct d_info *di,
                 struct demangle_component **pret, int member_fn)
                 struct demangle_component **pret, int member_fn)
{
{
  char peek;
  char peek;
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  while (peek == 'r' || peek == 'V' || peek == 'K')
  while (peek == 'r' || peek == 'V' || peek == 'K')
    {
    {
      enum demangle_component_type t;
      enum demangle_component_type t;
 
 
      d_advance (di, 1);
      d_advance (di, 1);
      if (peek == 'r')
      if (peek == 'r')
        {
        {
          t = (member_fn
          t = (member_fn
               ? DEMANGLE_COMPONENT_RESTRICT_THIS
               ? DEMANGLE_COMPONENT_RESTRICT_THIS
               : DEMANGLE_COMPONENT_RESTRICT);
               : DEMANGLE_COMPONENT_RESTRICT);
          di->expansion += sizeof "restrict";
          di->expansion += sizeof "restrict";
        }
        }
      else if (peek == 'V')
      else if (peek == 'V')
        {
        {
          t = (member_fn
          t = (member_fn
               ? DEMANGLE_COMPONENT_VOLATILE_THIS
               ? DEMANGLE_COMPONENT_VOLATILE_THIS
               : DEMANGLE_COMPONENT_VOLATILE);
               : DEMANGLE_COMPONENT_VOLATILE);
          di->expansion += sizeof "volatile";
          di->expansion += sizeof "volatile";
        }
        }
      else
      else
        {
        {
          t = (member_fn
          t = (member_fn
               ? DEMANGLE_COMPONENT_CONST_THIS
               ? DEMANGLE_COMPONENT_CONST_THIS
               : DEMANGLE_COMPONENT_CONST);
               : DEMANGLE_COMPONENT_CONST);
          di->expansion += sizeof "const";
          di->expansion += sizeof "const";
        }
        }
 
 
      *pret = d_make_comp (di, t, NULL, NULL);
      *pret = d_make_comp (di, t, NULL, NULL);
      if (*pret == NULL)
      if (*pret == NULL)
        return NULL;
        return NULL;
      pret = &d_left (*pret);
      pret = &d_left (*pret);
 
 
      peek = d_peek_char (di);
      peek = d_peek_char (di);
    }
    }
 
 
  return pret;
  return pret;
}
}
 
 
/* <function-type> ::= F [Y] <bare-function-type> E  */
/* <function-type> ::= F [Y] <bare-function-type> E  */
 
 
static struct demangle_component *
static struct demangle_component *
d_function_type (struct d_info *di)
d_function_type (struct d_info *di)
{
{
  struct demangle_component *ret;
  struct demangle_component *ret;
 
 
  if (! d_check_char (di, 'F'))
  if (! d_check_char (di, 'F'))
    return NULL;
    return NULL;
  if (d_peek_char (di) == 'Y')
  if (d_peek_char (di) == 'Y')
    {
    {
      /* Function has C linkage.  We don't print this information.
      /* Function has C linkage.  We don't print this information.
         FIXME: We should print it in verbose mode.  */
         FIXME: We should print it in verbose mode.  */
      d_advance (di, 1);
      d_advance (di, 1);
    }
    }
  ret = d_bare_function_type (di, 1);
  ret = d_bare_function_type (di, 1);
  if (! d_check_char (di, 'E'))
  if (! d_check_char (di, 'E'))
    return NULL;
    return NULL;
  return ret;
  return ret;
}
}
 
 
/* <type>+ */
/* <type>+ */
 
 
static struct demangle_component *
static struct demangle_component *
d_parmlist (struct d_info *di)
d_parmlist (struct d_info *di)
{
{
  struct demangle_component *tl;
  struct demangle_component *tl;
  struct demangle_component **ptl;
  struct demangle_component **ptl;
 
 
  tl = NULL;
  tl = NULL;
  ptl = &tl;
  ptl = &tl;
  while (1)
  while (1)
    {
    {
      struct demangle_component *type;
      struct demangle_component *type;
 
 
      char peek = d_peek_char (di);
      char peek = d_peek_char (di);
      if (peek == '\0' || peek == 'E')
      if (peek == '\0' || peek == 'E')
        break;
        break;
      type = cplus_demangle_type (di);
      type = cplus_demangle_type (di);
      if (type == NULL)
      if (type == NULL)
        return NULL;
        return NULL;
      *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
      *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
      if (*ptl == NULL)
      if (*ptl == NULL)
        return NULL;
        return NULL;
      ptl = &d_right (*ptl);
      ptl = &d_right (*ptl);
    }
    }
 
 
  /* There should be at least one parameter type besides the optional
  /* There should be at least one parameter type besides the optional
     return type.  A function which takes no arguments will have a
     return type.  A function which takes no arguments will have a
     single parameter type void.  */
     single parameter type void.  */
  if (tl == NULL)
  if (tl == NULL)
    return NULL;
    return NULL;
 
 
  /* If we have a single parameter type void, omit it.  */
  /* If we have a single parameter type void, omit it.  */
  if (d_right (tl) == NULL
  if (d_right (tl) == NULL
      && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
      && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
      && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
      && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
    {
    {
      di->expansion -= d_left (tl)->u.s_builtin.type->len;
      di->expansion -= d_left (tl)->u.s_builtin.type->len;
      d_left (tl) = NULL;
      d_left (tl) = NULL;
    }
    }
 
 
  return tl;
  return tl;
}
}
 
 
/* <bare-function-type> ::= [J]<type>+  */
/* <bare-function-type> ::= [J]<type>+  */
 
 
static struct demangle_component *
static struct demangle_component *
d_bare_function_type (struct d_info *di, int has_return_type)
d_bare_function_type (struct d_info *di, int has_return_type)
{
{
  struct demangle_component *return_type;
  struct demangle_component *return_type;
  struct demangle_component *tl;
  struct demangle_component *tl;
  char peek;
  char peek;
 
 
  /* Detect special qualifier indicating that the first argument
  /* Detect special qualifier indicating that the first argument
     is the return type.  */
     is the return type.  */
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == 'J')
  if (peek == 'J')
    {
    {
      d_advance (di, 1);
      d_advance (di, 1);
      has_return_type = 1;
      has_return_type = 1;
    }
    }
 
 
  if (has_return_type)
  if (has_return_type)
    {
    {
      return_type = cplus_demangle_type (di);
      return_type = cplus_demangle_type (di);
      if (return_type == NULL)
      if (return_type == NULL)
        return NULL;
        return NULL;
    }
    }
  else
  else
    return_type = NULL;
    return_type = NULL;
 
 
  tl = d_parmlist (di);
  tl = d_parmlist (di);
  if (tl == NULL)
  if (tl == NULL)
    return NULL;
    return NULL;
 
 
  return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE,
  return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE,
                      return_type, tl);
                      return_type, tl);
}
}
 
 
/* <class-enum-type> ::= <name>  */
/* <class-enum-type> ::= <name>  */
 
 
static struct demangle_component *
static struct demangle_component *
d_class_enum_type (struct d_info *di)
d_class_enum_type (struct d_info *di)
{
{
  return d_name (di);
  return d_name (di);
}
}
 
 
/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
                ::= A [<(dimension) expression>] _ <(element) type>
                ::= A [<(dimension) expression>] _ <(element) type>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_array_type (struct d_info *di)
d_array_type (struct d_info *di)
{
{
  char peek;
  char peek;
  struct demangle_component *dim;
  struct demangle_component *dim;
 
 
  if (! d_check_char (di, 'A'))
  if (! d_check_char (di, 'A'))
    return NULL;
    return NULL;
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == '_')
  if (peek == '_')
    dim = NULL;
    dim = NULL;
  else if (IS_DIGIT (peek))
  else if (IS_DIGIT (peek))
    {
    {
      const char *s;
      const char *s;
 
 
      s = d_str (di);
      s = d_str (di);
      do
      do
        {
        {
          d_advance (di, 1);
          d_advance (di, 1);
          peek = d_peek_char (di);
          peek = d_peek_char (di);
        }
        }
      while (IS_DIGIT (peek));
      while (IS_DIGIT (peek));
      dim = d_make_name (di, s, d_str (di) - s);
      dim = d_make_name (di, s, d_str (di) - s);
      if (dim == NULL)
      if (dim == NULL)
        return NULL;
        return NULL;
    }
    }
  else
  else
    {
    {
      dim = d_expression (di);
      dim = d_expression (di);
      if (dim == NULL)
      if (dim == NULL)
        return NULL;
        return NULL;
    }
    }
 
 
  if (! d_check_char (di, '_'))
  if (! d_check_char (di, '_'))
    return NULL;
    return NULL;
 
 
  return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
  return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
                      cplus_demangle_type (di));
                      cplus_demangle_type (di));
}
}
 
 
/* <vector-type> ::= Dv <number> _ <type>
/* <vector-type> ::= Dv <number> _ <type>
                 ::= Dv _ <expression> _ <type> */
                 ::= Dv _ <expression> _ <type> */
 
 
static struct demangle_component *
static struct demangle_component *
d_vector_type (struct d_info *di)
d_vector_type (struct d_info *di)
{
{
  char peek;
  char peek;
  struct demangle_component *dim;
  struct demangle_component *dim;
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == '_')
  if (peek == '_')
    {
    {
      d_advance (di, 1);
      d_advance (di, 1);
      dim = d_expression (di);
      dim = d_expression (di);
    }
    }
  else
  else
    dim = d_number_component (di);
    dim = d_number_component (di);
 
 
  if (dim == NULL)
  if (dim == NULL)
    return NULL;
    return NULL;
 
 
  if (! d_check_char (di, '_'))
  if (! d_check_char (di, '_'))
    return NULL;
    return NULL;
 
 
  return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim,
  return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim,
                      cplus_demangle_type (di));
                      cplus_demangle_type (di));
}
}
 
 
/* <pointer-to-member-type> ::= M <(class) type> <(member) type>  */
/* <pointer-to-member-type> ::= M <(class) type> <(member) type>  */
 
 
static struct demangle_component *
static struct demangle_component *
d_pointer_to_member_type (struct d_info *di)
d_pointer_to_member_type (struct d_info *di)
{
{
  struct demangle_component *cl;
  struct demangle_component *cl;
  struct demangle_component *mem;
  struct demangle_component *mem;
  struct demangle_component **pmem;
  struct demangle_component **pmem;
 
 
  if (! d_check_char (di, 'M'))
  if (! d_check_char (di, 'M'))
    return NULL;
    return NULL;
 
 
  cl = cplus_demangle_type (di);
  cl = cplus_demangle_type (di);
 
 
  /* The ABI specifies that any type can be a substitution source, and
  /* The ABI specifies that any type can be a substitution source, and
     that M is followed by two types, and that when a CV-qualified
     that M is followed by two types, and that when a CV-qualified
     type is seen both the base type and the CV-qualified types are
     type is seen both the base type and the CV-qualified types are
     substitution sources.  The ABI also specifies that for a pointer
     substitution sources.  The ABI also specifies that for a pointer
     to a CV-qualified member function, the qualifiers are attached to
     to a CV-qualified member function, the qualifiers are attached to
     the second type.  Given the grammar, a plain reading of the ABI
     the second type.  Given the grammar, a plain reading of the ABI
     suggests that both the CV-qualified member function and the
     suggests that both the CV-qualified member function and the
     non-qualified member function are substitution sources.  However,
     non-qualified member function are substitution sources.  However,
     g++ does not work that way.  g++ treats only the CV-qualified
     g++ does not work that way.  g++ treats only the CV-qualified
     member function as a substitution source.  FIXME.  So to work
     member function as a substitution source.  FIXME.  So to work
     with g++, we need to pull off the CV-qualifiers here, in order to
     with g++, we need to pull off the CV-qualifiers here, in order to
     avoid calling add_substitution() in cplus_demangle_type().  But
     avoid calling add_substitution() in cplus_demangle_type().  But
     for a CV-qualified member which is not a function, g++ does
     for a CV-qualified member which is not a function, g++ does
     follow the ABI, so we need to handle that case here by calling
     follow the ABI, so we need to handle that case here by calling
     d_add_substitution ourselves.  */
     d_add_substitution ourselves.  */
 
 
  pmem = d_cv_qualifiers (di, &mem, 1);
  pmem = d_cv_qualifiers (di, &mem, 1);
  if (pmem == NULL)
  if (pmem == NULL)
    return NULL;
    return NULL;
  *pmem = cplus_demangle_type (di);
  *pmem = cplus_demangle_type (di);
  if (*pmem == NULL)
  if (*pmem == NULL)
    return NULL;
    return NULL;
 
 
  if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
  if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
    {
    {
      if (! d_add_substitution (di, mem))
      if (! d_add_substitution (di, mem))
        return NULL;
        return NULL;
    }
    }
 
 
  return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
  return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
}
}
 
 
/* <non-negative number> _ */
/* <non-negative number> _ */
 
 
static long
static long
d_compact_number (struct d_info *di)
d_compact_number (struct d_info *di)
{
{
  long num;
  long num;
  if (d_peek_char (di) == '_')
  if (d_peek_char (di) == '_')
    num = 0;
    num = 0;
  else if (d_peek_char (di) == 'n')
  else if (d_peek_char (di) == 'n')
    return -1;
    return -1;
  else
  else
    num = d_number (di) + 1;
    num = d_number (di) + 1;
 
 
  if (! d_check_char (di, '_'))
  if (! d_check_char (di, '_'))
    return -1;
    return -1;
  return num;
  return num;
}
}
 
 
/* <template-param> ::= T_
/* <template-param> ::= T_
                    ::= T <(parameter-2 non-negative) number> _
                    ::= T <(parameter-2 non-negative) number> _
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_template_param (struct d_info *di)
d_template_param (struct d_info *di)
{
{
  long param;
  long param;
 
 
  if (! d_check_char (di, 'T'))
  if (! d_check_char (di, 'T'))
    return NULL;
    return NULL;
 
 
  param = d_compact_number (di);
  param = d_compact_number (di);
  if (param < 0)
  if (param < 0)
    return NULL;
    return NULL;
 
 
  ++di->did_subs;
  ++di->did_subs;
 
 
  return d_make_template_param (di, param);
  return d_make_template_param (di, param);
}
}
 
 
/* <template-args> ::= I <template-arg>+ E  */
/* <template-args> ::= I <template-arg>+ E  */
 
 
static struct demangle_component *
static struct demangle_component *
d_template_args (struct d_info *di)
d_template_args (struct d_info *di)
{
{
  struct demangle_component *hold_last_name;
  struct demangle_component *hold_last_name;
  struct demangle_component *al;
  struct demangle_component *al;
  struct demangle_component **pal;
  struct demangle_component **pal;
 
 
  /* Preserve the last name we saw--don't let the template arguments
  /* Preserve the last name we saw--don't let the template arguments
     clobber it, as that would give us the wrong name for a subsequent
     clobber it, as that would give us the wrong name for a subsequent
     constructor or destructor.  */
     constructor or destructor.  */
  hold_last_name = di->last_name;
  hold_last_name = di->last_name;
 
 
  if (! d_check_char (di, 'I'))
  if (! d_check_char (di, 'I'))
    return NULL;
    return NULL;
 
 
  if (d_peek_char (di) == 'E')
  if (d_peek_char (di) == 'E')
    {
    {
      /* An argument pack can be empty.  */
      /* An argument pack can be empty.  */
      d_advance (di, 1);
      d_advance (di, 1);
      return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
      return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
    }
    }
 
 
  al = NULL;
  al = NULL;
  pal = &al;
  pal = &al;
  while (1)
  while (1)
    {
    {
      struct demangle_component *a;
      struct demangle_component *a;
 
 
      a = d_template_arg (di);
      a = d_template_arg (di);
      if (a == NULL)
      if (a == NULL)
        return NULL;
        return NULL;
 
 
      *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
      *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
      if (*pal == NULL)
      if (*pal == NULL)
        return NULL;
        return NULL;
      pal = &d_right (*pal);
      pal = &d_right (*pal);
 
 
      if (d_peek_char (di) == 'E')
      if (d_peek_char (di) == 'E')
        {
        {
          d_advance (di, 1);
          d_advance (di, 1);
          break;
          break;
        }
        }
    }
    }
 
 
  di->last_name = hold_last_name;
  di->last_name = hold_last_name;
 
 
  return al;
  return al;
}
}
 
 
/* <template-arg> ::= <type>
/* <template-arg> ::= <type>
                  ::= X <expression> E
                  ::= X <expression> E
                  ::= <expr-primary>
                  ::= <expr-primary>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_template_arg (struct d_info *di)
d_template_arg (struct d_info *di)
{
{
  struct demangle_component *ret;
  struct demangle_component *ret;
 
 
  switch (d_peek_char (di))
  switch (d_peek_char (di))
    {
    {
    case 'X':
    case 'X':
      d_advance (di, 1);
      d_advance (di, 1);
      ret = d_expression (di);
      ret = d_expression (di);
      if (! d_check_char (di, 'E'))
      if (! d_check_char (di, 'E'))
        return NULL;
        return NULL;
      return ret;
      return ret;
 
 
    case 'L':
    case 'L':
      return d_expr_primary (di);
      return d_expr_primary (di);
 
 
    case 'I':
    case 'I':
      /* An argument pack.  */
      /* An argument pack.  */
      return d_template_args (di);
      return d_template_args (di);
 
 
    default:
    default:
      return cplus_demangle_type (di);
      return cplus_demangle_type (di);
    }
    }
}
}
 
 
/* Subroutine of <expression> ::= cl <expression>+ E */
/* Subroutine of <expression> ::= cl <expression>+ E */
 
 
static struct demangle_component *
static struct demangle_component *
d_exprlist (struct d_info *di)
d_exprlist (struct d_info *di)
{
{
  struct demangle_component *list = NULL;
  struct demangle_component *list = NULL;
  struct demangle_component **p = &list;
  struct demangle_component **p = &list;
 
 
  if (d_peek_char (di) == 'E')
  if (d_peek_char (di) == 'E')
    {
    {
      d_advance (di, 1);
      d_advance (di, 1);
      return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
      return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
    }
    }
 
 
  while (1)
  while (1)
    {
    {
      struct demangle_component *arg = d_expression (di);
      struct demangle_component *arg = d_expression (di);
      if (arg == NULL)
      if (arg == NULL)
        return NULL;
        return NULL;
 
 
      *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
      *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
      if (*p == NULL)
      if (*p == NULL)
        return NULL;
        return NULL;
      p = &d_right (*p);
      p = &d_right (*p);
 
 
      if (d_peek_char (di) == 'E')
      if (d_peek_char (di) == 'E')
        {
        {
          d_advance (di, 1);
          d_advance (di, 1);
          break;
          break;
        }
        }
    }
    }
 
 
  return list;
  return list;
}
}
 
 
/* <expression> ::= <(unary) operator-name> <expression>
/* <expression> ::= <(unary) operator-name> <expression>
                ::= <(binary) operator-name> <expression> <expression>
                ::= <(binary) operator-name> <expression> <expression>
                ::= <(trinary) operator-name> <expression> <expression> <expression>
                ::= <(trinary) operator-name> <expression> <expression> <expression>
                ::= cl <expression>+ E
                ::= cl <expression>+ E
                ::= st <type>
                ::= st <type>
                ::= <template-param>
                ::= <template-param>
                ::= sr <type> <unqualified-name>
                ::= sr <type> <unqualified-name>
                ::= sr <type> <unqualified-name> <template-args>
                ::= sr <type> <unqualified-name> <template-args>
                ::= <expr-primary>
                ::= <expr-primary>
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_expression (struct d_info *di)
d_expression (struct d_info *di)
{
{
  char peek;
  char peek;
 
 
  peek = d_peek_char (di);
  peek = d_peek_char (di);
  if (peek == 'L')
  if (peek == 'L')
    return d_expr_primary (di);
    return d_expr_primary (di);
  else if (peek == 'T')
  else if (peek == 'T')
    return d_template_param (di);
    return d_template_param (di);
  else if (peek == 's' && d_peek_next_char (di) == 'r')
  else if (peek == 's' && d_peek_next_char (di) == 'r')
    {
    {
      struct demangle_component *type;
      struct demangle_component *type;
      struct demangle_component *name;
      struct demangle_component *name;
 
 
      d_advance (di, 2);
      d_advance (di, 2);
      type = cplus_demangle_type (di);
      type = cplus_demangle_type (di);
      name = d_unqualified_name (di);
      name = d_unqualified_name (di);
      if (d_peek_char (di) != 'I')
      if (d_peek_char (di) != 'I')
        return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
        return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
      else
      else
        return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
        return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
                            d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
                            d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
                                         d_template_args (di)));
                                         d_template_args (di)));
    }
    }
  else if (peek == 's' && d_peek_next_char (di) == 'p')
  else if (peek == 's' && d_peek_next_char (di) == 'p')
    {
    {
      d_advance (di, 2);
      d_advance (di, 2);
      return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
      return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
                          d_expression (di), NULL);
                          d_expression (di), NULL);
    }
    }
  else if (peek == 'f' && d_peek_next_char (di) == 'p')
  else if (peek == 'f' && d_peek_next_char (di) == 'p')
    {
    {
      /* Function parameter used in a late-specified return type.  */
      /* Function parameter used in a late-specified return type.  */
      int index;
      int index;
      d_advance (di, 2);
      d_advance (di, 2);
      index = d_compact_number (di);
      index = d_compact_number (di);
      if (index < 0)
      if (index < 0)
        return NULL;
        return NULL;
 
 
      return d_make_function_param (di, index);
      return d_make_function_param (di, index);
    }
    }
  else if (IS_DIGIT (peek)
  else if (IS_DIGIT (peek)
           || (peek == 'o' && d_peek_next_char (di) == 'n'))
           || (peek == 'o' && d_peek_next_char (di) == 'n'))
    {
    {
      /* We can get an unqualified name as an expression in the case of
      /* We can get an unqualified name as an expression in the case of
         a dependent function call, i.e. decltype(f(t)).  */
         a dependent function call, i.e. decltype(f(t)).  */
      struct demangle_component *name;
      struct demangle_component *name;
 
 
      if (peek == 'o')
      if (peek == 'o')
        /* operator-function-id, i.e. operator+(t).  */
        /* operator-function-id, i.e. operator+(t).  */
        d_advance (di, 2);
        d_advance (di, 2);
 
 
      name = d_unqualified_name (di);
      name = d_unqualified_name (di);
      if (name == NULL)
      if (name == NULL)
        return NULL;
        return NULL;
      if (d_peek_char (di) == 'I')
      if (d_peek_char (di) == 'I')
        return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
        return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
                            d_template_args (di));
                            d_template_args (di));
      else
      else
        return name;
        return name;
    }
    }
  else
  else
    {
    {
      struct demangle_component *op;
      struct demangle_component *op;
      int args;
      int args;
 
 
      op = d_operator_name (di);
      op = d_operator_name (di);
      if (op == NULL)
      if (op == NULL)
        return NULL;
        return NULL;
 
 
      if (op->type == DEMANGLE_COMPONENT_OPERATOR)
      if (op->type == DEMANGLE_COMPONENT_OPERATOR)
        di->expansion += op->u.s_operator.op->len - 2;
        di->expansion += op->u.s_operator.op->len - 2;
 
 
      if (op->type == DEMANGLE_COMPONENT_OPERATOR
      if (op->type == DEMANGLE_COMPONENT_OPERATOR
          && strcmp (op->u.s_operator.op->code, "st") == 0)
          && strcmp (op->u.s_operator.op->code, "st") == 0)
        return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
        return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
                            cplus_demangle_type (di));
                            cplus_demangle_type (di));
 
 
      switch (op->type)
      switch (op->type)
        {
        {
        default:
        default:
          return NULL;
          return NULL;
        case DEMANGLE_COMPONENT_OPERATOR:
        case DEMANGLE_COMPONENT_OPERATOR:
          args = op->u.s_operator.op->args;
          args = op->u.s_operator.op->args;
          break;
          break;
        case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
        case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
          args = op->u.s_extended_operator.args;
          args = op->u.s_extended_operator.args;
          break;
          break;
        case DEMANGLE_COMPONENT_CAST:
        case DEMANGLE_COMPONENT_CAST:
          args = 1;
          args = 1;
          break;
          break;
        }
        }
 
 
      switch (args)
      switch (args)
        {
        {
        case 1:
        case 1:
          {
          {
            struct demangle_component *operand;
            struct demangle_component *operand;
            if (op->type == DEMANGLE_COMPONENT_CAST
            if (op->type == DEMANGLE_COMPONENT_CAST
                && d_check_char (di, '_'))
                && d_check_char (di, '_'))
              operand = d_exprlist (di);
              operand = d_exprlist (di);
            else
            else
              operand = d_expression (di);
              operand = d_expression (di);
            return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
            return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
                                operand);
                                operand);
          }
          }
        case 2:
        case 2:
          {
          {
            struct demangle_component *left;
            struct demangle_component *left;
            struct demangle_component *right;
            struct demangle_component *right;
            const char *code = op->u.s_operator.op->code;
            const char *code = op->u.s_operator.op->code;
 
 
            left = d_expression (di);
            left = d_expression (di);
            if (!strcmp (code, "cl"))
            if (!strcmp (code, "cl"))
              right = d_exprlist (di);
              right = d_exprlist (di);
            else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
            else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
              {
              {
                right = d_unqualified_name (di);
                right = d_unqualified_name (di);
                if (d_peek_char (di) == 'I')
                if (d_peek_char (di) == 'I')
                  right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
                  right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
                                       right, d_template_args (di));
                                       right, d_template_args (di));
              }
              }
            else
            else
              right = d_expression (di);
              right = d_expression (di);
 
 
            return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
            return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
                                d_make_comp (di,
                                d_make_comp (di,
                                             DEMANGLE_COMPONENT_BINARY_ARGS,
                                             DEMANGLE_COMPONENT_BINARY_ARGS,
                                             left, right));
                                             left, right));
          }
          }
        case 3:
        case 3:
          {
          {
            struct demangle_component *first;
            struct demangle_component *first;
            struct demangle_component *second;
            struct demangle_component *second;
 
 
            first = d_expression (di);
            first = d_expression (di);
            second = d_expression (di);
            second = d_expression (di);
            return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
            return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
                                d_make_comp (di,
                                d_make_comp (di,
                                             DEMANGLE_COMPONENT_TRINARY_ARG1,
                                             DEMANGLE_COMPONENT_TRINARY_ARG1,
                                             first,
                                             first,
                                             d_make_comp (di,
                                             d_make_comp (di,
                                                          DEMANGLE_COMPONENT_TRINARY_ARG2,
                                                          DEMANGLE_COMPONENT_TRINARY_ARG2,
                                                          second,
                                                          second,
                                                          d_expression (di))));
                                                          d_expression (di))));
          }
          }
        default:
        default:
          return NULL;
          return NULL;
        }
        }
    }
    }
}
}
 
 
/* <expr-primary> ::= L <type> <(value) number> E
/* <expr-primary> ::= L <type> <(value) number> E
                  ::= L <type> <(value) float> E
                  ::= L <type> <(value) float> E
                  ::= L <mangled-name> E
                  ::= L <mangled-name> E
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_expr_primary (struct d_info *di)
d_expr_primary (struct d_info *di)
{
{
  struct demangle_component *ret;
  struct demangle_component *ret;
 
 
  if (! d_check_char (di, 'L'))
  if (! d_check_char (di, 'L'))
    return NULL;
    return NULL;
  if (d_peek_char (di) == '_'
  if (d_peek_char (di) == '_'
      /* Workaround for G++ bug; see comment in write_template_arg.  */
      /* Workaround for G++ bug; see comment in write_template_arg.  */
      || d_peek_char (di) == 'Z')
      || d_peek_char (di) == 'Z')
    ret = cplus_demangle_mangled_name (di, 0);
    ret = cplus_demangle_mangled_name (di, 0);
  else
  else
    {
    {
      struct demangle_component *type;
      struct demangle_component *type;
      enum demangle_component_type t;
      enum demangle_component_type t;
      const char *s;
      const char *s;
 
 
      type = cplus_demangle_type (di);
      type = cplus_demangle_type (di);
      if (type == NULL)
      if (type == NULL)
        return NULL;
        return NULL;
 
 
      /* If we have a type we know how to print, we aren't going to
      /* If we have a type we know how to print, we aren't going to
         print the type name itself.  */
         print the type name itself.  */
      if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
      if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
          && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
          && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
        di->expansion -= type->u.s_builtin.type->len;
        di->expansion -= type->u.s_builtin.type->len;
 
 
      /* Rather than try to interpret the literal value, we just
      /* Rather than try to interpret the literal value, we just
         collect it as a string.  Note that it's possible to have a
         collect it as a string.  Note that it's possible to have a
         floating point literal here.  The ABI specifies that the
         floating point literal here.  The ABI specifies that the
         format of such literals is machine independent.  That's fine,
         format of such literals is machine independent.  That's fine,
         but what's not fine is that versions of g++ up to 3.2 with
         but what's not fine is that versions of g++ up to 3.2 with
         -fabi-version=1 used upper case letters in the hex constant,
         -fabi-version=1 used upper case letters in the hex constant,
         and dumped out gcc's internal representation.  That makes it
         and dumped out gcc's internal representation.  That makes it
         hard to tell where the constant ends, and hard to dump the
         hard to tell where the constant ends, and hard to dump the
         constant in any readable form anyhow.  We don't attempt to
         constant in any readable form anyhow.  We don't attempt to
         handle these cases.  */
         handle these cases.  */
 
 
      t = DEMANGLE_COMPONENT_LITERAL;
      t = DEMANGLE_COMPONENT_LITERAL;
      if (d_peek_char (di) == 'n')
      if (d_peek_char (di) == 'n')
        {
        {
          t = DEMANGLE_COMPONENT_LITERAL_NEG;
          t = DEMANGLE_COMPONENT_LITERAL_NEG;
          d_advance (di, 1);
          d_advance (di, 1);
        }
        }
      s = d_str (di);
      s = d_str (di);
      while (d_peek_char (di) != 'E')
      while (d_peek_char (di) != 'E')
        {
        {
          if (d_peek_char (di) == '\0')
          if (d_peek_char (di) == '\0')
            return NULL;
            return NULL;
          d_advance (di, 1);
          d_advance (di, 1);
        }
        }
      ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
      ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
    }
    }
  if (! d_check_char (di, 'E'))
  if (! d_check_char (di, 'E'))
    return NULL;
    return NULL;
  return ret;
  return ret;
}
}
 
 
/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
                ::= Z <(function) encoding> E s [<discriminator>]
                ::= Z <(function) encoding> E s [<discriminator>]
*/
*/
 
 
static struct demangle_component *
static struct demangle_component *
d_local_name (struct d_info *di)
d_local_name (struct d_info *di)
{
{
  struct demangle_component *function;
  struct demangle_component *function;
 
 
  if (! d_check_char (di, 'Z'))
  if (! d_check_char (di, 'Z'))
    return NULL;
    return NULL;
 
 
  function = d_encoding (di, 0);
  function = d_encoding (di, 0);
 
 
  if (! d_check_char (di, 'E'))
  if (! d_check_char (di, 'E'))
    return NULL;
    return NULL;
 
 
  if (d_peek_char (di) == 's')
  if (d_peek_char (di) == 's')
    {
    {
      d_advance (di, 1);
      d_advance (di, 1);
      if (! d_discriminator (di))
      if (! d_discriminator (di))
        return NULL;
        return NULL;
      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
                          d_make_name (di, "string literal",
                          d_make_name (di, "string literal",
                                       sizeof "string literal" - 1));
                                       sizeof "string literal" - 1));
    }
    }
  else
  else
    {
    {
      struct demangle_component *name;
      struct demangle_component *name;
      int num = -1;
      int num = -1;
 
 
      if (d_peek_char (di) == 'd')
      if (d_peek_char (di) == 'd')
        {
        {
          /* Default argument scope: d <number> _.  */
          /* Default argument scope: d <number> _.  */
          d_advance (di, 1);
          d_advance (di, 1);
          num = d_compact_number (di);
          num = d_compact_number (di);
          if (num < 0)
          if (num < 0)
            return NULL;
            return NULL;
        }
        }
 
 
      name = d_name (di);
      name = d_name (di);
      if (name)
      if (name)
        switch (name->type)
        switch (name->type)
          {
          {
            /* Lambdas and unnamed types have internal discriminators.  */
            /* Lambdas and unnamed types have internal discriminators.  */
          case DEMANGLE_COMPONENT_LAMBDA:
          case DEMANGLE_COMPONENT_LAMBDA:
          case DEMANGLE_COMPONENT_UNNAMED_TYPE:
          case DEMANGLE_COMPONENT_UNNAMED_TYPE:
            break;
            break;
          default:
          default:
            if (! d_discriminator (di))
            if (! d_discriminator (di))
              return NULL;
              return NULL;
          }
          }
      if (num >= 0)
      if (num >= 0)
        name = d_make_default_arg (di, num, name);
        name = d_make_default_arg (di, num, name);
      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
      return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
    }
    }
}
}
 
 
/* <discriminator> ::= _ <(non-negative) number>
/* <discriminator> ::= _ <(non-negative) number>
 
 
   We demangle the discriminator, but we don't print it out.  FIXME:
   We demangle the discriminator, but we don't print it out.  FIXME:
   We should print it out in verbose mode.  */
   We should print it out in verbose mode.  */
 
 
static int
static int
d_discriminator (struct d_info *di)
d_discriminator (struct d_info *di)
{
{
  long discrim;
  long discrim;
 
 
  if (d_peek_char (di) != '_')
  if (d_peek_char (di) != '_')
    return 1;
    return 1;
  d_advance (di, 1);
  d_advance (di, 1);
  discrim = d_number (di);
  discrim = d_number (di);
  if (discrim < 0)
  if (discrim < 0)
    return 0;
    return 0;
  return 1;
  return 1;
}
}
 
 
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
 
 
static struct demangle_component *
static struct demangle_component *
d_lambda (struct d_info *di)
d_lambda (struct d_info *di)
{
{
  struct demangle_component *tl;
  struct demangle_component *tl;
  struct demangle_component *ret;
  struct demangle_component *ret;
  int num;
  int num;
 
 
  if (! d_check_char (di, 'U'))
  if (! d_check_char (di, 'U'))
    return NULL;
    return NULL;
  if (! d_check_char (di, 'l'))
  if (! d_check_char (di, 'l'))
    return NULL;
    return NULL;
 
 
  tl = d_parmlist (di);
  tl = d_parmlist (di);
  if (tl == NULL)
  if (tl == NULL)
    return NULL;
    return NULL;
 
 
  if (! d_check_char (di, 'E'))
  if (! d_check_char (di, 'E'))
    return NULL;
    return NULL;
 
 
  num = d_compact_number (di);
  num = d_compact_number (di);
  if (num < 0)
  if (num < 0)
    return NULL;
    return NULL;
 
 
  ret = d_make_empty (di);
  ret = d_make_empty (di);
  if (ret)
  if (ret)
    {
    {
      ret->type = DEMANGLE_COMPONENT_LAMBDA;
      ret->type = DEMANGLE_COMPONENT_LAMBDA;
      ret->u.s_unary_num.sub = tl;
      ret->u.s_unary_num.sub = tl;
      ret->u.s_unary_num.num = num;
      ret->u.s_unary_num.num = num;
    }
    }
 
 
  if (! d_add_substitution (di, ret))
  if (! d_add_substitution (di, ret))
    return NULL;
    return NULL;
 
 
  return ret;
  return ret;
}
}
 
 
/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
 
 
static struct demangle_component *
static struct demangle_component *
d_unnamed_type (struct d_info *di)
d_unnamed_type (struct d_info *di)
{
{
  struct demangle_component *ret;
  struct demangle_component *ret;
  long num;
  long num;
 
 
  if (! d_check_char (di, 'U'))
  if (! d_check_char (di, 'U'))
    return NULL;
    return NULL;
  if (! d_check_char (di, 't'))
  if (! d_check_char (di, 't'))
    return NULL;
    return NULL;
 
 
  num = d_compact_number (di);
  num = d_compact_number (di);
  if (num < 0)
  if (num < 0)
    return NULL;
    return NULL;
 
 
  ret = d_make_empty (di);
  ret = d_make_empty (di);
  if (ret)
  if (ret)
    {
    {
      ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE;
      ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE;
      ret->u.s_number.number = num;
      ret->u.s_number.number = num;
    }
    }
 
 
  if (! d_add_substitution (di, ret))
  if (! d_add_substitution (di, ret))
    return NULL;
    return NULL;
 
 
  return ret;
  return ret;
}
}
 
 
/* Add a new substitution.  */
/* Add a new substitution.  */
 
 
static int
static int
d_add_substitution (struct d_info *di, struct demangle_component *dc)
d_add_substitution (struct d_info *di, struct demangle_component *dc)
{
{
  if (dc == NULL)
  if (dc == NULL)
    return 0;
    return 0;
  if (di->next_sub >= di->num_subs)
  if (di->next_sub >= di->num_subs)
    return 0;
    return 0;
  di->subs[di->next_sub] = dc;
  di->subs[di->next_sub] = dc;
  ++di->next_sub;
  ++di->next_sub;
  return 1;
  return 1;
}
}
 
 
/* <substitution> ::= S <seq-id> _
/* <substitution> ::= S <seq-id> _
                  ::= S_
                  ::= S_
                  ::= St
                  ::= St
                  ::= Sa
                  ::= Sa
                  ::= Sb
                  ::= Sb
                  ::= Ss
                  ::= Ss
                  ::= Si
                  ::= Si
                  ::= So
                  ::= So
                  ::= Sd
                  ::= Sd
 
 
   If PREFIX is non-zero, then this type is being used as a prefix in
   If PREFIX is non-zero, then this type is being used as a prefix in
   a qualified name.  In this case, for the standard substitutions, we
   a qualified name.  In this case, for the standard substitutions, we
   need to check whether we are being used as a prefix for a
   need to check whether we are being used as a prefix for a
   constructor or destructor, and return a full template name.
   constructor or destructor, and return a full template name.
   Otherwise we will get something like std::iostream::~iostream()
   Otherwise we will get something like std::iostream::~iostream()
   which does not correspond particularly well to any function which
   which does not correspond particularly well to any function which
   actually appears in the source.
   actually appears in the source.
*/
*/
 
 
static const struct d_standard_sub_info standard_subs[] =
static const struct d_standard_sub_info standard_subs[] =
{
{
  { 't', NL ("std"),
  { 't', NL ("std"),
    NL ("std"),
    NL ("std"),
    NULL, 0 },
    NULL, 0 },
  { 'a', NL ("std::allocator"),
  { 'a', NL ("std::allocator"),
    NL ("std::allocator"),
    NL ("std::allocator"),
    NL ("allocator") },
    NL ("allocator") },
  { 'b', NL ("std::basic_string"),
  { 'b', NL ("std::basic_string"),
    NL ("std::basic_string"),
    NL ("std::basic_string"),
    NL ("basic_string") },
    NL ("basic_string") },
  { 's', NL ("std::string"),
  { 's', NL ("std::string"),
    NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
    NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
    NL ("basic_string") },
    NL ("basic_string") },
  { 'i', NL ("std::istream"),
  { 'i', NL ("std::istream"),
    NL ("std::basic_istream<char, std::char_traits<char> >"),
    NL ("std::basic_istream<char, std::char_traits<char> >"),
    NL ("basic_istream") },
    NL ("basic_istream") },
  { 'o', NL ("std::ostream"),
  { 'o', NL ("std::ostream"),
    NL ("std::basic_ostream<char, std::char_traits<char> >"),
    NL ("std::basic_ostream<char, std::char_traits<char> >"),
    NL ("basic_ostream") },
    NL ("basic_ostream") },
  { 'd', NL ("std::iostream"),
  { 'd', NL ("std::iostream"),
    NL ("std::basic_iostream<char, std::char_traits<char> >"),
    NL ("std::basic_iostream<char, std::char_traits<char> >"),
    NL ("basic_iostream") }
    NL ("basic_iostream") }
};
};
 
 
static struct demangle_component *
static struct demangle_component *
d_substitution (struct d_info *di, int prefix)
d_substitution (struct d_info *di, int prefix)
{
{
  char c;
  char c;
 
 
  if (! d_check_char (di, 'S'))
  if (! d_check_char (di, 'S'))
    return NULL;
    return NULL;
 
 
  c = d_next_char (di);
  c = d_next_char (di);
  if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
  if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
    {
    {
      unsigned int id;
      unsigned int id;
 
 
      id = 0;
      id = 0;
      if (c != '_')
      if (c != '_')
        {
        {
          do
          do
            {
            {
              unsigned int new_id;
              unsigned int new_id;
 
 
              if (IS_DIGIT (c))
              if (IS_DIGIT (c))
                new_id = id * 36 + c - '0';
                new_id = id * 36 + c - '0';
              else if (IS_UPPER (c))
              else if (IS_UPPER (c))
                new_id = id * 36 + c - 'A' + 10;
                new_id = id * 36 + c - 'A' + 10;
              else
              else
                return NULL;
                return NULL;
              if (new_id < id)
              if (new_id < id)
                return NULL;
                return NULL;
              id = new_id;
              id = new_id;
              c = d_next_char (di);
              c = d_next_char (di);
            }
            }
          while (c != '_');
          while (c != '_');
 
 
          ++id;
          ++id;
        }
        }
 
 
      if (id >= (unsigned int) di->next_sub)
      if (id >= (unsigned int) di->next_sub)
        return NULL;
        return NULL;
 
 
      ++di->did_subs;
      ++di->did_subs;
 
 
      return di->subs[id];
      return di->subs[id];
    }
    }
  else
  else
    {
    {
      int verbose;
      int verbose;
      const struct d_standard_sub_info *p;
      const struct d_standard_sub_info *p;
      const struct d_standard_sub_info *pend;
      const struct d_standard_sub_info *pend;
 
 
      verbose = (di->options & DMGL_VERBOSE) != 0;
      verbose = (di->options & DMGL_VERBOSE) != 0;
      if (! verbose && prefix)
      if (! verbose && prefix)
        {
        {
          char peek;
          char peek;
 
 
          peek = d_peek_char (di);
          peek = d_peek_char (di);
          if (peek == 'C' || peek == 'D')
          if (peek == 'C' || peek == 'D')
            verbose = 1;
            verbose = 1;
        }
        }
 
 
      pend = (&standard_subs[0]
      pend = (&standard_subs[0]
              + sizeof standard_subs / sizeof standard_subs[0]);
              + sizeof standard_subs / sizeof standard_subs[0]);
      for (p = &standard_subs[0]; p < pend; ++p)
      for (p = &standard_subs[0]; p < pend; ++p)
        {
        {
          if (c == p->code)
          if (c == p->code)
            {
            {
              const char *s;
              const char *s;
              int len;
              int len;
 
 
              if (p->set_last_name != NULL)
              if (p->set_last_name != NULL)
                di->last_name = d_make_sub (di, p->set_last_name,
                di->last_name = d_make_sub (di, p->set_last_name,
                                            p->set_last_name_len);
                                            p->set_last_name_len);
              if (verbose)
              if (verbose)
                {
                {
                  s = p->full_expansion;
                  s = p->full_expansion;
                  len = p->full_len;
                  len = p->full_len;
                }
                }
              else
              else
                {
                {
                  s = p->simple_expansion;
                  s = p->simple_expansion;
                  len = p->simple_len;
                  len = p->simple_len;
                }
                }
              di->expansion += len;
              di->expansion += len;
              return d_make_sub (di, s, len);
              return d_make_sub (di, s, len);
            }
            }
        }
        }
 
 
      return NULL;
      return NULL;
    }
    }
}
}
 
 
/* Initialize a growable string.  */
/* Initialize a growable string.  */
 
 
static void
static void
d_growable_string_init (struct d_growable_string *dgs, size_t estimate)
d_growable_string_init (struct d_growable_string *dgs, size_t estimate)
{
{
  dgs->buf = NULL;
  dgs->buf = NULL;
  dgs->len = 0;
  dgs->len = 0;
  dgs->alc = 0;
  dgs->alc = 0;
  dgs->allocation_failure = 0;
  dgs->allocation_failure = 0;
 
 
  if (estimate > 0)
  if (estimate > 0)
    d_growable_string_resize (dgs, estimate);
    d_growable_string_resize (dgs, estimate);
}
}
 
 
/* Grow a growable string to a given size.  */
/* Grow a growable string to a given size.  */
 
 
static inline void
static inline void
d_growable_string_resize (struct d_growable_string *dgs, size_t need)
d_growable_string_resize (struct d_growable_string *dgs, size_t need)
{
{
  size_t newalc;
  size_t newalc;
  char *newbuf;
  char *newbuf;
 
 
  if (dgs->allocation_failure)
  if (dgs->allocation_failure)
    return;
    return;
 
 
  /* Start allocation at two bytes to avoid any possibility of confusion
  /* Start allocation at two bytes to avoid any possibility of confusion
     with the special value of 1 used as a return in *palc to indicate
     with the special value of 1 used as a return in *palc to indicate
     allocation failures.  */
     allocation failures.  */
  newalc = dgs->alc > 0 ? dgs->alc : 2;
  newalc = dgs->alc > 0 ? dgs->alc : 2;
  while (newalc < need)
  while (newalc < need)
    newalc <<= 1;
    newalc <<= 1;
 
 
  newbuf = (char *) realloc (dgs->buf, newalc);
  newbuf = (char *) realloc (dgs->buf, newalc);
  if (newbuf == NULL)
  if (newbuf == NULL)
    {
    {
      free (dgs->buf);
      free (dgs->buf);
      dgs->buf = NULL;
      dgs->buf = NULL;
      dgs->len = 0;
      dgs->len = 0;
      dgs->alc = 0;
      dgs->alc = 0;
      dgs->allocation_failure = 1;
      dgs->allocation_failure = 1;
      return;
      return;
    }
    }
  dgs->buf = newbuf;
  dgs->buf = newbuf;
  dgs->alc = newalc;
  dgs->alc = newalc;
}
}
 
 
/* Append a buffer to a growable string.  */
/* Append a buffer to a growable string.  */
 
 
static inline void
static inline void
d_growable_string_append_buffer (struct d_growable_string *dgs,
d_growable_string_append_buffer (struct d_growable_string *dgs,
                                 const char *s, size_t l)
                                 const char *s, size_t l)
{
{
  size_t need;
  size_t need;
 
 
  need = dgs->len + l + 1;
  need = dgs->len + l + 1;
  if (need > dgs->alc)
  if (need > dgs->alc)
    d_growable_string_resize (dgs, need);
    d_growable_string_resize (dgs, need);
 
 
  if (dgs->allocation_failure)
  if (dgs->allocation_failure)
    return;
    return;
 
 
  memcpy (dgs->buf + dgs->len, s, l);
  memcpy (dgs->buf + dgs->len, s, l);
  dgs->buf[dgs->len + l] = '\0';
  dgs->buf[dgs->len + l] = '\0';
  dgs->len += l;
  dgs->len += l;
}
}
 
 
/* Bridge growable strings to the callback mechanism.  */
/* Bridge growable strings to the callback mechanism.  */
 
 
static void
static void
d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
{
{
  struct d_growable_string *dgs = (struct d_growable_string*) opaque;
  struct d_growable_string *dgs = (struct d_growable_string*) opaque;
 
 
  d_growable_string_append_buffer (dgs, s, l);
  d_growable_string_append_buffer (dgs, s, l);
}
}
 
 
/* Initialize a print information structure.  */
/* Initialize a print information structure.  */
 
 
static void
static void
d_print_init (struct d_print_info *dpi, int options,
d_print_init (struct d_print_info *dpi, int options,
              demangle_callbackref callback, void *opaque)
              demangle_callbackref callback, void *opaque)
{
{
  dpi->options = options;
  dpi->options = options;
  dpi->len = 0;
  dpi->len = 0;
  dpi->last_char = '\0';
  dpi->last_char = '\0';
  dpi->templates = NULL;
  dpi->templates = NULL;
  dpi->modifiers = NULL;
  dpi->modifiers = NULL;
 
 
  dpi->callback = callback;
  dpi->callback = callback;
  dpi->opaque = opaque;
  dpi->opaque = opaque;
 
 
  dpi->demangle_failure = 0;
  dpi->demangle_failure = 0;
}
}
 
 
/* Indicate that an error occurred during printing, and test for error.  */
/* Indicate that an error occurred during printing, and test for error.  */
 
 
static inline void
static inline void
d_print_error (struct d_print_info *dpi)
d_print_error (struct d_print_info *dpi)
{
{
  dpi->demangle_failure = 1;
  dpi->demangle_failure = 1;
}
}
 
 
static inline int
static inline int
d_print_saw_error (struct d_print_info *dpi)
d_print_saw_error (struct d_print_info *dpi)
{
{
  return dpi->demangle_failure != 0;
  return dpi->demangle_failure != 0;
}
}
 
 
/* Flush buffered characters to the callback.  */
/* Flush buffered characters to the callback.  */
 
 
static inline void
static inline void
d_print_flush (struct d_print_info *dpi)
d_print_flush (struct d_print_info *dpi)
{
{
  dpi->buf[dpi->len] = '\0';
  dpi->buf[dpi->len] = '\0';
  dpi->callback (dpi->buf, dpi->len, dpi->opaque);
  dpi->callback (dpi->buf, dpi->len, dpi->opaque);
  dpi->len = 0;
  dpi->len = 0;
}
}
 
 
/* Append characters and buffers for printing.  */
/* Append characters and buffers for printing.  */
 
 
static inline void
static inline void
d_append_char (struct d_print_info *dpi, char c)
d_append_char (struct d_print_info *dpi, char c)
{
{
  if (dpi->len == sizeof (dpi->buf) - 1)
  if (dpi->len == sizeof (dpi->buf) - 1)
    d_print_flush (dpi);
    d_print_flush (dpi);
 
 
  dpi->buf[dpi->len++] = c;
  dpi->buf[dpi->len++] = c;
  dpi->last_char = c;
  dpi->last_char = c;
}
}
 
 
static inline void
static inline void
d_append_buffer (struct d_print_info *dpi, const char *s, size_t l)
d_append_buffer (struct d_print_info *dpi, const char *s, size_t l)
{
{
  size_t i;
  size_t i;
 
 
  for (i = 0; i < l; i++)
  for (i = 0; i < l; i++)
    d_append_char (dpi, s[i]);
    d_append_char (dpi, s[i]);
}
}
 
 
static inline void
static inline void
d_append_string (struct d_print_info *dpi, const char *s)
d_append_string (struct d_print_info *dpi, const char *s)
{
{
  d_append_buffer (dpi, s, strlen (s));
  d_append_buffer (dpi, s, strlen (s));
}
}
 
 
static inline void
static inline void
d_append_num (struct d_print_info *dpi, long l)
d_append_num (struct d_print_info *dpi, long l)
{
{
  char buf[25];
  char buf[25];
  sprintf (buf,"%ld", l);
  sprintf (buf,"%ld", l);
  d_append_string (dpi, buf);
  d_append_string (dpi, buf);
}
}
 
 
static inline char
static inline char
d_last_char (struct d_print_info *dpi)
d_last_char (struct d_print_info *dpi)
{
{
  return dpi->last_char;
  return dpi->last_char;
}
}
 
 
/* Turn components into a human readable string.  OPTIONS is the
/* Turn components into a human readable string.  OPTIONS is the
   options bits passed to the demangler.  DC is the tree to print.
   options bits passed to the demangler.  DC is the tree to print.
   CALLBACK is a function to call to flush demangled string segments
   CALLBACK is a function to call to flush demangled string segments
   as they fill the intermediate buffer, and OPAQUE is a generalized
   as they fill the intermediate buffer, and OPAQUE is a generalized
   callback argument.  On success, this returns 1.  On failure,
   callback argument.  On success, this returns 1.  On failure,
   it returns 0, indicating a bad parse.  It does not use heap
   it returns 0, indicating a bad parse.  It does not use heap
   memory to build an output string, so cannot encounter memory
   memory to build an output string, so cannot encounter memory
   allocation failure.  */
   allocation failure.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
int
int
cplus_demangle_print_callback (int options,
cplus_demangle_print_callback (int options,
                               const struct demangle_component *dc,
                               const struct demangle_component *dc,
                               demangle_callbackref callback, void *opaque)
                               demangle_callbackref callback, void *opaque)
{
{
  struct d_print_info dpi;
  struct d_print_info dpi;
 
 
  d_print_init (&dpi, options, callback, opaque);
  d_print_init (&dpi, options, callback, opaque);
 
 
  d_print_comp (&dpi, dc);
  d_print_comp (&dpi, dc);
 
 
  d_print_flush (&dpi);
  d_print_flush (&dpi);
 
 
  return ! d_print_saw_error (&dpi);
  return ! d_print_saw_error (&dpi);
}
}
 
 
/* Turn components into a human readable string.  OPTIONS is the
/* Turn components into a human readable string.  OPTIONS is the
   options bits passed to the demangler.  DC is the tree to print.
   options bits passed to the demangler.  DC is the tree to print.
   ESTIMATE is a guess at the length of the result.  This returns a
   ESTIMATE is a guess at the length of the result.  This returns a
   string allocated by malloc, or NULL on error.  On success, this
   string allocated by malloc, or NULL on error.  On success, this
   sets *PALC to the size of the allocated buffer.  On failure, this
   sets *PALC to the size of the allocated buffer.  On failure, this
   sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
   sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
   failure.  */
   failure.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
char *
char *
cplus_demangle_print (int options, const struct demangle_component *dc,
cplus_demangle_print (int options, const struct demangle_component *dc,
                      int estimate, size_t *palc)
                      int estimate, size_t *palc)
{
{
  struct d_growable_string dgs;
  struct d_growable_string dgs;
 
 
  d_growable_string_init (&dgs, estimate);
  d_growable_string_init (&dgs, estimate);
 
 
  if (! cplus_demangle_print_callback (options, dc,
  if (! cplus_demangle_print_callback (options, dc,
                                       d_growable_string_callback_adapter,
                                       d_growable_string_callback_adapter,
                                       &dgs))
                                       &dgs))
    {
    {
      free (dgs.buf);
      free (dgs.buf);
      *palc = 0;
      *palc = 0;
      return NULL;
      return NULL;
    }
    }
 
 
  *palc = dgs.allocation_failure ? 1 : dgs.alc;
  *palc = dgs.allocation_failure ? 1 : dgs.alc;
  return dgs.buf;
  return dgs.buf;
}
}
 
 
/* Returns the I'th element of the template arglist ARGS, or NULL on
/* Returns the I'th element of the template arglist ARGS, or NULL on
   failure.  */
   failure.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_index_template_argument (struct demangle_component *args, int i)
d_index_template_argument (struct demangle_component *args, int i)
{
{
  struct demangle_component *a;
  struct demangle_component *a;
 
 
  for (a = args;
  for (a = args;
       a != NULL;
       a != NULL;
       a = d_right (a))
       a = d_right (a))
    {
    {
      if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
      if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
        return NULL;
        return NULL;
      if (i <= 0)
      if (i <= 0)
        break;
        break;
      --i;
      --i;
    }
    }
  if (i != 0 || a == NULL)
  if (i != 0 || a == NULL)
    return NULL;
    return NULL;
 
 
  return d_left (a);
  return d_left (a);
}
}
 
 
/* Returns the template argument from the current context indicated by DC,
/* Returns the template argument from the current context indicated by DC,
   which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL.  */
   which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_lookup_template_argument (struct d_print_info *dpi,
d_lookup_template_argument (struct d_print_info *dpi,
                            const struct demangle_component *dc)
                            const struct demangle_component *dc)
{
{
  if (dpi->templates == NULL)
  if (dpi->templates == NULL)
    {
    {
      d_print_error (dpi);
      d_print_error (dpi);
      return NULL;
      return NULL;
    }
    }
 
 
  return d_index_template_argument
  return d_index_template_argument
    (d_right (dpi->templates->template_decl),
    (d_right (dpi->templates->template_decl),
     dc->u.s_number.number);
     dc->u.s_number.number);
}
}
 
 
/* Returns a template argument pack used in DC (any will do), or NULL.  */
/* Returns a template argument pack used in DC (any will do), or NULL.  */
 
 
static struct demangle_component *
static struct demangle_component *
d_find_pack (struct d_print_info *dpi,
d_find_pack (struct d_print_info *dpi,
             const struct demangle_component *dc)
             const struct demangle_component *dc)
{
{
  struct demangle_component *a;
  struct demangle_component *a;
  if (dc == NULL)
  if (dc == NULL)
    return NULL;
    return NULL;
 
 
  switch (dc->type)
  switch (dc->type)
    {
    {
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
      a = d_lookup_template_argument (dpi, dc);
      a = d_lookup_template_argument (dpi, dc);
      if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
      if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
        return a;
        return a;
      return NULL;
      return NULL;
 
 
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
      return NULL;
      return NULL;
 
 
    case DEMANGLE_COMPONENT_NAME:
    case DEMANGLE_COMPONENT_NAME:
    case DEMANGLE_COMPONENT_OPERATOR:
    case DEMANGLE_COMPONENT_OPERATOR:
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
    case DEMANGLE_COMPONENT_SUB_STD:
    case DEMANGLE_COMPONENT_SUB_STD:
    case DEMANGLE_COMPONENT_CHARACTER:
    case DEMANGLE_COMPONENT_CHARACTER:
    case DEMANGLE_COMPONENT_FUNCTION_PARAM:
    case DEMANGLE_COMPONENT_FUNCTION_PARAM:
      return NULL;
      return NULL;
 
 
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
      return d_find_pack (dpi, dc->u.s_extended_operator.name);
      return d_find_pack (dpi, dc->u.s_extended_operator.name);
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_CTOR:
      return d_find_pack (dpi, dc->u.s_ctor.name);
      return d_find_pack (dpi, dc->u.s_ctor.name);
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_DTOR:
      return d_find_pack (dpi, dc->u.s_dtor.name);
      return d_find_pack (dpi, dc->u.s_dtor.name);
 
 
    default:
    default:
      a = d_find_pack (dpi, d_left (dc));
      a = d_find_pack (dpi, d_left (dc));
      if (a)
      if (a)
        return a;
        return a;
      return d_find_pack (dpi, d_right (dc));
      return d_find_pack (dpi, d_right (dc));
    }
    }
}
}
 
 
/* Returns the length of the template argument pack DC.  */
/* Returns the length of the template argument pack DC.  */
 
 
static int
static int
d_pack_length (const struct demangle_component *dc)
d_pack_length (const struct demangle_component *dc)
{
{
  int count = 0;
  int count = 0;
  while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST
  while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST
         && d_left (dc) != NULL)
         && d_left (dc) != NULL)
    {
    {
      ++count;
      ++count;
      dc = d_right (dc);
      dc = d_right (dc);
    }
    }
  return count;
  return count;
}
}
 
 
/* DC is a component of a mangled expression.  Print it, wrapped in parens
/* DC is a component of a mangled expression.  Print it, wrapped in parens
   if needed.  */
   if needed.  */
 
 
static void
static void
d_print_subexpr (struct d_print_info *dpi,
d_print_subexpr (struct d_print_info *dpi,
                 const struct demangle_component *dc)
                 const struct demangle_component *dc)
{
{
  int simple = 0;
  int simple = 0;
  if (dc->type == DEMANGLE_COMPONENT_NAME
  if (dc->type == DEMANGLE_COMPONENT_NAME
      || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
      || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
    simple = 1;
    simple = 1;
  if (!simple)
  if (!simple)
    d_append_char (dpi, '(');
    d_append_char (dpi, '(');
  d_print_comp (dpi, dc);
  d_print_comp (dpi, dc);
  if (!simple)
  if (!simple)
    d_append_char (dpi, ')');
    d_append_char (dpi, ')');
}
}
 
 
/* Subroutine to handle components.  */
/* Subroutine to handle components.  */
 
 
static void
static void
d_print_comp (struct d_print_info *dpi,
d_print_comp (struct d_print_info *dpi,
              const struct demangle_component *dc)
              const struct demangle_component *dc)
{
{
  if (dc == NULL)
  if (dc == NULL)
    {
    {
      d_print_error (dpi);
      d_print_error (dpi);
      return;
      return;
    }
    }
  if (d_print_saw_error (dpi))
  if (d_print_saw_error (dpi))
    return;
    return;
 
 
  switch (dc->type)
  switch (dc->type)
    {
    {
    case DEMANGLE_COMPONENT_NAME:
    case DEMANGLE_COMPONENT_NAME:
      if ((dpi->options & DMGL_JAVA) == 0)
      if ((dpi->options & DMGL_JAVA) == 0)
        d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len);
        d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len);
      else
      else
        d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
        d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      if ((dpi->options & DMGL_JAVA) == 0)
      if ((dpi->options & DMGL_JAVA) == 0)
        d_append_string (dpi, "::");
        d_append_string (dpi, "::");
      else
      else
        d_append_char (dpi, '.');
        d_append_char (dpi, '.');
      d_print_comp (dpi, d_right (dc));
      d_print_comp (dpi, d_right (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
      {
      {
        struct d_print_mod *hold_modifiers;
        struct d_print_mod *hold_modifiers;
        struct demangle_component *typed_name;
        struct demangle_component *typed_name;
        struct d_print_mod adpm[4];
        struct d_print_mod adpm[4];
        unsigned int i;
        unsigned int i;
        struct d_print_template dpt;
        struct d_print_template dpt;
 
 
        /* Pass the name down to the type so that it can be printed in
        /* Pass the name down to the type so that it can be printed in
           the right place for the type.  We also have to pass down
           the right place for the type.  We also have to pass down
           any CV-qualifiers, which apply to the this parameter.  */
           any CV-qualifiers, which apply to the this parameter.  */
        hold_modifiers = dpi->modifiers;
        hold_modifiers = dpi->modifiers;
        dpi->modifiers = 0;
        dpi->modifiers = 0;
        i = 0;
        i = 0;
        typed_name = d_left (dc);
        typed_name = d_left (dc);
        while (typed_name != NULL)
        while (typed_name != NULL)
          {
          {
            if (i >= sizeof adpm / sizeof adpm[0])
            if (i >= sizeof adpm / sizeof adpm[0])
              {
              {
                d_print_error (dpi);
                d_print_error (dpi);
                return;
                return;
              }
              }
 
 
            adpm[i].next = dpi->modifiers;
            adpm[i].next = dpi->modifiers;
            dpi->modifiers = &adpm[i];
            dpi->modifiers = &adpm[i];
            adpm[i].mod = typed_name;
            adpm[i].mod = typed_name;
            adpm[i].printed = 0;
            adpm[i].printed = 0;
            adpm[i].templates = dpi->templates;
            adpm[i].templates = dpi->templates;
            ++i;
            ++i;
 
 
            if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
            if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
                && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
                && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
                && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS)
                && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS)
              break;
              break;
 
 
            typed_name = d_left (typed_name);
            typed_name = d_left (typed_name);
          }
          }
 
 
        if (typed_name == NULL)
        if (typed_name == NULL)
          {
          {
            d_print_error (dpi);
            d_print_error (dpi);
            return;
            return;
          }
          }
 
 
        /* If typed_name is a template, then it applies to the
        /* If typed_name is a template, then it applies to the
           function type as well.  */
           function type as well.  */
        if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
        if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
          {
          {
            dpt.next = dpi->templates;
            dpt.next = dpi->templates;
            dpi->templates = &dpt;
            dpi->templates = &dpt;
            dpt.template_decl = typed_name;
            dpt.template_decl = typed_name;
          }
          }
 
 
        /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
        /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
           there may be CV-qualifiers on its right argument which
           there may be CV-qualifiers on its right argument which
           really apply here; this happens when parsing a class which
           really apply here; this happens when parsing a class which
           is local to a function.  */
           is local to a function.  */
        if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
        if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
          {
          {
            struct demangle_component *local_name;
            struct demangle_component *local_name;
 
 
            local_name = d_right (typed_name);
            local_name = d_right (typed_name);
            if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
            if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
              local_name = local_name->u.s_unary_num.sub;
              local_name = local_name->u.s_unary_num.sub;
            while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
            while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
                   || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                   || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
                   || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
                   || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
              {
              {
                if (i >= sizeof adpm / sizeof adpm[0])
                if (i >= sizeof adpm / sizeof adpm[0])
                  {
                  {
                    d_print_error (dpi);
                    d_print_error (dpi);
                    return;
                    return;
                  }
                  }
 
 
                adpm[i] = adpm[i - 1];
                adpm[i] = adpm[i - 1];
                adpm[i].next = &adpm[i - 1];
                adpm[i].next = &adpm[i - 1];
                dpi->modifiers = &adpm[i];
                dpi->modifiers = &adpm[i];
 
 
                adpm[i - 1].mod = local_name;
                adpm[i - 1].mod = local_name;
                adpm[i - 1].printed = 0;
                adpm[i - 1].printed = 0;
                adpm[i - 1].templates = dpi->templates;
                adpm[i - 1].templates = dpi->templates;
                ++i;
                ++i;
 
 
                local_name = d_left (local_name);
                local_name = d_left (local_name);
              }
              }
          }
          }
 
 
        d_print_comp (dpi, d_right (dc));
        d_print_comp (dpi, d_right (dc));
 
 
        if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
        if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
          dpi->templates = dpt.next;
          dpi->templates = dpt.next;
 
 
        /* If the modifiers didn't get printed by the type, print them
        /* If the modifiers didn't get printed by the type, print them
           now.  */
           now.  */
        while (i > 0)
        while (i > 0)
          {
          {
            --i;
            --i;
            if (! adpm[i].printed)
            if (! adpm[i].printed)
              {
              {
                d_append_char (dpi, ' ');
                d_append_char (dpi, ' ');
                d_print_mod (dpi, adpm[i].mod);
                d_print_mod (dpi, adpm[i].mod);
              }
              }
          }
          }
 
 
        dpi->modifiers = hold_modifiers;
        dpi->modifiers = hold_modifiers;
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_TEMPLATE:
      {
      {
        struct d_print_mod *hold_dpm;
        struct d_print_mod *hold_dpm;
        struct demangle_component *dcl;
        struct demangle_component *dcl;
 
 
        /* Don't push modifiers into a template definition.  Doing so
        /* Don't push modifiers into a template definition.  Doing so
           could give the wrong definition for a template argument.
           could give the wrong definition for a template argument.
           Instead, treat the template essentially as a name.  */
           Instead, treat the template essentially as a name.  */
 
 
        hold_dpm = dpi->modifiers;
        hold_dpm = dpi->modifiers;
        dpi->modifiers = NULL;
        dpi->modifiers = NULL;
 
 
        dcl = d_left (dc);
        dcl = d_left (dc);
 
 
        if ((dpi->options & DMGL_JAVA) != 0
        if ((dpi->options & DMGL_JAVA) != 0
            && dcl->type == DEMANGLE_COMPONENT_NAME
            && dcl->type == DEMANGLE_COMPONENT_NAME
            && dcl->u.s_name.len == 6
            && dcl->u.s_name.len == 6
            && strncmp (dcl->u.s_name.s, "JArray", 6) == 0)
            && strncmp (dcl->u.s_name.s, "JArray", 6) == 0)
          {
          {
            /* Special-case Java arrays, so that JArray<TYPE> appears
            /* Special-case Java arrays, so that JArray<TYPE> appears
               instead as TYPE[].  */
               instead as TYPE[].  */
 
 
            d_print_comp (dpi, d_right (dc));
            d_print_comp (dpi, d_right (dc));
            d_append_string (dpi, "[]");
            d_append_string (dpi, "[]");
          }
          }
        else
        else
          {
          {
            d_print_comp (dpi, dcl);
            d_print_comp (dpi, dcl);
            if (d_last_char (dpi) == '<')
            if (d_last_char (dpi) == '<')
              d_append_char (dpi, ' ');
              d_append_char (dpi, ' ');
            d_append_char (dpi, '<');
            d_append_char (dpi, '<');
            d_print_comp (dpi, d_right (dc));
            d_print_comp (dpi, d_right (dc));
            /* Avoid generating two consecutive '>' characters, to avoid
            /* Avoid generating two consecutive '>' characters, to avoid
               the C++ syntactic ambiguity.  */
               the C++ syntactic ambiguity.  */
            if (d_last_char (dpi) == '>')
            if (d_last_char (dpi) == '>')
              d_append_char (dpi, ' ');
              d_append_char (dpi, ' ');
            d_append_char (dpi, '>');
            d_append_char (dpi, '>');
          }
          }
 
 
        dpi->modifiers = hold_dpm;
        dpi->modifiers = hold_dpm;
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
      {
      {
        struct d_print_template *hold_dpt;
        struct d_print_template *hold_dpt;
        struct demangle_component *a = d_lookup_template_argument (dpi, dc);
        struct demangle_component *a = d_lookup_template_argument (dpi, dc);
 
 
        if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
        if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
          a = d_index_template_argument (a, dpi->pack_index);
          a = d_index_template_argument (a, dpi->pack_index);
 
 
        if (a == NULL)
        if (a == NULL)
          {
          {
            d_print_error (dpi);
            d_print_error (dpi);
            return;
            return;
          }
          }
 
 
        /* While processing this parameter, we need to pop the list of
        /* While processing this parameter, we need to pop the list of
           templates.  This is because the template parameter may
           templates.  This is because the template parameter may
           itself be a reference to a parameter of an outer
           itself be a reference to a parameter of an outer
           template.  */
           template.  */
 
 
        hold_dpt = dpi->templates;
        hold_dpt = dpi->templates;
        dpi->templates = hold_dpt->next;
        dpi->templates = hold_dpt->next;
 
 
        d_print_comp (dpi, a);
        d_print_comp (dpi, a);
 
 
        dpi->templates = hold_dpt;
        dpi->templates = hold_dpt;
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_CTOR:
      d_print_comp (dpi, dc->u.s_ctor.name);
      d_print_comp (dpi, dc->u.s_ctor.name);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_DTOR:
      d_append_char (dpi, '~');
      d_append_char (dpi, '~');
      d_print_comp (dpi, dc->u.s_dtor.name);
      d_print_comp (dpi, dc->u.s_dtor.name);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_VTABLE:
    case DEMANGLE_COMPONENT_VTABLE:
      d_append_string (dpi, "vtable for ");
      d_append_string (dpi, "vtable for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_VTT:
    case DEMANGLE_COMPONENT_VTT:
      d_append_string (dpi, "VTT for ");
      d_append_string (dpi, "VTT for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
    case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
      d_append_string (dpi, "construction vtable for ");
      d_append_string (dpi, "construction vtable for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      d_append_string (dpi, "-in-");
      d_append_string (dpi, "-in-");
      d_print_comp (dpi, d_right (dc));
      d_print_comp (dpi, d_right (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TYPEINFO:
    case DEMANGLE_COMPONENT_TYPEINFO:
      d_append_string (dpi, "typeinfo for ");
      d_append_string (dpi, "typeinfo for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
    case DEMANGLE_COMPONENT_TYPEINFO_NAME:
      d_append_string (dpi, "typeinfo name for ");
      d_append_string (dpi, "typeinfo name for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
    case DEMANGLE_COMPONENT_TYPEINFO_FN:
      d_append_string (dpi, "typeinfo fn for ");
      d_append_string (dpi, "typeinfo fn for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_THUNK:
    case DEMANGLE_COMPONENT_THUNK:
      d_append_string (dpi, "non-virtual thunk to ");
      d_append_string (dpi, "non-virtual thunk to ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
    case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
      d_append_string (dpi, "virtual thunk to ");
      d_append_string (dpi, "virtual thunk to ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
    case DEMANGLE_COMPONENT_COVARIANT_THUNK:
      d_append_string (dpi, "covariant return thunk to ");
      d_append_string (dpi, "covariant return thunk to ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
      d_append_string (dpi, "java Class for ");
      d_append_string (dpi, "java Class for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_GUARD:
    case DEMANGLE_COMPONENT_GUARD:
      d_append_string (dpi, "guard variable for ");
      d_append_string (dpi, "guard variable for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_REFTEMP:
    case DEMANGLE_COMPONENT_REFTEMP:
      d_append_string (dpi, "reference temporary for ");
      d_append_string (dpi, "reference temporary for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
    case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
      d_append_string (dpi, "hidden alias for ");
      d_append_string (dpi, "hidden alias for ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_SUB_STD:
    case DEMANGLE_COMPONENT_SUB_STD:
      d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len);
      d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST:
      {
      {
        struct d_print_mod *pdpm;
        struct d_print_mod *pdpm;
 
 
        /* When printing arrays, it's possible to have cases where the
        /* When printing arrays, it's possible to have cases where the
           same CV-qualifier gets pushed on the stack multiple times.
           same CV-qualifier gets pushed on the stack multiple times.
           We only need to print it once.  */
           We only need to print it once.  */
 
 
        for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next)
        for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next)
          {
          {
            if (! pdpm->printed)
            if (! pdpm->printed)
              {
              {
                if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT
                if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT
                    && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE
                    && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE
                    && pdpm->mod->type != DEMANGLE_COMPONENT_CONST)
                    && pdpm->mod->type != DEMANGLE_COMPONENT_CONST)
                  break;
                  break;
                if (pdpm->mod->type == dc->type)
                if (pdpm->mod->type == dc->type)
                  {
                  {
                    d_print_comp (dpi, d_left (dc));
                    d_print_comp (dpi, d_left (dc));
                    return;
                    return;
                  }
                  }
              }
              }
          }
          }
      }
      }
      /* Fall through.  */
      /* Fall through.  */
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_IMAGINARY:
      {
      {
        /* We keep a list of modifiers on the stack.  */
        /* We keep a list of modifiers on the stack.  */
        struct d_print_mod dpm;
        struct d_print_mod dpm;
 
 
        dpm.next = dpi->modifiers;
        dpm.next = dpi->modifiers;
        dpi->modifiers = &dpm;
        dpi->modifiers = &dpm;
        dpm.mod = dc;
        dpm.mod = dc;
        dpm.printed = 0;
        dpm.printed = 0;
        dpm.templates = dpi->templates;
        dpm.templates = dpi->templates;
 
 
        d_print_comp (dpi, d_left (dc));
        d_print_comp (dpi, d_left (dc));
 
 
        /* If the modifier didn't get printed by the type, print it
        /* If the modifier didn't get printed by the type, print it
           now.  */
           now.  */
        if (! dpm.printed)
        if (! dpm.printed)
          d_print_mod (dpi, dc);
          d_print_mod (dpi, dc);
 
 
        dpi->modifiers = dpm.next;
        dpi->modifiers = dpm.next;
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
      if ((dpi->options & DMGL_JAVA) == 0)
      if ((dpi->options & DMGL_JAVA) == 0)
        d_append_buffer (dpi, dc->u.s_builtin.type->name,
        d_append_buffer (dpi, dc->u.s_builtin.type->name,
                         dc->u.s_builtin.type->len);
                         dc->u.s_builtin.type->len);
      else
      else
        d_append_buffer (dpi, dc->u.s_builtin.type->java_name,
        d_append_buffer (dpi, dc->u.s_builtin.type->java_name,
                         dc->u.s_builtin.type->java_len);
                         dc->u.s_builtin.type->java_len);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
      {
      {
        if ((dpi->options & DMGL_RET_POSTFIX) != 0)
        if ((dpi->options & DMGL_RET_POSTFIX) != 0)
          d_print_function_type (dpi, dc, dpi->modifiers);
          d_print_function_type (dpi, dc, dpi->modifiers);
 
 
        /* Print return type if present */
        /* Print return type if present */
        if (d_left (dc) != NULL)
        if (d_left (dc) != NULL)
          {
          {
            struct d_print_mod dpm;
            struct d_print_mod dpm;
 
 
            /* We must pass this type down as a modifier in order to
            /* We must pass this type down as a modifier in order to
               print it in the right location.  */
               print it in the right location.  */
            dpm.next = dpi->modifiers;
            dpm.next = dpi->modifiers;
            dpi->modifiers = &dpm;
            dpi->modifiers = &dpm;
            dpm.mod = dc;
            dpm.mod = dc;
            dpm.printed = 0;
            dpm.printed = 0;
            dpm.templates = dpi->templates;
            dpm.templates = dpi->templates;
 
 
            d_print_comp (dpi, d_left (dc));
            d_print_comp (dpi, d_left (dc));
 
 
            dpi->modifiers = dpm.next;
            dpi->modifiers = dpm.next;
 
 
            if (dpm.printed)
            if (dpm.printed)
              return;
              return;
 
 
            /* In standard prefix notation, there is a space between the
            /* In standard prefix notation, there is a space between the
               return type and the function signature.  */
               return type and the function signature.  */
            if ((dpi->options & DMGL_RET_POSTFIX) == 0)
            if ((dpi->options & DMGL_RET_POSTFIX) == 0)
              d_append_char (dpi, ' ');
              d_append_char (dpi, ' ');
          }
          }
 
 
        if ((dpi->options & DMGL_RET_POSTFIX) == 0)
        if ((dpi->options & DMGL_RET_POSTFIX) == 0)
          d_print_function_type (dpi, dc, dpi->modifiers);
          d_print_function_type (dpi, dc, dpi->modifiers);
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
      {
      {
        struct d_print_mod *hold_modifiers;
        struct d_print_mod *hold_modifiers;
        struct d_print_mod adpm[4];
        struct d_print_mod adpm[4];
        unsigned int i;
        unsigned int i;
        struct d_print_mod *pdpm;
        struct d_print_mod *pdpm;
 
 
        /* We must pass this type down as a modifier in order to print
        /* We must pass this type down as a modifier in order to print
           multi-dimensional arrays correctly.  If the array itself is
           multi-dimensional arrays correctly.  If the array itself is
           CV-qualified, we act as though the element type were
           CV-qualified, we act as though the element type were
           CV-qualified.  We do this by copying the modifiers down
           CV-qualified.  We do this by copying the modifiers down
           rather than fiddling pointers, so that we don't wind up
           rather than fiddling pointers, so that we don't wind up
           with a d_print_mod higher on the stack pointing into our
           with a d_print_mod higher on the stack pointing into our
           stack frame after we return.  */
           stack frame after we return.  */
 
 
        hold_modifiers = dpi->modifiers;
        hold_modifiers = dpi->modifiers;
 
 
        adpm[0].next = hold_modifiers;
        adpm[0].next = hold_modifiers;
        dpi->modifiers = &adpm[0];
        dpi->modifiers = &adpm[0];
        adpm[0].mod = dc;
        adpm[0].mod = dc;
        adpm[0].printed = 0;
        adpm[0].printed = 0;
        adpm[0].templates = dpi->templates;
        adpm[0].templates = dpi->templates;
 
 
        i = 1;
        i = 1;
        pdpm = hold_modifiers;
        pdpm = hold_modifiers;
        while (pdpm != NULL
        while (pdpm != NULL
               && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT
               && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT
                   || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE
                   || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE
                   || pdpm->mod->type == DEMANGLE_COMPONENT_CONST))
                   || pdpm->mod->type == DEMANGLE_COMPONENT_CONST))
          {
          {
            if (! pdpm->printed)
            if (! pdpm->printed)
              {
              {
                if (i >= sizeof adpm / sizeof adpm[0])
                if (i >= sizeof adpm / sizeof adpm[0])
                  {
                  {
                    d_print_error (dpi);
                    d_print_error (dpi);
                    return;
                    return;
                  }
                  }
 
 
                adpm[i] = *pdpm;
                adpm[i] = *pdpm;
                adpm[i].next = dpi->modifiers;
                adpm[i].next = dpi->modifiers;
                dpi->modifiers = &adpm[i];
                dpi->modifiers = &adpm[i];
                pdpm->printed = 1;
                pdpm->printed = 1;
                ++i;
                ++i;
              }
              }
 
 
            pdpm = pdpm->next;
            pdpm = pdpm->next;
          }
          }
 
 
        d_print_comp (dpi, d_right (dc));
        d_print_comp (dpi, d_right (dc));
 
 
        dpi->modifiers = hold_modifiers;
        dpi->modifiers = hold_modifiers;
 
 
        if (adpm[0].printed)
        if (adpm[0].printed)
          return;
          return;
 
 
        while (i > 1)
        while (i > 1)
          {
          {
            --i;
            --i;
            d_print_mod (dpi, adpm[i].mod);
            d_print_mod (dpi, adpm[i].mod);
          }
          }
 
 
        d_print_array_type (dpi, dc, dpi->modifiers);
        d_print_array_type (dpi, dc, dpi->modifiers);
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
      {
      {
        struct d_print_mod dpm;
        struct d_print_mod dpm;
 
 
        dpm.next = dpi->modifiers;
        dpm.next = dpi->modifiers;
        dpi->modifiers = &dpm;
        dpi->modifiers = &dpm;
        dpm.mod = dc;
        dpm.mod = dc;
        dpm.printed = 0;
        dpm.printed = 0;
        dpm.templates = dpi->templates;
        dpm.templates = dpi->templates;
 
 
        d_print_comp (dpi, d_right (dc));
        d_print_comp (dpi, d_right (dc));
 
 
        /* If the modifier didn't get printed by the type, print it
        /* If the modifier didn't get printed by the type, print it
           now.  */
           now.  */
        if (! dpm.printed)
        if (! dpm.printed)
          d_print_mod (dpi, dc);
          d_print_mod (dpi, dc);
 
 
        dpi->modifiers = dpm.next;
        dpi->modifiers = dpm.next;
 
 
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_FIXED_TYPE:
    case DEMANGLE_COMPONENT_FIXED_TYPE:
      if (dc->u.s_fixed.sat)
      if (dc->u.s_fixed.sat)
        d_append_string (dpi, "_Sat ");
        d_append_string (dpi, "_Sat ");
      /* Don't print "int _Accum".  */
      /* Don't print "int _Accum".  */
      if (dc->u.s_fixed.length->u.s_builtin.type
      if (dc->u.s_fixed.length->u.s_builtin.type
          != &cplus_demangle_builtin_types['i'-'a'])
          != &cplus_demangle_builtin_types['i'-'a'])
        {
        {
          d_print_comp (dpi, dc->u.s_fixed.length);
          d_print_comp (dpi, dc->u.s_fixed.length);
          d_append_char (dpi, ' ');
          d_append_char (dpi, ' ');
        }
        }
      if (dc->u.s_fixed.accum)
      if (dc->u.s_fixed.accum)
        d_append_string (dpi, "_Accum");
        d_append_string (dpi, "_Accum");
      else
      else
        d_append_string (dpi, "_Fract");
        d_append_string (dpi, "_Fract");
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
    case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
      if (d_left (dc) != NULL)
      if (d_left (dc) != NULL)
        d_print_comp (dpi, d_left (dc));
        d_print_comp (dpi, d_left (dc));
      if (d_right (dc) != NULL)
      if (d_right (dc) != NULL)
        {
        {
          size_t len;
          size_t len;
          d_append_string (dpi, ", ");
          d_append_string (dpi, ", ");
          len = dpi->len;
          len = dpi->len;
          d_print_comp (dpi, d_right (dc));
          d_print_comp (dpi, d_right (dc));
          /* If that didn't print anything (which can happen with empty
          /* If that didn't print anything (which can happen with empty
             template argument packs), remove the comma and space.  */
             template argument packs), remove the comma and space.  */
          if (dpi->len == len)
          if (dpi->len == len)
            dpi->len -= 2;
            dpi->len -= 2;
        }
        }
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_OPERATOR:
    case DEMANGLE_COMPONENT_OPERATOR:
      {
      {
        char c;
        char c;
 
 
        d_append_string (dpi, "operator");
        d_append_string (dpi, "operator");
        c = dc->u.s_operator.op->name[0];
        c = dc->u.s_operator.op->name[0];
        if (IS_LOWER (c))
        if (IS_LOWER (c))
          d_append_char (dpi, ' ');
          d_append_char (dpi, ' ');
        d_append_buffer (dpi, dc->u.s_operator.op->name,
        d_append_buffer (dpi, dc->u.s_operator.op->name,
                         dc->u.s_operator.op->len);
                         dc->u.s_operator.op->len);
        return;
        return;
      }
      }
 
 
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
    case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
      d_append_string (dpi, "operator ");
      d_append_string (dpi, "operator ");
      d_print_comp (dpi, dc->u.s_extended_operator.name);
      d_print_comp (dpi, dc->u.s_extended_operator.name);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_CAST:
    case DEMANGLE_COMPONENT_CAST:
      d_append_string (dpi, "operator ");
      d_append_string (dpi, "operator ");
      d_print_cast (dpi, dc);
      d_print_cast (dpi, dc);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_UNARY:
    case DEMANGLE_COMPONENT_UNARY:
      if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST)
      if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST)
        d_print_expr_op (dpi, d_left (dc));
        d_print_expr_op (dpi, d_left (dc));
      else
      else
        {
        {
          d_append_char (dpi, '(');
          d_append_char (dpi, '(');
          d_print_cast (dpi, d_left (dc));
          d_print_cast (dpi, d_left (dc));
          d_append_char (dpi, ')');
          d_append_char (dpi, ')');
        }
        }
      d_print_subexpr (dpi, d_right (dc));
      d_print_subexpr (dpi, d_right (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_BINARY:
    case DEMANGLE_COMPONENT_BINARY:
      if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS)
      if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS)
        {
        {
          d_print_error (dpi);
          d_print_error (dpi);
          return;
          return;
        }
        }
 
 
      /* We wrap an expression which uses the greater-than operator in
      /* We wrap an expression which uses the greater-than operator in
         an extra layer of parens so that it does not get confused
         an extra layer of parens so that it does not get confused
         with the '>' which ends the template parameters.  */
         with the '>' which ends the template parameters.  */
      if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
      if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
          && d_left (dc)->u.s_operator.op->len == 1
          && d_left (dc)->u.s_operator.op->len == 1
          && d_left (dc)->u.s_operator.op->name[0] == '>')
          && d_left (dc)->u.s_operator.op->name[0] == '>')
        d_append_char (dpi, '(');
        d_append_char (dpi, '(');
 
 
      d_print_subexpr (dpi, d_left (d_right (dc)));
      d_print_subexpr (dpi, d_left (d_right (dc)));
      if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0)
      if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0)
        {
        {
          d_append_char (dpi, '[');
          d_append_char (dpi, '[');
          d_print_comp (dpi, d_right (d_right (dc)));
          d_print_comp (dpi, d_right (d_right (dc)));
          d_append_char (dpi, ']');
          d_append_char (dpi, ']');
        }
        }
      else
      else
        {
        {
          if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0)
          if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0)
            d_print_expr_op (dpi, d_left (dc));
            d_print_expr_op (dpi, d_left (dc));
          d_print_subexpr (dpi, d_right (d_right (dc)));
          d_print_subexpr (dpi, d_right (d_right (dc)));
        }
        }
 
 
      if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
      if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
          && d_left (dc)->u.s_operator.op->len == 1
          && d_left (dc)->u.s_operator.op->len == 1
          && d_left (dc)->u.s_operator.op->name[0] == '>')
          && d_left (dc)->u.s_operator.op->name[0] == '>')
        d_append_char (dpi, ')');
        d_append_char (dpi, ')');
 
 
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_BINARY_ARGS:
    case DEMANGLE_COMPONENT_BINARY_ARGS:
      /* We should only see this as part of DEMANGLE_COMPONENT_BINARY.  */
      /* We should only see this as part of DEMANGLE_COMPONENT_BINARY.  */
      d_print_error (dpi);
      d_print_error (dpi);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TRINARY:
    case DEMANGLE_COMPONENT_TRINARY:
      if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1
      if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1
          || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2)
          || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2)
        {
        {
          d_print_error (dpi);
          d_print_error (dpi);
          return;
          return;
        }
        }
      d_print_subexpr (dpi, d_left (d_right (dc)));
      d_print_subexpr (dpi, d_left (d_right (dc)));
      d_print_expr_op (dpi, d_left (dc));
      d_print_expr_op (dpi, d_left (dc));
      d_print_subexpr (dpi, d_left (d_right (d_right (dc))));
      d_print_subexpr (dpi, d_left (d_right (d_right (dc))));
      d_append_string (dpi, " : ");
      d_append_string (dpi, " : ");
      d_print_subexpr (dpi, d_right (d_right (d_right (dc))));
      d_print_subexpr (dpi, d_right (d_right (d_right (dc))));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
    case DEMANGLE_COMPONENT_TRINARY_ARG1:
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
    case DEMANGLE_COMPONENT_TRINARY_ARG2:
      /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY.  */
      /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY.  */
      d_print_error (dpi);
      d_print_error (dpi);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_LITERAL:
    case DEMANGLE_COMPONENT_LITERAL:
    case DEMANGLE_COMPONENT_LITERAL_NEG:
    case DEMANGLE_COMPONENT_LITERAL_NEG:
      {
      {
        enum d_builtin_type_print tp;
        enum d_builtin_type_print tp;
 
 
        /* For some builtin types, produce simpler output.  */
        /* For some builtin types, produce simpler output.  */
        tp = D_PRINT_DEFAULT;
        tp = D_PRINT_DEFAULT;
        if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)
        if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)
          {
          {
            tp = d_left (dc)->u.s_builtin.type->print;
            tp = d_left (dc)->u.s_builtin.type->print;
            switch (tp)
            switch (tp)
              {
              {
              case D_PRINT_INT:
              case D_PRINT_INT:
              case D_PRINT_UNSIGNED:
              case D_PRINT_UNSIGNED:
              case D_PRINT_LONG:
              case D_PRINT_LONG:
              case D_PRINT_UNSIGNED_LONG:
              case D_PRINT_UNSIGNED_LONG:
              case D_PRINT_LONG_LONG:
              case D_PRINT_LONG_LONG:
              case D_PRINT_UNSIGNED_LONG_LONG:
              case D_PRINT_UNSIGNED_LONG_LONG:
                if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME)
                if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME)
                  {
                  {
                    if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
                    if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
                      d_append_char (dpi, '-');
                      d_append_char (dpi, '-');
                    d_print_comp (dpi, d_right (dc));
                    d_print_comp (dpi, d_right (dc));
                    switch (tp)
                    switch (tp)
                      {
                      {
                      default:
                      default:
                        break;
                        break;
                      case D_PRINT_UNSIGNED:
                      case D_PRINT_UNSIGNED:
                        d_append_char (dpi, 'u');
                        d_append_char (dpi, 'u');
                        break;
                        break;
                      case D_PRINT_LONG:
                      case D_PRINT_LONG:
                        d_append_char (dpi, 'l');
                        d_append_char (dpi, 'l');
                        break;
                        break;
                      case D_PRINT_UNSIGNED_LONG:
                      case D_PRINT_UNSIGNED_LONG:
                        d_append_string (dpi, "ul");
                        d_append_string (dpi, "ul");
                        break;
                        break;
                      case D_PRINT_LONG_LONG:
                      case D_PRINT_LONG_LONG:
                        d_append_string (dpi, "ll");
                        d_append_string (dpi, "ll");
                        break;
                        break;
                      case D_PRINT_UNSIGNED_LONG_LONG:
                      case D_PRINT_UNSIGNED_LONG_LONG:
                        d_append_string (dpi, "ull");
                        d_append_string (dpi, "ull");
                        break;
                        break;
                      }
                      }
                    return;
                    return;
                  }
                  }
                break;
                break;
 
 
              case D_PRINT_BOOL:
              case D_PRINT_BOOL:
                if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME
                if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME
                    && d_right (dc)->u.s_name.len == 1
                    && d_right (dc)->u.s_name.len == 1
                    && dc->type == DEMANGLE_COMPONENT_LITERAL)
                    && dc->type == DEMANGLE_COMPONENT_LITERAL)
                  {
                  {
                    switch (d_right (dc)->u.s_name.s[0])
                    switch (d_right (dc)->u.s_name.s[0])
                      {
                      {
                      case '0':
                      case '0':
                        d_append_string (dpi, "false");
                        d_append_string (dpi, "false");
                        return;
                        return;
                      case '1':
                      case '1':
                        d_append_string (dpi, "true");
                        d_append_string (dpi, "true");
                        return;
                        return;
                      default:
                      default:
                        break;
                        break;
                      }
                      }
                  }
                  }
                break;
                break;
 
 
              default:
              default:
                break;
                break;
              }
              }
          }
          }
 
 
        d_append_char (dpi, '(');
        d_append_char (dpi, '(');
        d_print_comp (dpi, d_left (dc));
        d_print_comp (dpi, d_left (dc));
        d_append_char (dpi, ')');
        d_append_char (dpi, ')');
        if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
        if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
          d_append_char (dpi, '-');
          d_append_char (dpi, '-');
        if (tp == D_PRINT_FLOAT)
        if (tp == D_PRINT_FLOAT)
          d_append_char (dpi, '[');
          d_append_char (dpi, '[');
        d_print_comp (dpi, d_right (dc));
        d_print_comp (dpi, d_right (dc));
        if (tp == D_PRINT_FLOAT)
        if (tp == D_PRINT_FLOAT)
          d_append_char (dpi, ']');
          d_append_char (dpi, ']');
      }
      }
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_NUMBER:
    case DEMANGLE_COMPONENT_NUMBER:
      d_append_num (dpi, dc->u.s_number.number);
      d_append_num (dpi, dc->u.s_number.number);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
    case DEMANGLE_COMPONENT_JAVA_RESOURCE:
      d_append_string (dpi, "java resource ");
      d_append_string (dpi, "java resource ");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
    case DEMANGLE_COMPONENT_COMPOUND_NAME:
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_right (dc));
      d_print_comp (dpi, d_right (dc));
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_CHARACTER:
    case DEMANGLE_COMPONENT_CHARACTER:
      d_append_char (dpi, dc->u.s_character.character);
      d_append_char (dpi, dc->u.s_character.character);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_DECLTYPE:
    case DEMANGLE_COMPONENT_DECLTYPE:
      d_append_string (dpi, "decltype (");
      d_append_string (dpi, "decltype (");
      d_print_comp (dpi, d_left (dc));
      d_print_comp (dpi, d_left (dc));
      d_append_char (dpi, ')');
      d_append_char (dpi, ')');
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
    case DEMANGLE_COMPONENT_PACK_EXPANSION:
      {
      {
        int len;
        int len;
        int i;
        int i;
        struct demangle_component *a = d_find_pack (dpi, d_left (dc));
        struct demangle_component *a = d_find_pack (dpi, d_left (dc));
        if (a == NULL)
        if (a == NULL)
          {
          {
            /* d_find_pack won't find anything if the only packs involved
            /* d_find_pack won't find anything if the only packs involved
               in this expansion are function parameter packs; in that
               in this expansion are function parameter packs; in that
               case, just print the pattern and "...".  */
               case, just print the pattern and "...".  */
            d_print_subexpr (dpi, d_left (dc));
            d_print_subexpr (dpi, d_left (dc));
            d_append_string (dpi, "...");
            d_append_string (dpi, "...");
            return;
            return;
          }
          }
 
 
        len = d_pack_length (a);
        len = d_pack_length (a);
        dc = d_left (dc);
        dc = d_left (dc);
        for (i = 0; i < len; ++i)
        for (i = 0; i < len; ++i)
          {
          {
            dpi->pack_index = i;
            dpi->pack_index = i;
            d_print_comp (dpi, dc);
            d_print_comp (dpi, dc);
            if (i < len-1)
            if (i < len-1)
              d_append_string (dpi, ", ");
              d_append_string (dpi, ", ");
          }
          }
      }
      }
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_FUNCTION_PARAM:
    case DEMANGLE_COMPONENT_FUNCTION_PARAM:
      d_append_string (dpi, "{parm#");
      d_append_string (dpi, "{parm#");
      d_append_num (dpi, dc->u.s_number.number + 1);
      d_append_num (dpi, dc->u.s_number.number + 1);
      d_append_char (dpi, '}');
      d_append_char (dpi, '}');
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
    case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
      d_append_string (dpi, "global constructors keyed to ");
      d_append_string (dpi, "global constructors keyed to ");
      d_print_comp (dpi, dc->u.s_binary.left);
      d_print_comp (dpi, dc->u.s_binary.left);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
    case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
      d_append_string (dpi, "global destructors keyed to ");
      d_append_string (dpi, "global destructors keyed to ");
      d_print_comp (dpi, dc->u.s_binary.left);
      d_print_comp (dpi, dc->u.s_binary.left);
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_LAMBDA:
    case DEMANGLE_COMPONENT_LAMBDA:
      d_append_string (dpi, "{lambda(");
      d_append_string (dpi, "{lambda(");
      d_print_comp (dpi, dc->u.s_unary_num.sub);
      d_print_comp (dpi, dc->u.s_unary_num.sub);
      d_append_string (dpi, ")#");
      d_append_string (dpi, ")#");
      d_append_num (dpi, dc->u.s_unary_num.num + 1);
      d_append_num (dpi, dc->u.s_unary_num.num + 1);
      d_append_char (dpi, '}');
      d_append_char (dpi, '}');
      return;
      return;
 
 
    case DEMANGLE_COMPONENT_UNNAMED_TYPE:
    case DEMANGLE_COMPONENT_UNNAMED_TYPE:
      d_append_string (dpi, "{unnamed type#");
      d_append_string (dpi, "{unnamed type#");
      d_append_num (dpi, dc->u.s_number.number + 1);
      d_append_num (dpi, dc->u.s_number.number + 1);
      d_append_char (dpi, '}');
      d_append_char (dpi, '}');
      return;
      return;
 
 
    default:
    default:
      d_print_error (dpi);
      d_print_error (dpi);
      return;
      return;
    }
    }
}
}
 
 
/* Print a Java dentifier.  For Java we try to handle encoded extended
/* Print a Java dentifier.  For Java we try to handle encoded extended
   Unicode characters.  The C++ ABI doesn't mention Unicode encoding,
   Unicode characters.  The C++ ABI doesn't mention Unicode encoding,
   so we don't it for C++.  Characters are encoded as
   so we don't it for C++.  Characters are encoded as
   __U<hex-char>+_.  */
   __U<hex-char>+_.  */
 
 
static void
static void
d_print_java_identifier (struct d_print_info *dpi, const char *name, int len)
d_print_java_identifier (struct d_print_info *dpi, const char *name, int len)
{
{
  const char *p;
  const char *p;
  const char *end;
  const char *end;
 
 
  end = name + len;
  end = name + len;
  for (p = name; p < end; ++p)
  for (p = name; p < end; ++p)
    {
    {
      if (end - p > 3
      if (end - p > 3
          && p[0] == '_'
          && p[0] == '_'
          && p[1] == '_'
          && p[1] == '_'
          && p[2] == 'U')
          && p[2] == 'U')
        {
        {
          unsigned long c;
          unsigned long c;
          const char *q;
          const char *q;
 
 
          c = 0;
          c = 0;
          for (q = p + 3; q < end; ++q)
          for (q = p + 3; q < end; ++q)
            {
            {
              int dig;
              int dig;
 
 
              if (IS_DIGIT (*q))
              if (IS_DIGIT (*q))
                dig = *q - '0';
                dig = *q - '0';
              else if (*q >= 'A' && *q <= 'F')
              else if (*q >= 'A' && *q <= 'F')
                dig = *q - 'A' + 10;
                dig = *q - 'A' + 10;
              else if (*q >= 'a' && *q <= 'f')
              else if (*q >= 'a' && *q <= 'f')
                dig = *q - 'a' + 10;
                dig = *q - 'a' + 10;
              else
              else
                break;
                break;
 
 
              c = c * 16 + dig;
              c = c * 16 + dig;
            }
            }
          /* If the Unicode character is larger than 256, we don't try
          /* If the Unicode character is larger than 256, we don't try
             to deal with it here.  FIXME.  */
             to deal with it here.  FIXME.  */
          if (q < end && *q == '_' && c < 256)
          if (q < end && *q == '_' && c < 256)
            {
            {
              d_append_char (dpi, c);
              d_append_char (dpi, c);
              p = q;
              p = q;
              continue;
              continue;
            }
            }
        }
        }
 
 
      d_append_char (dpi, *p);
      d_append_char (dpi, *p);
    }
    }
}
}
 
 
/* Print a list of modifiers.  SUFFIX is 1 if we are printing
/* Print a list of modifiers.  SUFFIX is 1 if we are printing
   qualifiers on this after printing a function.  */
   qualifiers on this after printing a function.  */
 
 
static void
static void
d_print_mod_list (struct d_print_info *dpi,
d_print_mod_list (struct d_print_info *dpi,
                  struct d_print_mod *mods, int suffix)
                  struct d_print_mod *mods, int suffix)
{
{
  struct d_print_template *hold_dpt;
  struct d_print_template *hold_dpt;
 
 
  if (mods == NULL || d_print_saw_error (dpi))
  if (mods == NULL || d_print_saw_error (dpi))
    return;
    return;
 
 
  if (mods->printed
  if (mods->printed
      || (! suffix
      || (! suffix
          && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
          && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
              || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
              || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
              || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS)))
              || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS)))
    {
    {
      d_print_mod_list (dpi, mods->next, suffix);
      d_print_mod_list (dpi, mods->next, suffix);
      return;
      return;
    }
    }
 
 
  mods->printed = 1;
  mods->printed = 1;
 
 
  hold_dpt = dpi->templates;
  hold_dpt = dpi->templates;
  dpi->templates = mods->templates;
  dpi->templates = mods->templates;
 
 
  if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
  if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
    {
    {
      d_print_function_type (dpi, mods->mod, mods->next);
      d_print_function_type (dpi, mods->mod, mods->next);
      dpi->templates = hold_dpt;
      dpi->templates = hold_dpt;
      return;
      return;
    }
    }
  else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
  else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
    {
    {
      d_print_array_type (dpi, mods->mod, mods->next);
      d_print_array_type (dpi, mods->mod, mods->next);
      dpi->templates = hold_dpt;
      dpi->templates = hold_dpt;
      return;
      return;
    }
    }
  else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME)
  else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME)
    {
    {
      struct d_print_mod *hold_modifiers;
      struct d_print_mod *hold_modifiers;
      struct demangle_component *dc;
      struct demangle_component *dc;
 
 
      /* When this is on the modifier stack, we have pulled any
      /* When this is on the modifier stack, we have pulled any
         qualifiers off the right argument already.  Otherwise, we
         qualifiers off the right argument already.  Otherwise, we
         print it as usual, but don't let the left argument see any
         print it as usual, but don't let the left argument see any
         modifiers.  */
         modifiers.  */
 
 
      hold_modifiers = dpi->modifiers;
      hold_modifiers = dpi->modifiers;
      dpi->modifiers = NULL;
      dpi->modifiers = NULL;
      d_print_comp (dpi, d_left (mods->mod));
      d_print_comp (dpi, d_left (mods->mod));
      dpi->modifiers = hold_modifiers;
      dpi->modifiers = hold_modifiers;
 
 
      if ((dpi->options & DMGL_JAVA) == 0)
      if ((dpi->options & DMGL_JAVA) == 0)
        d_append_string (dpi, "::");
        d_append_string (dpi, "::");
      else
      else
        d_append_char (dpi, '.');
        d_append_char (dpi, '.');
 
 
      dc = d_right (mods->mod);
      dc = d_right (mods->mod);
 
 
      if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
      if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
        {
        {
          d_append_string (dpi, "{default arg#");
          d_append_string (dpi, "{default arg#");
          d_append_num (dpi, dc->u.s_unary_num.num + 1);
          d_append_num (dpi, dc->u.s_unary_num.num + 1);
          d_append_string (dpi, "}::");
          d_append_string (dpi, "}::");
          dc = dc->u.s_unary_num.sub;
          dc = dc->u.s_unary_num.sub;
        }
        }
 
 
      while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
      while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
             || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
             || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
             || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
             || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
        dc = d_left (dc);
        dc = d_left (dc);
 
 
      d_print_comp (dpi, dc);
      d_print_comp (dpi, dc);
 
 
      dpi->templates = hold_dpt;
      dpi->templates = hold_dpt;
      return;
      return;
    }
    }
 
 
  d_print_mod (dpi, mods->mod);
  d_print_mod (dpi, mods->mod);
 
 
  dpi->templates = hold_dpt;
  dpi->templates = hold_dpt;
 
 
  d_print_mod_list (dpi, mods->next, suffix);
  d_print_mod_list (dpi, mods->next, suffix);
}
}
 
 
/* Print a modifier.  */
/* Print a modifier.  */
 
 
static void
static void
d_print_mod (struct d_print_info *dpi,
d_print_mod (struct d_print_info *dpi,
             const struct demangle_component *mod)
             const struct demangle_component *mod)
{
{
  switch (mod->type)
  switch (mod->type)
    {
    {
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
      d_append_string (dpi, " restrict");
      d_append_string (dpi, " restrict");
      return;
      return;
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
      d_append_string (dpi, " volatile");
      d_append_string (dpi, " volatile");
      return;
      return;
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
      d_append_string (dpi, " const");
      d_append_string (dpi, " const");
      return;
      return;
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
      d_append_char (dpi, ' ');
      d_append_char (dpi, ' ');
      d_print_comp (dpi, d_right (mod));
      d_print_comp (dpi, d_right (mod));
      return;
      return;
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_POINTER:
      /* There is no pointer symbol in Java.  */
      /* There is no pointer symbol in Java.  */
      if ((dpi->options & DMGL_JAVA) == 0)
      if ((dpi->options & DMGL_JAVA) == 0)
        d_append_char (dpi, '*');
        d_append_char (dpi, '*');
      return;
      return;
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_REFERENCE:
      d_append_char (dpi, '&');
      d_append_char (dpi, '&');
      return;
      return;
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
    case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
      d_append_string (dpi, "&&");
      d_append_string (dpi, "&&");
      return;
      return;
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_COMPLEX:
      d_append_string (dpi, "complex ");
      d_append_string (dpi, "complex ");
      return;
      return;
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_IMAGINARY:
      d_append_string (dpi, "imaginary ");
      d_append_string (dpi, "imaginary ");
      return;
      return;
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
      if (d_last_char (dpi) != '(')
      if (d_last_char (dpi) != '(')
        d_append_char (dpi, ' ');
        d_append_char (dpi, ' ');
      d_print_comp (dpi, d_left (mod));
      d_print_comp (dpi, d_left (mod));
      d_append_string (dpi, "::*");
      d_append_string (dpi, "::*");
      return;
      return;
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
      d_print_comp (dpi, d_left (mod));
      d_print_comp (dpi, d_left (mod));
      return;
      return;
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
    case DEMANGLE_COMPONENT_VECTOR_TYPE:
      d_append_string (dpi, " vector[");
      d_append_string (dpi, " vector[");
      d_print_comp (dpi, d_left (mod));
      d_print_comp (dpi, d_left (mod));
      d_append_char (dpi, ']');
      d_append_char (dpi, ']');
      return;
      return;
 
 
    default:
    default:
      /* Otherwise, we have something that won't go back on the
      /* Otherwise, we have something that won't go back on the
         modifier stack, so we can just print it.  */
         modifier stack, so we can just print it.  */
      d_print_comp (dpi, mod);
      d_print_comp (dpi, mod);
      return;
      return;
    }
    }
}
}
 
 
/* Print a function type, except for the return type.  */
/* Print a function type, except for the return type.  */
 
 
static void
static void
d_print_function_type (struct d_print_info *dpi,
d_print_function_type (struct d_print_info *dpi,
                       const struct demangle_component *dc,
                       const struct demangle_component *dc,
                       struct d_print_mod *mods)
                       struct d_print_mod *mods)
{
{
  int need_paren;
  int need_paren;
  int saw_mod;
  int saw_mod;
  int need_space;
  int need_space;
  struct d_print_mod *p;
  struct d_print_mod *p;
  struct d_print_mod *hold_modifiers;
  struct d_print_mod *hold_modifiers;
 
 
  need_paren = 0;
  need_paren = 0;
  saw_mod = 0;
  saw_mod = 0;
  need_space = 0;
  need_space = 0;
  for (p = mods; p != NULL; p = p->next)
  for (p = mods; p != NULL; p = p->next)
    {
    {
      if (p->printed)
      if (p->printed)
        break;
        break;
 
 
      saw_mod = 1;
      saw_mod = 1;
      switch (p->mod->type)
      switch (p->mod->type)
        {
        {
        case DEMANGLE_COMPONENT_POINTER:
        case DEMANGLE_COMPONENT_POINTER:
        case DEMANGLE_COMPONENT_REFERENCE:
        case DEMANGLE_COMPONENT_REFERENCE:
        case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
        case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
          need_paren = 1;
          need_paren = 1;
          break;
          break;
        case DEMANGLE_COMPONENT_RESTRICT:
        case DEMANGLE_COMPONENT_RESTRICT:
        case DEMANGLE_COMPONENT_VOLATILE:
        case DEMANGLE_COMPONENT_VOLATILE:
        case DEMANGLE_COMPONENT_CONST:
        case DEMANGLE_COMPONENT_CONST:
        case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
        case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
        case DEMANGLE_COMPONENT_COMPLEX:
        case DEMANGLE_COMPONENT_COMPLEX:
        case DEMANGLE_COMPONENT_IMAGINARY:
        case DEMANGLE_COMPONENT_IMAGINARY:
        case DEMANGLE_COMPONENT_PTRMEM_TYPE:
        case DEMANGLE_COMPONENT_PTRMEM_TYPE:
          need_space = 1;
          need_space = 1;
          need_paren = 1;
          need_paren = 1;
          break;
          break;
        case DEMANGLE_COMPONENT_RESTRICT_THIS:
        case DEMANGLE_COMPONENT_RESTRICT_THIS:
        case DEMANGLE_COMPONENT_VOLATILE_THIS:
        case DEMANGLE_COMPONENT_VOLATILE_THIS:
        case DEMANGLE_COMPONENT_CONST_THIS:
        case DEMANGLE_COMPONENT_CONST_THIS:
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
      if (need_paren)
      if (need_paren)
        break;
        break;
    }
    }
 
 
  if (d_left (dc) != NULL && ! saw_mod)
  if (d_left (dc) != NULL && ! saw_mod)
    need_paren = 1;
    need_paren = 1;
 
 
  if (need_paren)
  if (need_paren)
    {
    {
      if (! need_space)
      if (! need_space)
        {
        {
          if (d_last_char (dpi) != '('
          if (d_last_char (dpi) != '('
              && d_last_char (dpi) != '*')
              && d_last_char (dpi) != '*')
            need_space = 1;
            need_space = 1;
        }
        }
      if (need_space && d_last_char (dpi) != ' ')
      if (need_space && d_last_char (dpi) != ' ')
        d_append_char (dpi, ' ');
        d_append_char (dpi, ' ');
      d_append_char (dpi, '(');
      d_append_char (dpi, '(');
    }
    }
 
 
  hold_modifiers = dpi->modifiers;
  hold_modifiers = dpi->modifiers;
  dpi->modifiers = NULL;
  dpi->modifiers = NULL;
 
 
  d_print_mod_list (dpi, mods, 0);
  d_print_mod_list (dpi, mods, 0);
 
 
  if (need_paren)
  if (need_paren)
    d_append_char (dpi, ')');
    d_append_char (dpi, ')');
 
 
  d_append_char (dpi, '(');
  d_append_char (dpi, '(');
 
 
  if (d_right (dc) != NULL)
  if (d_right (dc) != NULL)
    d_print_comp (dpi, d_right (dc));
    d_print_comp (dpi, d_right (dc));
 
 
  d_append_char (dpi, ')');
  d_append_char (dpi, ')');
 
 
  d_print_mod_list (dpi, mods, 1);
  d_print_mod_list (dpi, mods, 1);
 
 
  dpi->modifiers = hold_modifiers;
  dpi->modifiers = hold_modifiers;
}
}
 
 
/* Print an array type, except for the element type.  */
/* Print an array type, except for the element type.  */
 
 
static void
static void
d_print_array_type (struct d_print_info *dpi,
d_print_array_type (struct d_print_info *dpi,
                    const struct demangle_component *dc,
                    const struct demangle_component *dc,
                    struct d_print_mod *mods)
                    struct d_print_mod *mods)
{
{
  int need_space;
  int need_space;
 
 
  need_space = 1;
  need_space = 1;
  if (mods != NULL)
  if (mods != NULL)
    {
    {
      int need_paren;
      int need_paren;
      struct d_print_mod *p;
      struct d_print_mod *p;
 
 
      need_paren = 0;
      need_paren = 0;
      for (p = mods; p != NULL; p = p->next)
      for (p = mods; p != NULL; p = p->next)
        {
        {
          if (! p->printed)
          if (! p->printed)
            {
            {
              if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
              if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
                {
                {
                  need_space = 0;
                  need_space = 0;
                  break;
                  break;
                }
                }
              else
              else
                {
                {
                  need_paren = 1;
                  need_paren = 1;
                  need_space = 1;
                  need_space = 1;
                  break;
                  break;
                }
                }
            }
            }
        }
        }
 
 
      if (need_paren)
      if (need_paren)
        d_append_string (dpi, " (");
        d_append_string (dpi, " (");
 
 
      d_print_mod_list (dpi, mods, 0);
      d_print_mod_list (dpi, mods, 0);
 
 
      if (need_paren)
      if (need_paren)
        d_append_char (dpi, ')');
        d_append_char (dpi, ')');
    }
    }
 
 
  if (need_space)
  if (need_space)
    d_append_char (dpi, ' ');
    d_append_char (dpi, ' ');
 
 
  d_append_char (dpi, '[');
  d_append_char (dpi, '[');
 
 
  if (d_left (dc) != NULL)
  if (d_left (dc) != NULL)
    d_print_comp (dpi, d_left (dc));
    d_print_comp (dpi, d_left (dc));
 
 
  d_append_char (dpi, ']');
  d_append_char (dpi, ']');
}
}
 
 
/* Print an operator in an expression.  */
/* Print an operator in an expression.  */
 
 
static void
static void
d_print_expr_op (struct d_print_info *dpi,
d_print_expr_op (struct d_print_info *dpi,
                 const struct demangle_component *dc)
                 const struct demangle_component *dc)
{
{
  if (dc->type == DEMANGLE_COMPONENT_OPERATOR)
  if (dc->type == DEMANGLE_COMPONENT_OPERATOR)
    d_append_buffer (dpi, dc->u.s_operator.op->name,
    d_append_buffer (dpi, dc->u.s_operator.op->name,
                     dc->u.s_operator.op->len);
                     dc->u.s_operator.op->len);
  else
  else
    d_print_comp (dpi, dc);
    d_print_comp (dpi, dc);
}
}
 
 
/* Print a cast.  */
/* Print a cast.  */
 
 
static void
static void
d_print_cast (struct d_print_info *dpi,
d_print_cast (struct d_print_info *dpi,
              const struct demangle_component *dc)
              const struct demangle_component *dc)
{
{
  if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
  if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
    d_print_comp (dpi, d_left (dc));
    d_print_comp (dpi, d_left (dc));
  else
  else
    {
    {
      struct d_print_mod *hold_dpm;
      struct d_print_mod *hold_dpm;
      struct d_print_template dpt;
      struct d_print_template dpt;
 
 
      /* It appears that for a templated cast operator, we need to put
      /* It appears that for a templated cast operator, we need to put
         the template parameters in scope for the operator name, but
         the template parameters in scope for the operator name, but
         not for the parameters.  The effect is that we need to handle
         not for the parameters.  The effect is that we need to handle
         the template printing here.  */
         the template printing here.  */
 
 
      hold_dpm = dpi->modifiers;
      hold_dpm = dpi->modifiers;
      dpi->modifiers = NULL;
      dpi->modifiers = NULL;
 
 
      dpt.next = dpi->templates;
      dpt.next = dpi->templates;
      dpi->templates = &dpt;
      dpi->templates = &dpt;
      dpt.template_decl = d_left (dc);
      dpt.template_decl = d_left (dc);
 
 
      d_print_comp (dpi, d_left (d_left (dc)));
      d_print_comp (dpi, d_left (d_left (dc)));
 
 
      dpi->templates = dpt.next;
      dpi->templates = dpt.next;
 
 
      if (d_last_char (dpi) == '<')
      if (d_last_char (dpi) == '<')
        d_append_char (dpi, ' ');
        d_append_char (dpi, ' ');
      d_append_char (dpi, '<');
      d_append_char (dpi, '<');
      d_print_comp (dpi, d_right (d_left (dc)));
      d_print_comp (dpi, d_right (d_left (dc)));
      /* Avoid generating two consecutive '>' characters, to avoid
      /* Avoid generating two consecutive '>' characters, to avoid
         the C++ syntactic ambiguity.  */
         the C++ syntactic ambiguity.  */
      if (d_last_char (dpi) == '>')
      if (d_last_char (dpi) == '>')
        d_append_char (dpi, ' ');
        d_append_char (dpi, ' ');
      d_append_char (dpi, '>');
      d_append_char (dpi, '>');
 
 
      dpi->modifiers = hold_dpm;
      dpi->modifiers = hold_dpm;
    }
    }
}
}
 
 
/* Initialize the information structure we use to pass around
/* Initialize the information structure we use to pass around
   information.  */
   information.  */
 
 
CP_STATIC_IF_GLIBCPP_V3
CP_STATIC_IF_GLIBCPP_V3
void
void
cplus_demangle_init_info (const char *mangled, int options, size_t len,
cplus_demangle_init_info (const char *mangled, int options, size_t len,
                          struct d_info *di)
                          struct d_info *di)
{
{
  di->s = mangled;
  di->s = mangled;
  di->send = mangled + len;
  di->send = mangled + len;
  di->options = options;
  di->options = options;
 
 
  di->n = mangled;
  di->n = mangled;
 
 
  /* We can not need more components than twice the number of chars in
  /* We can not need more components than twice the number of chars in
     the mangled string.  Most components correspond directly to
     the mangled string.  Most components correspond directly to
     chars, but the ARGLIST types are exceptions.  */
     chars, but the ARGLIST types are exceptions.  */
  di->num_comps = 2 * len;
  di->num_comps = 2 * len;
  di->next_comp = 0;
  di->next_comp = 0;
 
 
  /* Similarly, we can not need more substitutions than there are
  /* Similarly, we can not need more substitutions than there are
     chars in the mangled string.  */
     chars in the mangled string.  */
  di->num_subs = len;
  di->num_subs = len;
  di->next_sub = 0;
  di->next_sub = 0;
  di->did_subs = 0;
  di->did_subs = 0;
 
 
  di->last_name = NULL;
  di->last_name = NULL;
 
 
  di->expansion = 0;
  di->expansion = 0;
}
}
 
 
/* Internal implementation for the demangler.  If MANGLED is a g++ v3 ABI
/* Internal implementation for the demangler.  If MANGLED is a g++ v3 ABI
   mangled name, return strings in repeated callback giving the demangled
   mangled name, return strings in repeated callback giving the demangled
   name.  OPTIONS is the usual libiberty demangler options.  On success,
   name.  OPTIONS is the usual libiberty demangler options.  On success,
   this returns 1.  On failure, returns 0.  */
   this returns 1.  On failure, returns 0.  */
 
 
static int
static int
d_demangle_callback (const char *mangled, int options,
d_demangle_callback (const char *mangled, int options,
                     demangle_callbackref callback, void *opaque)
                     demangle_callbackref callback, void *opaque)
{
{
  enum
  enum
    {
    {
      DCT_TYPE,
      DCT_TYPE,
      DCT_MANGLED,
      DCT_MANGLED,
      DCT_GLOBAL_CTORS,
      DCT_GLOBAL_CTORS,
      DCT_GLOBAL_DTORS
      DCT_GLOBAL_DTORS
    }
    }
  type;
  type;
  struct d_info di;
  struct d_info di;
  struct demangle_component *dc;
  struct demangle_component *dc;
  int status;
  int status;
 
 
  if (mangled[0] == '_' && mangled[1] == 'Z')
  if (mangled[0] == '_' && mangled[1] == 'Z')
    type = DCT_MANGLED;
    type = DCT_MANGLED;
  else if (strncmp (mangled, "_GLOBAL_", 8) == 0
  else if (strncmp (mangled, "_GLOBAL_", 8) == 0
           && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$')
           && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$')
           && (mangled[9] == 'D' || mangled[9] == 'I')
           && (mangled[9] == 'D' || mangled[9] == 'I')
           && mangled[10] == '_')
           && mangled[10] == '_')
    type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
    type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
  else
  else
    {
    {
      if ((options & DMGL_TYPES) == 0)
      if ((options & DMGL_TYPES) == 0)
        return 0;
        return 0;
      type = DCT_TYPE;
      type = DCT_TYPE;
    }
    }
 
 
  cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
  cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
 
 
  {
  {
#ifdef CP_DYNAMIC_ARRAYS
#ifdef CP_DYNAMIC_ARRAYS
    __extension__ struct demangle_component comps[di.num_comps];
    __extension__ struct demangle_component comps[di.num_comps];
    __extension__ struct demangle_component *subs[di.num_subs];
    __extension__ struct demangle_component *subs[di.num_subs];
 
 
    di.comps = comps;
    di.comps = comps;
    di.subs = subs;
    di.subs = subs;
#else
#else
    di.comps = alloca (di.num_comps * sizeof (*di.comps));
    di.comps = alloca (di.num_comps * sizeof (*di.comps));
    di.subs = alloca (di.num_subs * sizeof (*di.subs));
    di.subs = alloca (di.num_subs * sizeof (*di.subs));
#endif
#endif
 
 
    switch (type)
    switch (type)
      {
      {
      case DCT_TYPE:
      case DCT_TYPE:
        dc = cplus_demangle_type (&di);
        dc = cplus_demangle_type (&di);
        break;
        break;
      case DCT_MANGLED:
      case DCT_MANGLED:
        dc = cplus_demangle_mangled_name (&di, 1);
        dc = cplus_demangle_mangled_name (&di, 1);
        break;
        break;
      case DCT_GLOBAL_CTORS:
      case DCT_GLOBAL_CTORS:
      case DCT_GLOBAL_DTORS:
      case DCT_GLOBAL_DTORS:
        d_advance (&di, 11);
        d_advance (&di, 11);
        dc = d_make_comp (&di,
        dc = d_make_comp (&di,
                          (type == DCT_GLOBAL_CTORS
                          (type == DCT_GLOBAL_CTORS
                           ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
                           ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
                           : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
                           : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
                          d_make_name (&di, d_str (&di), strlen (d_str (&di))),
                          d_make_name (&di, d_str (&di), strlen (d_str (&di))),
                          NULL);
                          NULL);
        d_advance (&di, strlen (d_str (&di)));
        d_advance (&di, strlen (d_str (&di)));
        break;
        break;
      }
      }
 
 
    /* If DMGL_PARAMS is set, then if we didn't consume the entire
    /* If DMGL_PARAMS is set, then if we didn't consume the entire
       mangled string, then we didn't successfully demangle it.  If
       mangled string, then we didn't successfully demangle it.  If
       DMGL_PARAMS is not set, we didn't look at the trailing
       DMGL_PARAMS is not set, we didn't look at the trailing
       parameters.  */
       parameters.  */
    if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
    if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
      dc = NULL;
      dc = NULL;
 
 
#ifdef CP_DEMANGLE_DEBUG
#ifdef CP_DEMANGLE_DEBUG
    d_dump (dc, 0);
    d_dump (dc, 0);
#endif
#endif
 
 
    status = (dc != NULL)
    status = (dc != NULL)
             ? cplus_demangle_print_callback (options, dc, callback, opaque)
             ? cplus_demangle_print_callback (options, dc, callback, opaque)
             : 0;
             : 0;
  }
  }
 
 
  return status;
  return status;
}
}
 
 
/* Entry point for the demangler.  If MANGLED is a g++ v3 ABI mangled
/* Entry point for the demangler.  If MANGLED is a g++ v3 ABI mangled
   name, return a buffer allocated with malloc holding the demangled
   name, return a buffer allocated with malloc holding the demangled
   name.  OPTIONS is the usual libiberty demangler options.  On
   name.  OPTIONS is the usual libiberty demangler options.  On
   success, this sets *PALC to the allocated size of the returned
   success, this sets *PALC to the allocated size of the returned
   buffer.  On failure, this sets *PALC to 0 for a bad name, or 1 for
   buffer.  On failure, this sets *PALC to 0 for a bad name, or 1 for
   a memory allocation failure, and returns NULL.  */
   a memory allocation failure, and returns NULL.  */
 
 
static char *
static char *
d_demangle (const char *mangled, int options, size_t *palc)
d_demangle (const char *mangled, int options, size_t *palc)
{
{
  struct d_growable_string dgs;
  struct d_growable_string dgs;
  int status;
  int status;
 
 
  d_growable_string_init (&dgs, 0);
  d_growable_string_init (&dgs, 0);
 
 
  status = d_demangle_callback (mangled, options,
  status = d_demangle_callback (mangled, options,
                                d_growable_string_callback_adapter, &dgs);
                                d_growable_string_callback_adapter, &dgs);
  if (status == 0)
  if (status == 0)
    {
    {
      free (dgs.buf);
      free (dgs.buf);
      *palc = 0;
      *palc = 0;
      return NULL;
      return NULL;
    }
    }
 
 
  *palc = dgs.allocation_failure ? 1 : dgs.alc;
  *palc = dgs.allocation_failure ? 1 : dgs.alc;
  return dgs.buf;
  return dgs.buf;
}
}
 
 
#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
 
 
extern char *__cxa_demangle (const char *, char *, size_t *, int *);
extern char *__cxa_demangle (const char *, char *, size_t *, int *);
 
 
/* ia64 ABI-mandated entry point in the C++ runtime library for
/* ia64 ABI-mandated entry point in the C++ runtime library for
   performing demangling.  MANGLED_NAME is a NUL-terminated character
   performing demangling.  MANGLED_NAME is a NUL-terminated character
   string containing the name to be demangled.
   string containing the name to be demangled.
 
 
   OUTPUT_BUFFER is a region of memory, allocated with malloc, of
   OUTPUT_BUFFER is a region of memory, allocated with malloc, of
   *LENGTH bytes, into which the demangled name is stored.  If
   *LENGTH bytes, into which the demangled name is stored.  If
   OUTPUT_BUFFER is not long enough, it is expanded using realloc.
   OUTPUT_BUFFER is not long enough, it is expanded using realloc.
   OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
   OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
   is placed in a region of memory allocated with malloc.
   is placed in a region of memory allocated with malloc.
 
 
   If LENGTH is non-NULL, the length of the buffer containing the
   If LENGTH is non-NULL, the length of the buffer containing the
   demangled name, is placed in *LENGTH.
   demangled name, is placed in *LENGTH.
 
 
   The return value is a pointer to the start of the NUL-terminated
   The return value is a pointer to the start of the NUL-terminated
   demangled name, or NULL if the demangling fails.  The caller is
   demangled name, or NULL if the demangling fails.  The caller is
   responsible for deallocating this memory using free.
   responsible for deallocating this memory using free.
 
 
   *STATUS is set to one of the following values:
   *STATUS is set to one of the following values:
      0: The demangling operation succeeded.
      0: The demangling operation succeeded.
     -1: A memory allocation failure occurred.
     -1: A memory allocation failure occurred.
     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
     -3: One of the arguments is invalid.
     -3: One of the arguments is invalid.
 
 
   The demangling is performed using the C++ ABI mangling rules, with
   The demangling is performed using the C++ ABI mangling rules, with
   GNU extensions.  */
   GNU extensions.  */
 
 
char *
char *
__cxa_demangle (const char *mangled_name, char *output_buffer,
__cxa_demangle (const char *mangled_name, char *output_buffer,
                size_t *length, int *status)
                size_t *length, int *status)
{
{
  char *demangled;
  char *demangled;
  size_t alc;
  size_t alc;
 
 
  if (mangled_name == NULL)
  if (mangled_name == NULL)
    {
    {
      if (status != NULL)
      if (status != NULL)
        *status = -3;
        *status = -3;
      return NULL;
      return NULL;
    }
    }
 
 
  if (output_buffer != NULL && length == NULL)
  if (output_buffer != NULL && length == NULL)
    {
    {
      if (status != NULL)
      if (status != NULL)
        *status = -3;
        *status = -3;
      return NULL;
      return NULL;
    }
    }
 
 
  demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc);
  demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc);
 
 
  if (demangled == NULL)
  if (demangled == NULL)
    {
    {
      if (status != NULL)
      if (status != NULL)
        {
        {
          if (alc == 1)
          if (alc == 1)
            *status = -1;
            *status = -1;
          else
          else
            *status = -2;
            *status = -2;
        }
        }
      return NULL;
      return NULL;
    }
    }
 
 
  if (output_buffer == NULL)
  if (output_buffer == NULL)
    {
    {
      if (length != NULL)
      if (length != NULL)
        *length = alc;
        *length = alc;
    }
    }
  else
  else
    {
    {
      if (strlen (demangled) < *length)
      if (strlen (demangled) < *length)
        {
        {
          strcpy (output_buffer, demangled);
          strcpy (output_buffer, demangled);
          free (demangled);
          free (demangled);
          demangled = output_buffer;
          demangled = output_buffer;
        }
        }
      else
      else
        {
        {
          free (output_buffer);
          free (output_buffer);
          *length = alc;
          *length = alc;
        }
        }
    }
    }
 
 
  if (status != NULL)
  if (status != NULL)
    *status = 0;
    *status = 0;
 
 
  return demangled;
  return demangled;
}
}
 
 
extern int __gcclibcxx_demangle_callback (const char *,
extern int __gcclibcxx_demangle_callback (const char *,
                                          void (*)
                                          void (*)
                                            (const char *, size_t, void *),
                                            (const char *, size_t, void *),
                                          void *);
                                          void *);
 
 
/* Alternative, allocationless entry point in the C++ runtime library
/* Alternative, allocationless entry point in the C++ runtime library
   for performing demangling.  MANGLED_NAME is a NUL-terminated character
   for performing demangling.  MANGLED_NAME is a NUL-terminated character
   string containing the name to be demangled.
   string containing the name to be demangled.
 
 
   CALLBACK is a callback function, called with demangled string
   CALLBACK is a callback function, called with demangled string
   segments as demangling progresses; it is called at least once,
   segments as demangling progresses; it is called at least once,
   but may be called more than once.  OPAQUE is a generalized pointer
   but may be called more than once.  OPAQUE is a generalized pointer
   used as a callback argument.
   used as a callback argument.
 
 
   The return code is one of the following values, equivalent to
   The return code is one of the following values, equivalent to
   the STATUS values of __cxa_demangle() (excluding -1, since this
   the STATUS values of __cxa_demangle() (excluding -1, since this
   function performs no memory allocations):
   function performs no memory allocations):
      0: The demangling operation succeeded.
      0: The demangling operation succeeded.
     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
     -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
     -3: One of the arguments is invalid.
     -3: One of the arguments is invalid.
 
 
   The demangling is performed using the C++ ABI mangling rules, with
   The demangling is performed using the C++ ABI mangling rules, with
   GNU extensions.  */
   GNU extensions.  */
 
 
int
int
__gcclibcxx_demangle_callback (const char *mangled_name,
__gcclibcxx_demangle_callback (const char *mangled_name,
                               void (*callback) (const char *, size_t, void *),
                               void (*callback) (const char *, size_t, void *),
                               void *opaque)
                               void *opaque)
{
{
  int status;
  int status;
 
 
  if (mangled_name == NULL || callback == NULL)
  if (mangled_name == NULL || callback == NULL)
    return -3;
    return -3;
 
 
  status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES,
  status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES,
                                callback, opaque);
                                callback, opaque);
  if (status == 0)
  if (status == 0)
    return -2;
    return -2;
 
 
  return 0;
  return 0;
}
}
 
 
#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
 
 
/* Entry point for libiberty demangler.  If MANGLED is a g++ v3 ABI
/* Entry point for libiberty demangler.  If MANGLED is a g++ v3 ABI
   mangled name, return a buffer allocated with malloc holding the
   mangled name, return a buffer allocated with malloc holding the
   demangled name.  Otherwise, return NULL.  */
   demangled name.  Otherwise, return NULL.  */
 
 
char *
char *
cplus_demangle_v3 (const char *mangled, int options)
cplus_demangle_v3 (const char *mangled, int options)
{
{
  size_t alc;
  size_t alc;
 
 
  return d_demangle (mangled, options, &alc);
  return d_demangle (mangled, options, &alc);
}
}
 
 
int
int
cplus_demangle_v3_callback (const char *mangled, int options,
cplus_demangle_v3_callback (const char *mangled, int options,
                            demangle_callbackref callback, void *opaque)
                            demangle_callbackref callback, void *opaque)
{
{
  return d_demangle_callback (mangled, options, callback, opaque);
  return d_demangle_callback (mangled, options, callback, opaque);
}
}
 
 
/* Demangle a Java symbol.  Java uses a subset of the V3 ABI C++ mangling
/* Demangle a Java symbol.  Java uses a subset of the V3 ABI C++ mangling
   conventions, but the output formatting is a little different.
   conventions, but the output formatting is a little different.
   This instructs the C++ demangler not to emit pointer characters ("*"), to
   This instructs the C++ demangler not to emit pointer characters ("*"), to
   use Java's namespace separator symbol ("." instead of "::"), and to output
   use Java's namespace separator symbol ("." instead of "::"), and to output
   JArray<TYPE> as TYPE[].  */
   JArray<TYPE> as TYPE[].  */
 
 
char *
char *
java_demangle_v3 (const char *mangled)
java_demangle_v3 (const char *mangled)
{
{
  size_t alc;
  size_t alc;
 
 
  return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc);
  return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc);
}
}
 
 
int
int
java_demangle_v3_callback (const char *mangled,
java_demangle_v3_callback (const char *mangled,
                           demangle_callbackref callback, void *opaque)
                           demangle_callbackref callback, void *opaque)
{
{
  return d_demangle_callback (mangled,
  return d_demangle_callback (mangled,
                              DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX,
                              DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX,
                              callback, opaque);
                              callback, opaque);
}
}
 
 
#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
 
 
#ifndef IN_GLIBCPP_V3
#ifndef IN_GLIBCPP_V3
 
 
/* Demangle a string in order to find out whether it is a constructor
/* Demangle a string in order to find out whether it is a constructor
   or destructor.  Return non-zero on success.  Set *CTOR_KIND and
   or destructor.  Return non-zero on success.  Set *CTOR_KIND and
   *DTOR_KIND appropriately.  */
   *DTOR_KIND appropriately.  */
 
 
static int
static int
is_ctor_or_dtor (const char *mangled,
is_ctor_or_dtor (const char *mangled,
                 enum gnu_v3_ctor_kinds *ctor_kind,
                 enum gnu_v3_ctor_kinds *ctor_kind,
                 enum gnu_v3_dtor_kinds *dtor_kind)
                 enum gnu_v3_dtor_kinds *dtor_kind)
{
{
  struct d_info di;
  struct d_info di;
  struct demangle_component *dc;
  struct demangle_component *dc;
  int ret;
  int ret;
 
 
  *ctor_kind = (enum gnu_v3_ctor_kinds) 0;
  *ctor_kind = (enum gnu_v3_ctor_kinds) 0;
  *dtor_kind = (enum gnu_v3_dtor_kinds) 0;
  *dtor_kind = (enum gnu_v3_dtor_kinds) 0;
 
 
  cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di);
  cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di);
 
 
  {
  {
#ifdef CP_DYNAMIC_ARRAYS
#ifdef CP_DYNAMIC_ARRAYS
    __extension__ struct demangle_component comps[di.num_comps];
    __extension__ struct demangle_component comps[di.num_comps];
    __extension__ struct demangle_component *subs[di.num_subs];
    __extension__ struct demangle_component *subs[di.num_subs];
 
 
    di.comps = comps;
    di.comps = comps;
    di.subs = subs;
    di.subs = subs;
#else
#else
    di.comps = alloca (di.num_comps * sizeof (*di.comps));
    di.comps = alloca (di.num_comps * sizeof (*di.comps));
    di.subs = alloca (di.num_subs * sizeof (*di.subs));
    di.subs = alloca (di.num_subs * sizeof (*di.subs));
#endif
#endif
 
 
    dc = cplus_demangle_mangled_name (&di, 1);
    dc = cplus_demangle_mangled_name (&di, 1);
 
 
    /* Note that because we did not pass DMGL_PARAMS, we don't expect
    /* Note that because we did not pass DMGL_PARAMS, we don't expect
       to demangle the entire string.  */
       to demangle the entire string.  */
 
 
    ret = 0;
    ret = 0;
    while (dc != NULL)
    while (dc != NULL)
      {
      {
        switch (dc->type)
        switch (dc->type)
          {
          {
          default:
          default:
            dc = NULL;
            dc = NULL;
            break;
            break;
          case DEMANGLE_COMPONENT_TYPED_NAME:
          case DEMANGLE_COMPONENT_TYPED_NAME:
          case DEMANGLE_COMPONENT_TEMPLATE:
          case DEMANGLE_COMPONENT_TEMPLATE:
          case DEMANGLE_COMPONENT_RESTRICT_THIS:
          case DEMANGLE_COMPONENT_RESTRICT_THIS:
          case DEMANGLE_COMPONENT_VOLATILE_THIS:
          case DEMANGLE_COMPONENT_VOLATILE_THIS:
          case DEMANGLE_COMPONENT_CONST_THIS:
          case DEMANGLE_COMPONENT_CONST_THIS:
            dc = d_left (dc);
            dc = d_left (dc);
            break;
            break;
          case DEMANGLE_COMPONENT_QUAL_NAME:
          case DEMANGLE_COMPONENT_QUAL_NAME:
          case DEMANGLE_COMPONENT_LOCAL_NAME:
          case DEMANGLE_COMPONENT_LOCAL_NAME:
            dc = d_right (dc);
            dc = d_right (dc);
            break;
            break;
          case DEMANGLE_COMPONENT_CTOR:
          case DEMANGLE_COMPONENT_CTOR:
            *ctor_kind = dc->u.s_ctor.kind;
            *ctor_kind = dc->u.s_ctor.kind;
            ret = 1;
            ret = 1;
            dc = NULL;
            dc = NULL;
            break;
            break;
          case DEMANGLE_COMPONENT_DTOR:
          case DEMANGLE_COMPONENT_DTOR:
            *dtor_kind = dc->u.s_dtor.kind;
            *dtor_kind = dc->u.s_dtor.kind;
            ret = 1;
            ret = 1;
            dc = NULL;
            dc = NULL;
            break;
            break;
          }
          }
      }
      }
  }
  }
 
 
  return ret;
  return ret;
}
}
 
 
/* Return whether NAME is the mangled form of a g++ V3 ABI constructor
/* Return whether NAME is the mangled form of a g++ V3 ABI constructor
   name.  A non-zero return indicates the type of constructor.  */
   name.  A non-zero return indicates the type of constructor.  */
 
 
enum gnu_v3_ctor_kinds
enum gnu_v3_ctor_kinds
is_gnu_v3_mangled_ctor (const char *name)
is_gnu_v3_mangled_ctor (const char *name)
{
{
  enum gnu_v3_ctor_kinds ctor_kind;
  enum gnu_v3_ctor_kinds ctor_kind;
  enum gnu_v3_dtor_kinds dtor_kind;
  enum gnu_v3_dtor_kinds dtor_kind;
 
 
  if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
  if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
    return (enum gnu_v3_ctor_kinds) 0;
    return (enum gnu_v3_ctor_kinds) 0;
  return ctor_kind;
  return ctor_kind;
}
}
 
 
 
 
/* Return whether NAME is the mangled form of a g++ V3 ABI destructor
/* Return whether NAME is the mangled form of a g++ V3 ABI destructor
   name.  A non-zero return indicates the type of destructor.  */
   name.  A non-zero return indicates the type of destructor.  */
 
 
enum gnu_v3_dtor_kinds
enum gnu_v3_dtor_kinds
is_gnu_v3_mangled_dtor (const char *name)
is_gnu_v3_mangled_dtor (const char *name)
{
{
  enum gnu_v3_ctor_kinds ctor_kind;
  enum gnu_v3_ctor_kinds ctor_kind;
  enum gnu_v3_dtor_kinds dtor_kind;
  enum gnu_v3_dtor_kinds dtor_kind;
 
 
  if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
  if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
    return (enum gnu_v3_dtor_kinds) 0;
    return (enum gnu_v3_dtor_kinds) 0;
  return dtor_kind;
  return dtor_kind;
}
}
 
 
#endif /* IN_GLIBCPP_V3 */
#endif /* IN_GLIBCPP_V3 */
 
 
#ifdef STANDALONE_DEMANGLER
#ifdef STANDALONE_DEMANGLER
 
 
#include "getopt.h"
#include "getopt.h"
#include "dyn-string.h"
#include "dyn-string.h"
 
 
static void print_usage (FILE* fp, int exit_value);
static void print_usage (FILE* fp, int exit_value);
 
 
#define IS_ALPHA(CHAR)                                                  \
#define IS_ALPHA(CHAR)                                                  \
  (((CHAR) >= 'a' && (CHAR) <= 'z')                                     \
  (((CHAR) >= 'a' && (CHAR) <= 'z')                                     \
   || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
   || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
 
 
/* Non-zero if CHAR is a character than can occur in a mangled name.  */
/* Non-zero if CHAR is a character than can occur in a mangled name.  */
#define is_mangled_char(CHAR)                                           \
#define is_mangled_char(CHAR)                                           \
  (IS_ALPHA (CHAR) || IS_DIGIT (CHAR)                                   \
  (IS_ALPHA (CHAR) || IS_DIGIT (CHAR)                                   \
   || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$')
   || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$')
 
 
/* The name of this program, as invoked.  */
/* The name of this program, as invoked.  */
const char* program_name;
const char* program_name;
 
 
/* Prints usage summary to FP and then exits with EXIT_VALUE.  */
/* Prints usage summary to FP and then exits with EXIT_VALUE.  */
 
 
static void
static void
print_usage (FILE* fp, int exit_value)
print_usage (FILE* fp, int exit_value)
{
{
  fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
  fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
  fprintf (fp, "Options:\n");
  fprintf (fp, "Options:\n");
  fprintf (fp, "  -h,--help       Display this message.\n");
  fprintf (fp, "  -h,--help       Display this message.\n");
  fprintf (fp, "  -p,--no-params  Don't display function parameters\n");
  fprintf (fp, "  -p,--no-params  Don't display function parameters\n");
  fprintf (fp, "  -v,--verbose    Produce verbose demanglings.\n");
  fprintf (fp, "  -v,--verbose    Produce verbose demanglings.\n");
  fprintf (fp, "If names are provided, they are demangled.  Otherwise filters standard input.\n");
  fprintf (fp, "If names are provided, they are demangled.  Otherwise filters standard input.\n");
 
 
  exit (exit_value);
  exit (exit_value);
}
}
 
 
/* Option specification for getopt_long.  */
/* Option specification for getopt_long.  */
static const struct option long_options[] =
static const struct option long_options[] =
{
{
  { "help",      no_argument, NULL, 'h' },
  { "help",      no_argument, NULL, 'h' },
  { "no-params", no_argument, NULL, 'p' },
  { "no-params", no_argument, NULL, 'p' },
  { "verbose",   no_argument, NULL, 'v' },
  { "verbose",   no_argument, NULL, 'v' },
  { NULL,        no_argument, NULL, 0   },
  { NULL,        no_argument, NULL, 0   },
};
};
 
 
/* Main entry for a demangling filter executable.  It will demangle
/* Main entry for a demangling filter executable.  It will demangle
   its command line arguments, if any.  If none are provided, it will
   its command line arguments, if any.  If none are provided, it will
   filter stdin to stdout, replacing any recognized mangled C++ names
   filter stdin to stdout, replacing any recognized mangled C++ names
   with their demangled equivalents.  */
   with their demangled equivalents.  */
 
 
int
int
main (int argc, char *argv[])
main (int argc, char *argv[])
{
{
  int i;
  int i;
  int opt_char;
  int opt_char;
  int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;
  int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;
 
 
  /* Use the program name of this program, as invoked.  */
  /* Use the program name of this program, as invoked.  */
  program_name = argv[0];
  program_name = argv[0];
 
 
  /* Parse options.  */
  /* Parse options.  */
  do
  do
    {
    {
      opt_char = getopt_long (argc, argv, "hpv", long_options, NULL);
      opt_char = getopt_long (argc, argv, "hpv", long_options, NULL);
      switch (opt_char)
      switch (opt_char)
        {
        {
        case '?':  /* Unrecognized option.  */
        case '?':  /* Unrecognized option.  */
          print_usage (stderr, 1);
          print_usage (stderr, 1);
          break;
          break;
 
 
        case 'h':
        case 'h':
          print_usage (stdout, 0);
          print_usage (stdout, 0);
          break;
          break;
 
 
        case 'p':
        case 'p':
          options &= ~ DMGL_PARAMS;
          options &= ~ DMGL_PARAMS;
          break;
          break;
 
 
        case 'v':
        case 'v':
          options |= DMGL_VERBOSE;
          options |= DMGL_VERBOSE;
          break;
          break;
        }
        }
    }
    }
  while (opt_char != -1);
  while (opt_char != -1);
 
 
  if (optind == argc)
  if (optind == argc)
    /* No command line arguments were provided.  Filter stdin.  */
    /* No command line arguments were provided.  Filter stdin.  */
    {
    {
      dyn_string_t mangled = dyn_string_new (3);
      dyn_string_t mangled = dyn_string_new (3);
      char *s;
      char *s;
 
 
      /* Read all of input.  */
      /* Read all of input.  */
      while (!feof (stdin))
      while (!feof (stdin))
        {
        {
          char c;
          char c;
 
 
          /* Pile characters into mangled until we hit one that can't
          /* Pile characters into mangled until we hit one that can't
             occur in a mangled name.  */
             occur in a mangled name.  */
          c = getchar ();
          c = getchar ();
          while (!feof (stdin) && is_mangled_char (c))
          while (!feof (stdin) && is_mangled_char (c))
            {
            {
              dyn_string_append_char (mangled, c);
              dyn_string_append_char (mangled, c);
              if (feof (stdin))
              if (feof (stdin))
                break;
                break;
              c = getchar ();
              c = getchar ();
            }
            }
 
 
          if (dyn_string_length (mangled) > 0)
          if (dyn_string_length (mangled) > 0)
            {
            {
#ifdef IN_GLIBCPP_V3
#ifdef IN_GLIBCPP_V3
              s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL);
              s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL);
#else
#else
              s = cplus_demangle_v3 (dyn_string_buf (mangled), options);
              s = cplus_demangle_v3 (dyn_string_buf (mangled), options);
#endif
#endif
 
 
              if (s != NULL)
              if (s != NULL)
                {
                {
                  fputs (s, stdout);
                  fputs (s, stdout);
                  free (s);
                  free (s);
                }
                }
              else
              else
                {
                {
                  /* It might not have been a mangled name.  Print the
                  /* It might not have been a mangled name.  Print the
                     original text.  */
                     original text.  */
                  fputs (dyn_string_buf (mangled), stdout);
                  fputs (dyn_string_buf (mangled), stdout);
                }
                }
 
 
              dyn_string_clear (mangled);
              dyn_string_clear (mangled);
            }
            }
 
 
          /* If we haven't hit EOF yet, we've read one character that
          /* If we haven't hit EOF yet, we've read one character that
             can't occur in a mangled name, so print it out.  */
             can't occur in a mangled name, so print it out.  */
          if (!feof (stdin))
          if (!feof (stdin))
            putchar (c);
            putchar (c);
        }
        }
 
 
      dyn_string_delete (mangled);
      dyn_string_delete (mangled);
    }
    }
  else
  else
    /* Demangle command line arguments.  */
    /* Demangle command line arguments.  */
    {
    {
      /* Loop over command line arguments.  */
      /* Loop over command line arguments.  */
      for (i = optind; i < argc; ++i)
      for (i = optind; i < argc; ++i)
        {
        {
          char *s;
          char *s;
#ifdef IN_GLIBCPP_V3
#ifdef IN_GLIBCPP_V3
          int status;
          int status;
#endif
#endif
 
 
          /* Attempt to demangle.  */
          /* Attempt to demangle.  */
#ifdef IN_GLIBCPP_V3
#ifdef IN_GLIBCPP_V3
          s = __cxa_demangle (argv[i], NULL, NULL, &status);
          s = __cxa_demangle (argv[i], NULL, NULL, &status);
#else
#else
          s = cplus_demangle_v3 (argv[i], options);
          s = cplus_demangle_v3 (argv[i], options);
#endif
#endif
 
 
          /* If it worked, print the demangled name.  */
          /* If it worked, print the demangled name.  */
          if (s != NULL)
          if (s != NULL)
            {
            {
              printf ("%s\n", s);
              printf ("%s\n", s);
              free (s);
              free (s);
            }
            }
          else
          else
            {
            {
#ifdef IN_GLIBCPP_V3
#ifdef IN_GLIBCPP_V3
              fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status);
              fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status);
#else
#else
              fprintf (stderr, "Failed: %s\n", argv[i]);
              fprintf (stderr, "Failed: %s\n", argv[i]);
#endif
#endif
            }
            }
        }
        }
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
#endif /* STANDALONE_DEMANGLER */
#endif /* STANDALONE_DEMANGLER */
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.