+ return sym;
+}
+
+/* This finds the method COPY in the class whose type is T and whose
+ symbol is SYM_CLASS. */
+
+static struct symtabs_and_lines
+find_method (int funfirstline, struct linespec_result *canonical,
+ char *saved_arg,
+ char *copy, struct type *t, struct symbol *sym_class,
+ struct symtab *file_symtab)
+{
+ struct symtabs_and_lines values;
+ struct symbol *sym = NULL;
+ int i1; /* Counter for the symbol array. */
+ struct symbol **sym_arr = alloca (total_number_of_methods (t)
+ * sizeof (struct symbol *));
+
+ /* Find all methods with a matching name, and put them in
+ sym_arr. */
+
+ i1 = find_methods (t, copy, SYMBOL_LANGUAGE (sym_class), sym_arr,
+ file_symtab);
+
+ /* If we were given a specific overload instance in COPY, defer the field
+ acceptance till the strcmp_iw verification below, even if we found just
+ a single field with that name. */
+ if (i1 == 1 && strchr (copy, '(') == NULL)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
+
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ {
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_function_start_sal (sym,
+ funfirstline);
+ }
+ else
+ {
+ values.sals = NULL;
+ values.nelts = 0;
+ }
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* If we were given a specific overload instance, use that
+ (or error if no matches were found). Otherwise ask the user
+ which one to use. */
+ if (strchr (copy, '('))
+ {
+ int i;
+ char *name;
+ char *canon;
+ struct cleanup *cleanup;
+
+ /* Construct the proper search name based on SYM_CLASS and COPY.
+ SAVED_ARG may contain a valid name, but that name might not be
+ what is actually stored in the symbol table. For example,
+ if SAVED_ARG (and SYM_CLASS) were found via an import
+ ("using namespace" in C++), then the physname of
+ SYM_CLASS ("A::myclass") may not be the same as SAVED_ARG
+ ("myclass"). */
+ name = xmalloc (strlen (SYMBOL_NATURAL_NAME (sym_class))
+ + 2 /* "::" */ + strlen (copy) + 1);
+ strcpy (name, SYMBOL_NATURAL_NAME (sym_class));
+ strcat (name, "::");
+ strcat (name, copy);
+ canon = cp_canonicalize_string_no_typedefs (name);
+ if (canon != NULL)
+ {
+ xfree (name);
+ name = canon;
+ }
+ cleanup = make_cleanup (xfree, name);
+
+ for (i = 0; i < i1; ++i)
+ {
+ if (strcmp_iw (name, SYMBOL_LINKAGE_NAME (sym_arr[i])) == 0)
+ {
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_function_start_sal (sym_arr[i],
+ funfirstline);
+ do_cleanups (cleanup);
+ return values;
+ }
+ }
+
+ cplusplus_error (saved_arg, _("the class `%s' does not have "
+ "any method instance named %s"),
+ SYMBOL_PRINT_NAME (sym_class), copy);
+ }
+
+ return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ }
+ else
+ {
+ if (copy[0] == '~')
+ cplusplus_error (saved_arg,
+ "the class `%s' does not have destructor defined\n",
+ SYMBOL_PRINT_NAME (sym_class));
+ else
+ cplusplus_error (saved_arg,
+ "the class %s does not have any method named %s\n",
+ SYMBOL_PRINT_NAME (sym_class), copy);
+ }
+}
+
+\f
+
+/* Return the symtab associated to the filename given by the substring
+ of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+
+static struct symtab *
+symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+{
+ char *p1;
+ char *copy;
+ struct symtab *file_symtab;
+
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ if ((*p == '"') && is_quote_enclosed)
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ /* It may have the ending quote right after the file name. */
+ if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
+ || copy[p - *argptr - 1] == '\'')
+ copy[p - *argptr - 1] = 0;
+ else
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ file_symtab = lookup_symtab (copy);
+ if (file_symtab == 0)
+ {
+ if (!have_full_symbols () && !have_partial_symbols ())
+ throw_error (NOT_FOUND_ERROR,
+ _("No symbol table is loaded. "
+ "Use the \"file\" command."));
+ throw_error (NOT_FOUND_ERROR, _("No source file named %s."), copy);
+ }
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ return file_symtab;
+}
+
+/* Look up a function symbol in *ARGPTR. If found, advance *ARGPTR
+ and return the symbol. If not found, return NULL. */
+
+static struct symbol *
+find_function_symbol (char **argptr, char *p, int is_quote_enclosed)
+{
+ char *p1;
+ char *copy;
+ struct symbol *function_symbol;
+
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ if ((*p == '"') && is_quote_enclosed)
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ /* It may have the ending quote right after the file name. */
+ if ((is_quote_enclosed && copy[p - *argptr - 1] == '"')
+ || copy[p - *argptr - 1] == '\'')
+ copy[p - *argptr - 1] = 0;
+ else
+ copy[p - *argptr] = 0;
+
+ function_symbol = lookup_symbol (copy, get_selected_block (0),
+ VAR_DOMAIN, 0);
+ if (!function_symbol || SYMBOL_CLASS (function_symbol) != LOC_BLOCK)
+ return NULL;
+
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ return function_symbol;
+}
+
+\f
+
+/* This decodes a line where the argument is all digits (possibly
+ preceded by a sign). Q should point to the end of those digits;
+ the other arguments are as usual. */
+
+static struct symtabs_and_lines
+decode_all_digits (char **argptr, struct symtab *default_symtab,
+ int default_line, struct linespec_result *canonical,
+ struct symtab *file_symtab, char *q)
+
+{
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+
+ enum sign
+ {
+ none, plus, minus
+ }
+ sign = none;
+
+ /* We might need a canonical line spec if no file was specified. */
+ int need_canonical = (file_symtab == NULL) ? 1 : 0;
+
+ init_sal (&val);
+
+ val.pspace = current_program_space;
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarantee that this section of code is never executed
+ when we are called with just a function name, since
+ set_default_source_symtab_and_line uses
+ select_source_symtab that calls us with such an argument. */
+
+ if (file_symtab == 0 && default_symtab == 0)
+ {
+ /* Make sure we have at least a default source file. */
+ set_default_source_symtab_and_line ();
+ initialize_defaults (&default_symtab, &default_line);
+ }
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ val.line = atoi (*argptr);
+ switch (sign)
+ {
+ case plus:
+ if (q == *argptr)
+ val.line = 5;
+ if (file_symtab == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (q == *argptr)
+ val.line = 15;
+ if (file_symtab == 0)
+ val.line = default_line - val.line;
+ else
+ val.line = 1;
+ break;
+ case none:
+ break; /* No need to adjust val.line. */
+ }
+
+ while (*q == ' ' || *q == '\t')
+ q++;
+ *argptr = q;
+ if (file_symtab == 0)
+ file_symtab = default_symtab;
+
+ /* It is possible that this source file has more than one symtab,
+ and that the new line number specification has moved us from the
+ default (in file_symtab) to a new one. */
+ val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
+ if (val.symtab == 0)
+ val.symtab = file_symtab;
+
+ val.pspace = SYMTAB_PSPACE (val.symtab);
+ val.pc = 0;
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ values.sals[0].explicit_line = 1;
+ return values;
+}
+
+\f
+
+/* Decode a linespec starting with a dollar sign. */
+
+static struct symtabs_and_lines
+decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
+ struct linespec_result *canonical, struct symtab *file_symtab)
+{
+ LONGEST valx;
+ int index = 0;
+ int need_canonical = 0;
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+ char *p;
+ struct symbol *sym;
+ struct minimal_symbol *msymbol;
+
+ p = (copy[1] == '$') ? copy + 2 : copy + 1;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (!*p) /* Reached end of token without hitting non-digit. */
+ {
+ /* We have a value history reference. */
+ struct value *val_history;
+
+ sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
+ val_history = access_value_history ((copy[1] == '$') ? -index : index);
+ if (TYPE_CODE (value_type (val_history)) != TYPE_CODE_INT)
+ error (_("History values used in line "
+ "specs must have integer values."));
+ valx = value_as_long (val_history);
+ }
+ else
+ {
+ /* Not all digits -- may be user variable/function or a
+ convenience variable. */
+
+ /* Look up entire name as a symbol first. */
+ sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0);
+ file_symtab = (struct symtab *) NULL;
+ need_canonical = 1;
+ /* Symbol was found --> jump to normal symbol processing. */
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
+
+ /* If symbol was not found, look in minimal symbol tables. */
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ /* Min symbol was found --> jump to minsym processing. */
+ if (msymbol)
+ return minsym_found (funfirstline, msymbol);
+
+ /* Not a user variable or function -- must be convenience variable. */
+ if (!get_internalvar_integer (lookup_internalvar (copy + 1), &valx))
+ error (_("Convenience variables used in line "
+ "specs must have integer values."));
+ }
+
+ init_sal (&val);
+
+ /* Either history value or convenience value from above, in valx. */
+ val.symtab = file_symtab ? file_symtab : default_symtab;
+ val.line = valx;
+ val.pc = 0;
+ val.pspace = current_program_space;
+
+ values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
+ values.sals[0] = val;
+ values.nelts = 1;
+
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
+
+ return values;
+}
+
+\f
+
+/* A helper for decode_line_1 that tries to find a label. The label
+ is searched for in the current block.
+ FUNCTION_SYMBOL is the enclosing function; or NULL if none
+ specified.
+ COPY is the name of the label to find.
+ CANONICAL is the same as the "canonical" argument to decode_line_1.
+ RESULT is a pointer to a symtabs_and_lines structure which will be
+ filled in on success.
+ This function returns 1 if a label was found, 0 otherwise. */
+
+static int
+decode_label (struct symbol *function_symbol, char *copy,
+ struct linespec_result *canonical,
+ struct symtabs_and_lines *result)
+{
+ struct symbol *sym;
+ struct block *block;
+
+ if (function_symbol)
+ block = SYMBOL_BLOCK_VALUE (function_symbol);
+ else
+ {
+ block = get_selected_block (0);
+ for (;
+ block && !BLOCK_FUNCTION (block);
+ block = BLOCK_SUPERBLOCK (block))
+ ;
+ if (!block)
+ return 0;
+ function_symbol = BLOCK_FUNCTION (block);
+ }
+
+ sym = lookup_symbol (copy, block, LABEL_DOMAIN, 0);
+
+ if (sym != NULL)
+ *result = symbol_found (0, canonical, copy, sym, NULL, function_symbol);
+
+ return sym != NULL;
+}
+
+/* Decode a linespec that's a variable. If FILE_SYMTAB is non-NULL,
+ look in that symtab's static variables first. */
+
+static struct symtabs_and_lines
+decode_variable (char *copy, int funfirstline,
+ struct linespec_result *canonical,
+ struct symtab *file_symtab)
+{
+ char *name, *canon;
+ struct symbol *sym;
+ struct cleanup *cleanup;
+ struct minimal_symbol *msymbol;
+
+ name = copy;
+ cleanup = make_cleanup (null_cleanup, NULL);
+ canon = cp_canonicalize_string_no_typedefs (copy);
+ if (canon != NULL)
+ {
+ name = canon;
+ make_cleanup (xfree, name);
+ }
+
+ sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0);
+
+ if (sym != NULL)
+ {
+ do_cleanups (cleanup);
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, NULL);
+ }