+/* 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. */
+ const char *name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+ if (!startswith (name, CP_OPERATOR_STR))
+ return 0;
+
+ name += 8;
+ if (! strchr (" \t\f\n\r", *name))
+ return 0;
+
+ while (strchr (" \t\f\n\r", *name))
+ name++;
+
+ if (!('a' <= *name && *name <= 'z')
+ && !('A' <= *name && *name <= 'Z')
+ && *name != '_')
+ /* If this doesn't look like the start of an identifier, then it
+ isn't a type conversion operator. */
+ return 0;
+ else if (startswith (name, "new"))
+ name += 3;
+ else if (startswith (name, "delete"))
+ name += 6;
+ else
+ /* If it doesn't look like new or delete, it's a type conversion
+ operator. */
+ return 1;
+
+ /* 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;
+}
+