+/* Next come some helper functions for decode_compound. */
+
+/* Return the symbol corresponding to the substring of *ARGPTR ending
+ at P, allowing whitespace. Also, advance *ARGPTR past the symbol
+ name in question, the compound object separator ("::" or "."), and
+ whitespace. */
+
+static struct symbol *
+lookup_prefix_sym (char **argptr, char *p)
+{
+ char *p1;
+ char *copy;
+
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
+
+ /* Discard the class name from the arg. */
+ p = p1 + (p1[0] == ':' ? 2 : 1);
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ return lookup_symbol (copy, 0, STRUCT_DOMAIN, 0,
+ (struct symtab **) NULL);
+}
+
+/* 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, char ***canonical, char *saved_arg,
+ char *copy, struct type *t, struct symbol *sym_class)
+{
+ struct symtabs_and_lines values;
+ struct symbol *sym = 0;
+ 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 = collect_methods (copy, t, sym_arr);
+
+ if (i1 == 1)
+ {
+ /* 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.nelts = 0;
+ }
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* There is more than one field with that name
+ (overloaded). Ask the user which one to use. */
+ return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ }
+ else
+ {
+ char *tmp;
+
+ if (is_operator_name (copy))
+ {
+ tmp = (char *) alloca (strlen (copy + 3) + 9);
+ strcpy (tmp, "operator ");
+ strcat (tmp, copy + 3);
+ }
+ else
+ tmp = copy;
+ if (tmp[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), tmp);
+ }
+}
+
+/* Find all methods named COPY in the class whose type is T, and put
+ them in SYM_ARR. Return the number of methods found. */
+
+static int
+collect_methods (char *copy, struct type *t,
+ struct symbol **sym_arr)
+{
+ int i1 = 0; /* Counter for the symbol array. */
+
+ if (destructor_name_p (copy, t))
+ {
+ /* Destructors are a special case. */
+ int m_index, f_index;
+
+ if (get_destructor_fn_field (t, &m_index, &f_index))
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, m_index);
+
+ sym_arr[i1] =
+ lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index),
+ NULL, VAR_DOMAIN, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ i1++;
+ }
+ }
+ else
+ i1 = find_methods (t, copy, sym_arr);
+
+ return i1;
+}
+
+\f
+
+/* Return the symtab associated to the filename given by the substring
+ of *ARGPTR ending at P, and advance ARGPTR past that filename. If
+ NOT_FOUND_PTR is not null and the source file is not found, store
+ boolean true at the location pointed to and do not issue an
+ error message. */
+
+static struct symtab *
+symtab_from_filename (char **argptr, char *p, int is_quote_enclosed,
+ int *not_found_ptr)
+{
+ 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] = 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 ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ if (not_found_ptr)
+ {
+ *not_found_ptr = 1;
+ throw_exception (RETURN_ERROR);
+ }
+ 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;
+}
+
+\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, char ***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 == 0) ? 1 : 0;
+
+ init_sal (&val);
+
+ /* 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.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);
+ 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,
+ char ***canonical, struct symtab *file_symtab)
+{
+ struct value *valx;
+ int index = 0;
+ int need_canonical = 0;
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+ char *p;
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+ 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. */
+ sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
+ valx = access_value_history ((copy[1] == '$') ? -index : index);
+ if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
+ error ("History values used in line specs must have integer values.");
+ }
+ 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, &sym_symtab);
+ file_symtab = (struct symtab *) 0;
+ need_canonical = 1;
+ /* Symbol was found --> jump to normal symbol processing. */
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+
+ /* 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. */
+ need_canonical = (file_symtab == 0) ? 1 : 0;
+ valx = value_of_internalvar (lookup_internalvar (copy + 1));
+ if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
+ 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 = value_as_long (valx);
+ val.pc = 0;
+
+ 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
+
+/* Decode a linespec that's a variable. If FILE_SYMTAB is non-NULL,
+ look in that symtab's static variables first. If NOT_FOUND_PTR is not NULL and
+ the function cannot be found, store boolean true in the location pointed to
+ and do not issue an error message. */
+
+static struct symtabs_and_lines
+decode_variable (char *copy, int funfirstline, char ***canonical,
+ struct symtab *file_symtab, int *not_found_ptr)
+{
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+
+ struct minimal_symbol *msymbol;
+
+ sym = lookup_symbol (copy,
+ (file_symtab
+ ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
+ STATIC_BLOCK)
+ : get_selected_block (0)),
+ VAR_DOMAIN, 0, &sym_symtab);
+
+ if (sym != NULL)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, sym_symtab);
+
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+
+ if (msymbol != NULL)
+ return minsym_found (funfirstline, msymbol);
+
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+
+ if (not_found_ptr)
+ {
+ *not_found_ptr = 1;
+ throw_exception (RETURN_ERROR);
+ }
+
+ error ("Function \"%s\" not defined.", copy);
+}
+
+