/* Support for printing C and C++ types for GDB, the GNU debugger.
- Copyright 1986, 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1998, 1999
+ Copyright 1986, 1988, 1989, 1991, 1993-1996, 1998-2000
Free Software Foundation, Inc.
This file is part of GDB.
/* Flag indicating target was compiled by HP compiler */
extern int hp_som_som_object_present;
-static void cp_type_print_method_args PARAMS ((struct type ** args, char *prefix, char *varstring, int staticp, GDB_FILE * stream));
+static void cp_type_print_method_args (struct type ** args, char *prefix,
+ char *varstring, int staticp,
+ struct ui_file *stream);
-static void
-c_type_print_args PARAMS ((struct type *, GDB_FILE *));
+static void c_type_print_args (struct type *, struct ui_file *);
-static void
-cp_type_print_derivation_info PARAMS ((GDB_FILE *, struct type *));
+static void cp_type_print_derivation_info (struct ui_file *, struct type *);
-void
-c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
+void c_type_print_varspec_prefix (struct type *, struct ui_file *, int,
+ int);
-static void
-c_type_print_cv_qualifier PARAMS ((struct type *, GDB_FILE *, int, int));
+static void c_type_print_cv_qualifier (struct type *, struct ui_file *,
+ int, int);
\f
-/* Print a description of a type in the format of a
- typedef for the current language.
- NEW is the new name for a type TYPE. */
-
-void
-c_typedef_print (type, new, stream)
- struct type *type;
- struct symbol *new;
- GDB_FILE *stream;
-{
- CHECK_TYPEDEF (type);
- switch (current_language->la_language)
- {
-#ifdef _LANG_c
- case language_c:
- case language_cplus:
- fprintf_filtered (stream, "typedef ");
- type_print (type, "", stream, 0);
- if (TYPE_NAME ((SYMBOL_TYPE (new))) == 0
- || !STREQ (TYPE_NAME ((SYMBOL_TYPE (new))), SYMBOL_NAME (new)))
- fprintf_filtered (stream, " %s", SYMBOL_SOURCE_NAME (new));
- break;
-#endif
-#ifdef _LANG_m2
- case language_m2:
- fprintf_filtered (stream, "TYPE ");
- if (!TYPE_NAME (SYMBOL_TYPE (new)) ||
- !STREQ (TYPE_NAME (SYMBOL_TYPE (new)), SYMBOL_NAME (new)))
- fprintf_filtered (stream, "%s = ", SYMBOL_SOURCE_NAME (new));
- else
- fprintf_filtered (stream, "<builtin> = ");
- type_print (type, "", stream, 0);
- break;
-#endif
-#ifdef _LANG_chill
- case language_chill:
- fprintf_filtered (stream, "SYNMODE ");
- if (!TYPE_NAME (SYMBOL_TYPE (new)) ||
- !STREQ (TYPE_NAME (SYMBOL_TYPE (new)), SYMBOL_NAME (new)))
- fprintf_filtered (stream, "%s = ", SYMBOL_SOURCE_NAME (new));
- else
- fprintf_filtered (stream, "<builtin> = ");
- type_print (type, "", stream, 0);
- break;
-#endif
- default:
- error ("Language not supported.");
- }
- fprintf_filtered (stream, ";\n");
-}
-
/* LEVEL is the depth to indent lines by. */
void
-c_print_type (type, varstring, stream, show, level)
- struct type *type;
- char *varstring;
- GDB_FILE *stream;
- int show;
- int level;
+c_print_type (struct type *type, char *varstring, struct ui_file *stream,
+ int show, int level)
{
register enum type_code code;
int demangled_args;
derivation via protected inheritance, so gdb can print it out */
static void
-cp_type_print_derivation_info (stream, type)
- GDB_FILE *stream;
- struct type *type;
+cp_type_print_derivation_info (struct ui_file *stream, struct type *type)
{
char *name;
int i;
/* Print the C++ method arguments ARGS to the file STREAM. */
static void
-cp_type_print_method_args (args, prefix, varstring, staticp, stream)
- struct type **args;
- char *prefix;
- char *varstring;
- int staticp;
- GDB_FILE *stream;
+cp_type_print_method_args (struct type **args, char *prefix, char *varstring,
+ int staticp, struct ui_file *stream)
{
int i;
SHOW is always zero on recursive calls. */
void
-c_type_print_varspec_prefix (type, stream, show, passed_a_ptr)
- struct type *type;
- GDB_FILE *stream;
- int show;
- int passed_a_ptr;
+c_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
+ int show, int passed_a_ptr)
{
char *name;
if (type == 0)
NEED_SPACE = 1 indicates an initial white space is needed */
static void
-c_type_print_cv_qualifier (type, stream, need_pre_space, need_post_space)
- struct type *type;
- GDB_FILE *stream;
- int need_pre_space;
- int need_post_space;
+c_type_print_cv_qualifier (struct type *type, struct ui_file *stream,
+ int need_pre_space, int need_post_space)
{
int flag = 0;
static void
-c_type_print_args (type, stream)
- struct type *type;
- GDB_FILE *stream;
+c_type_print_args (struct type *type, struct ui_file *stream)
{
int i;
struct type **args;
fprintf_filtered (stream, ")");
}
+
+/* Return true iff the j'th overloading of the i'th method of TYPE
+ is a type conversion operator, like `operator int () { ... }'.
+ When listing a class's methods, we don't print the return type of
+ such operators. */
+static int
+is_type_conversion_operator (struct type *type, int i, int j)
+{
+ /* I think the whole idea of recognizing type conversion operators
+ by their name is pretty terrible. But I don't think our present
+ data structure gives us any other way to tell. If you know of
+ some other way, feel free to rewrite this function. */
+ char *name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+ if (strncmp (name, "operator", 8) != 0)
+ return 0;
+
+ name += 8;
+ if (! strchr (" \t\f\n\r", *name))
+ return 0;
+
+ while (strchr (" \t\f\n\r", *name))
+ name++;
+
+ if (strncmp (name, "new", 3) == 0)
+ name += 3;
+ else if (strncmp (name, "delete", 6) == 0)
+ name += 6;
+ else
+ return 0;
+
+ /* Is that really the end of the name? */
+ if (('a' <= *name && *name <= 'z')
+ || ('A' <= *name && *name <= 'Z')
+ || ('0' <= *name && *name <= '9')
+ || *name == '_')
+ /* No, so the identifier following "operator" must be a type name,
+ and this is a type conversion operator. */
+ return 1;
+
+ /* That was indeed the end of the name, so it was `operator new' or
+ `operator delete', neither of which are type conversion operators. */
+ return 0;
+}
+
+
+/* Given a C++ qualified identifier QID, strip off the qualifiers,
+ yielding the unqualified name. The return value is a pointer into
+ the original string.
+
+ It's a pity we don't have this information in some more structured
+ form. Even the author of this function feels that writing little
+ parsers like this everywhere is stupid. */
+static char *
+remove_qualifiers (char *qid)
+{
+ int quoted = 0; /* zero if we're not in quotes;
+ '"' if we're in a double-quoted string;
+ '\'' if we're in a single-quoted string. */
+ int depth = 0; /* number of unclosed parens we've seen */
+ char *parenstack = (char *) alloca (strlen (qid));
+ char *scan;
+ char *last = 0; /* The character after the rightmost
+ `::' token we've seen so far. */
+
+ for (scan = qid; *scan; scan++)
+ {
+ if (quoted)
+ {
+ if (*scan == quoted)
+ quoted = 0;
+ else if (*scan == '\\' && *(scan + 1))
+ scan++;
+ }
+ else if (scan[0] == ':' && scan[1] == ':')
+ {
+ /* If we're inside parenthesis (i.e., an argument list) or
+ angle brackets (i.e., a list of template arguments), then
+ we don't record the position of this :: token, since it's
+ not relevant to the top-level structure we're trying
+ to operate on. */
+ if (depth == 0)
+ {
+ last = scan + 2;
+ scan++;
+ }
+ }
+ else if (*scan == '"' || *scan == '\'')
+ quoted = *scan;
+ else if (*scan == '(')
+ parenstack[depth++] = ')';
+ else if (*scan == '[')
+ parenstack[depth++] = ']';
+ /* We're going to treat <> as a pair of matching characters,
+ since we're more likely to see those in template id's than
+ real less-than characters. What a crock. */
+ else if (*scan == '<')
+ parenstack[depth++] = '>';
+ else if (*scan == ')' || *scan == ']' || *scan == '>')
+ {
+ if (depth > 0 && parenstack[depth - 1] == *scan)
+ depth--;
+ else
+ {
+ /* We're going to do a little error recovery here. If we
+ don't find a match for *scan on the paren stack, but
+ there is something lower on the stack that does match, we
+ pop the stack to that point. */
+ int i;
+
+ for (i = depth - 1; i >= 0; i--)
+ if (parenstack[i] == *scan)
+ {
+ depth = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (last)
+ return last;
+ else
+ /* We didn't find any :: tokens at the top level, so declare the
+ whole thing an unqualified identifier. */
+ return qid;
+}
+
+
/* Print any array sizes, function arguments or close parentheses
needed after the variable name (to describe its type).
Args work like c_type_print_varspec_prefix. */
void
-c_type_print_varspec_suffix (type, stream, show, passed_a_ptr, demangled_args)
- struct type *type;
- GDB_FILE *stream;
- int show;
- int passed_a_ptr;
- int demangled_args;
+c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
+ int show, int passed_a_ptr, int demangled_args)
{
if (type == 0)
return;
We increase it for some recursive calls. */
void
-c_type_print_base (type, stream, show, level)
- struct type *type;
- GDB_FILE *stream;
- int show;
- int level;
+c_type_print_base (struct type *type, struct ui_file *stream, int show,
+ int level)
{
register int i;
register int len;
}
else if (!is_constructor && /* constructors don't have declared types */
!is_full_physname_constructor && /* " " */
- !strstr (method_name, "operator ")) /* Not a type conversion operator */
- /* (note space -- other operators don't have it) */
+ !is_type_conversion_operator (type, i, j))
{
type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
"", stream, -1);
else
{
char *p;
- char *demangled_no_class = strrchr (demangled_name, ':');
+ char *demangled_no_class
+ = remove_qualifiers (demangled_name);
- if (demangled_no_class == NULL)
- demangled_no_class = demangled_name;
- else
- {
- ++demangled_no_class; /* skip over last ':' */
- }
- /* get rid of the static word appended by the demangler */
+ /* get rid of the `static' appended by the demangler */
p = strstr (demangled_no_class, " static");
if (p != NULL)
{