* completer.c (gdb_completer_loc_break_characters): New variable.

(line_completion_function): If we are completing on locations,
	back up the start of word pointer past all characters which can
	appear in a location spec.
	(location_completer): New function.

	* completer.h: Add prototype for location_completer.

	* symtab.c (make_source_files_completion_list)
	(add_filename_to_list, not_interesting_fname): New functions.
	(filename_seen): New function, body extracted from
	output_source_filename.
	(output_source_filename): Call filename_seen to check if the file
	was already printed.
	(make_symbol_completion_list): If TEXT includes a
	double-quoted string, return an empty list, not NULL.
	(make_file_symbol_completion_list): New function, similar to
	make_symbol_completion_list but with an additional argument
	SRCFILE.

	* symtab.h (make_file_symbol_completion_list)
	(make_source_files_completion_list): Add prototypes.

	* breakpoint.c (_initialize_breakpoint): Make location_completer
	be the completion function for all commands which set breakpoints
	and watchpoints.
	(top-level): #include "completer.h".

	* tracepoint.c (_initialize_tracepoint): Make location_completer
	be the completion function for the "trace" command.
	(top-level): #include "completer.h".

	* printcmd.c (_initialize_printcmd): Make location_completer be
	the completion function for the "print", "inspect", "call", and
	"disassemble" commands.
	(top-level): #include "completer.h".

	* infcmd.c (_initialize_infcmd): Make location_completer be the
	completion function for the "go", "jump", and "until" commands.
	(top-level): #include "completer.h".
This commit is contained in:
Eli Zaretskii 2001-06-11 16:05:25 +00:00
parent 6439fc285d
commit c94fdfd0a8
9 changed files with 608 additions and 67 deletions

View file

@ -1,3 +1,46 @@
2001-06-11 Eli Zaretskii <eliz@is.elta.co.il>
* completer.c (gdb_completer_loc_break_characters): New variable.
(line_completion_function): If we are completing on locations,
back up the start of word pointer past all characters which can
appear in a location spec.
(location_completer): New function.
* completer.h: Add prototype for location_completer.
* symtab.c (make_source_files_completion_list)
(add_filename_to_list, not_interesting_fname): New functions.
(filename_seen): New function, body extracted from
output_source_filename.
(output_source_filename): Call filename_seen to check if the file
was already printed.
(make_symbol_completion_list): If TEXT includes a
double-quoted string, return an empty list, not NULL.
(make_file_symbol_completion_list): New function, similar to
make_symbol_completion_list but with an additional argument
SRCFILE.
* symtab.h (make_file_symbol_completion_list)
(make_source_files_completion_list): Add prototypes.
* breakpoint.c (_initialize_breakpoint): Make location_completer
be the completion function for all commands which set breakpoints
and watchpoints.
(top-level): #include "completer.h".
* tracepoint.c (_initialize_tracepoint): Make location_completer
be the completion function for the "trace" command.
(top-level): #include "completer.h".
* printcmd.c (_initialize_printcmd): Make location_completer be
the completion function for the "print", "inspect", "call", and
"disassemble" commands.
(top-level): #include "completer.h".
* infcmd.c (_initialize_infcmd): Make location_completer be the
completion function for the "go", "jump", and "until" commands.
(top-level): #include "completer.h".
2001-06-10 Christopher Faylor <cgf@redhat.com> 2001-06-10 Christopher Faylor <cgf@redhat.com>
* gnu-regex.c: Eliminate obsolete check for _MSC_VER. * gnu-regex.c: Eliminate obsolete check for _MSC_VER.

View file

@ -40,6 +40,7 @@
#include "symfile.h" #include "symfile.h"
#include "objfiles.h" #include "objfiles.h"
#include "linespec.h" #include "linespec.h"
#include "completer.h"
#ifdef UI_OUT #ifdef UI_OUT
#include "ui-out.h" #include "ui-out.h"
#endif #endif
@ -7582,24 +7583,29 @@ then no output is printed when it is hit, except what the commands print.");
Usage is `condition N COND', where N is an integer and COND is an\n\ Usage is `condition N COND', where N is an integer and COND is an\n\
expression to be evaluated whenever breakpoint N is reached. "); expression to be evaluated whenever breakpoint N is reached. ");
add_com ("tbreak", class_breakpoint, tbreak_command, c = add_com ("tbreak", class_breakpoint, tbreak_command,
"Set a temporary breakpoint. Args like \"break\" command.\n\ "Set a temporary breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint is only temporary,\n\ Like \"break\" except the breakpoint is only temporary,\n\
so it will be deleted when hit. Equivalent to \"break\" followed\n\ so it will be deleted when hit. Equivalent to \"break\" followed\n\
by using \"enable delete\" on the breakpoint number."); by using \"enable delete\" on the breakpoint number.");
add_com ("txbreak", class_breakpoint, tbreak_at_finish_command, c->completer = location_completer;
"Set temporary breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n");
add_com ("hbreak", class_breakpoint, hbreak_command, c = add_com ("txbreak", class_breakpoint, tbreak_at_finish_command,
"Set a hardware assisted breakpoint. Args like \"break\" command.\n\ "Set temporary breakpoint at procedure exit. Either there should\n\
be no argument or the argument must be a depth.\n");
c->completer = location_completer;
c = add_com ("hbreak", class_breakpoint, hbreak_command,
"Set a hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"break\" except the breakpoint requires hardware support,\n\ Like \"break\" except the breakpoint requires hardware support,\n\
some target hardware may not have this support."); some target hardware may not have this support.");
c->completer = location_completer;
add_com ("thbreak", class_breakpoint, thbreak_command, c = add_com ("thbreak", class_breakpoint, thbreak_command,
"Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\ "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\
Like \"hbreak\" except the breakpoint is only temporary,\n\ Like \"hbreak\" except the breakpoint is only temporary,\n\
so it will be deleted when hit."); so it will be deleted when hit.");
c->completer = location_completer;
add_prefix_cmd ("enable", class_breakpoint, enable_command, add_prefix_cmd ("enable", class_breakpoint, enable_command,
"Enable some breakpoints.\n\ "Enable some breakpoints.\n\
@ -7701,8 +7707,8 @@ is executing in.\n\
\n\ \n\
See also the \"delete\" command which clears breakpoints by number.", NULL)); See also the \"delete\" command which clears breakpoints by number.", NULL));
add_com ("break", class_breakpoint, break_command, c = add_com ("break", class_breakpoint, break_command,
concat ("Set breakpoint at specified line or function.\n\ concat ("Set breakpoint at specified line or function.\n\
Argument may be line number, function name, or \"*\" and an address.\n\ Argument may be line number, function name, or \"*\" and an address.\n\
If line number is specified, break at start of code for that line.\n\ If line number is specified, break at start of code for that line.\n\
If function is specified, break at start of code for that function.\n\ If function is specified, break at start of code for that function.\n\
@ -7713,6 +7719,8 @@ This is useful for breaking on return to a stack frame.\n\
Multiple breakpoints at one place are permitted, and useful if conditional.\n\ Multiple breakpoints at one place are permitted, and useful if conditional.\n\
\n\ \n\
Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)); Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL));
c->completer = location_completer;
add_com_alias ("b", "break", class_run, 1); add_com_alias ("b", "break", class_run, 1);
add_com_alias ("br", "break", class_run, 1); add_com_alias ("br", "break", class_run, 1);
add_com_alias ("bre", "break", class_run, 1); add_com_alias ("bre", "break", class_run, 1);
@ -7858,20 +7866,23 @@ Like \"catch\" except the catchpoint is only temporary,\n\
so it will be deleted when hit. Equivalent to \"catch\" followed\n\ so it will be deleted when hit. Equivalent to \"catch\" followed\n\
by using \"enable delete\" on the catchpoint number."); by using \"enable delete\" on the catchpoint number.");
add_com ("watch", class_breakpoint, watch_command, c = add_com ("watch", class_breakpoint, watch_command,
"Set a watchpoint for an expression.\n\ "Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\ A watchpoint stops execution of your program whenever the value of\n\
an expression changes."); an expression changes.");
c->completer = location_completer;
add_com ("rwatch", class_breakpoint, rwatch_command, c = add_com ("rwatch", class_breakpoint, rwatch_command,
"Set a read watchpoint for an expression.\n\ "Set a read watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\ A watchpoint stops execution of your program whenever the value of\n\
an expression is read."); an expression is read.");
c->completer = location_completer;
add_com ("awatch", class_breakpoint, awatch_command, c = add_com ("awatch", class_breakpoint, awatch_command,
"Set a watchpoint for an expression.\n\ "Set a watchpoint for an expression.\n\
A watchpoint stops execution of your program whenever the value of\n\ A watchpoint stops execution of your program whenever the value of\n\
an expression is either read or written."); an expression is either read or written.");
c->completer = location_completer;
add_info ("watchpoints", breakpoints_info, add_info ("watchpoints", breakpoints_info,
"Synonym for ``info breakpoints''."); "Synonym for ``info breakpoints''.");

View file

@ -22,12 +22,14 @@
#include "symtab.h" #include "symtab.h"
#include "gdbtypes.h" #include "gdbtypes.h"
#include "expression.h" #include "expression.h"
#include "filenames.h" /* for DOSish file names */
/* FIXME: This is needed because of lookup_cmd_1(). /* FIXME: This is needed because of lookup_cmd_1().
We should be calling a hook instead so we eliminate the CLI dependency. */ We should be calling a hook instead so we eliminate the CLI dependency. */
#include "gdbcmd.h" #include "gdbcmd.h"
/* Needed for rl_completer_word_break_characters() */ /* Needed for rl_completer_word_break_characters() and for
filename_completion_function. */
#include <readline/readline.h> #include <readline/readline.h>
/* readline defines this. */ /* readline defines this. */
@ -72,6 +74,10 @@ static char *gdb_completer_file_name_break_characters = " \t\n*|\"';?><@";
static char *gdb_completer_file_name_break_characters = " \t\n*|\"';:?><"; static char *gdb_completer_file_name_break_characters = " \t\n*|\"';:?><";
#endif #endif
/* These are used when completing on locations, which can mix file
names and symbol names separated by a colon. */
static char *gdb_completer_loc_break_characters = " \t\n*|\"';:?><,";
/* Characters that can be used to quote completion strings. Note that we /* Characters that can be used to quote completion strings. Note that we
can't include '"' because the gdb C parser treats such quoted sequences can't include '"' because the gdb C parser treats such quoted sequences
as strings. */ as strings. */
@ -95,8 +101,6 @@ get_gdb_completer_quote_characters (void)
char ** char **
filename_completer (char *text, char *word) filename_completer (char *text, char *word)
{ {
/* From readline. */
extern char *filename_completion_function (char *, int);
int subsequent_name; int subsequent_name;
char **return_val; char **return_val;
int return_val_used; int return_val_used;
@ -170,6 +174,153 @@ extern char *filename_completion_function (char *, int);
return return_val; return return_val;
} }
/* Complete on locations, which might be of two possible forms:
file:line
or
symbol+offset
This is intended to be used in commands that set breakpoints etc. */
char **
location_completer (char *text, char *word)
{
int n_syms = 0, n_files = 0;
char ** fn_list = NULL;
char ** list = NULL;
char *p;
int quote_found = 0;
int quoted = *text == '\'' || *text == '"';
int quote_char = '\0';
char *colon = NULL;
char *file_to_match = NULL;
char *symbol_start = text;
char *orig_text = text;
size_t text_len;
/* Do we have an unquoted colon, as in "break foo.c::bar"? */
for (p = text; *p != '\0'; ++p)
{
if (*p == '\\' && p[1] == '\'')
p++;
else if (*p == '\'' || *p == '"')
{
quote_found = *p;
quote_char = *p++;
while (*p != '\0' && *p != quote_found)
{
if (*p == '\\' && p[1] == quote_found)
p++;
p++;
}
if (*p == quote_found)
quote_found = 0;
else
break; /* hit the end of text */
}
#if HAVE_DOS_BASED_FILE_SYSTEM
/* If we have a DOS-style absolute file name at the beginning of
TEXT, and the colon after the drive letter is the only colon
we found, pretend the colon is not there. */
else if (p < text + 3 && *p == ':' && p == text + 1 + quoted)
;
#endif
else if (*p == ':' && !colon)
{
colon = p;
symbol_start = p + 1;
}
else if (strchr (gdb_completer_word_break_characters, *p))
symbol_start = p + 1;
}
if (quoted)
text++;
text_len = strlen (text);
/* Where is the file name? */
if (colon)
{
char *s;
file_to_match = (char *) xmalloc (colon - text + 1);
strncpy (file_to_match, text, colon - text + 1);
/* Remove trailing colons and quotes from the file name. */
for (s = file_to_match + (colon - text);
s > file_to_match;
s--)
if (*s == ':' || *s == quote_char)
*s = '\0';
}
/* If the text includes a colon, they want completion only on a
symbol name after the colon. Otherwise, we need to complete on
symbols as well as on files. */
if (colon)
{
list = make_file_symbol_completion_list (symbol_start, word,
file_to_match);
xfree (file_to_match);
}
else
{
list = make_symbol_completion_list (symbol_start, word);
/* If text includes characters which cannot appear in a file
name, they cannot be asking for completion on files. */
if (strcspn (text, gdb_completer_file_name_break_characters) == text_len)
fn_list = make_source_files_completion_list (text, text);
}
/* How many completions do we have in both lists? */
if (fn_list)
for ( ; fn_list[n_files]; n_files++)
;
if (list)
for ( ; list[n_syms]; n_syms++)
;
/* Make list[] large enough to hold both lists, then catenate
fn_list[] onto the end of list[]. */
if (n_syms && n_files)
{
list = xrealloc (list, (n_syms + n_files + 1) * sizeof (char *));
memcpy (list + n_syms, fn_list, (n_files + 1) * sizeof (char *));
xfree (fn_list);
}
else if (n_files)
{
/* If we only have file names as possible completion, we should
bring them in sync with what rl_complete expects. The
problem is that if the user types "break /foo/b TAB", and the
possible completions are "/foo/bar" and "/foo/baz"
rl_complete expects us to return "bar" and "baz", without the
leading directories, as possible completions, because `word'
starts at the "b". But we ignore the value of `word' when we
call make_source_files_completion_list above (because that
would not DTRT when the completion results in both symbols
and file names), so make_source_files_completion_list returns
the full "/foo/bar" and "/foo/baz" strings. This produces
wrong results when, e.g., there's only one possible
completion, because rl_complete will prepend "/foo/" to each
candidate completion. The loop below removes that leading
part. */
for (n_files = 0; fn_list[n_files]; n_files++)
{
memmove (fn_list[n_files], fn_list[n_files] + (word - text),
strlen (fn_list[n_files]) + 1 - (word - text));
}
/* Return just the file-name list as the result. */
list = fn_list;
}
else if (!n_syms)
{
/* No completions at all. As the final resort, try completing
on the entire text as a symbol. */
list = make_symbol_completion_list (orig_text, word);
}
return list;
}
/* Here are some useful test cases for completion. FIXME: These should /* Here are some useful test cases for completion. FIXME: These should
be put in the test suite. They should be tested with both M-? and TAB. be put in the test suite. They should be tested with both M-? and TAB.
@ -362,7 +513,7 @@ line_completion_function (char *text, int matches, char *line_buffer, int point)
to complete the entire text after the to complete the entire text after the
command, just the last word. To this command, just the last word. To this
end, we need to find the beginning of the end, we need to find the beginning of the
file name starting at `word' and going file name by starting at `word' and going
backwards. */ backwards. */
for (p = word; for (p = word;
p > tmp_command p > tmp_command
@ -372,6 +523,16 @@ line_completion_function (char *text, int matches, char *line_buffer, int point)
rl_completer_word_break_characters = rl_completer_word_break_characters =
gdb_completer_file_name_break_characters; gdb_completer_file_name_break_characters;
} }
else if (c->completer == location_completer)
{
/* Commands which complete on locations want to
see the entire argument. */
for (p = word;
p > tmp_command
&& p[-1] != ' ' && p[-1] != '\t';
p--)
;
}
list = (*c->completer) (p, word); list = (*c->completer) (p, word);
} }
} }
@ -430,6 +591,14 @@ line_completion_function (char *text, int matches, char *line_buffer, int point)
rl_completer_word_break_characters = rl_completer_word_break_characters =
gdb_completer_file_name_break_characters; gdb_completer_file_name_break_characters;
} }
else if (c->completer == location_completer)
{
for (p = word;
p > tmp_command
&& p[-1] != ' ' && p[-1] != '\t';
p--)
;
}
list = (*c->completer) (p, word); list = (*c->completer) (p, word);
} }
} }

View file

@ -23,6 +23,8 @@ extern char *line_completion_function (char *, int, char *, int);
extern char **filename_completer (char *, char *); extern char **filename_completer (char *, char *);
extern char **location_completer (char *, char *);
extern char *get_gdb_completer_word_break_characters (void); extern char *get_gdb_completer_word_break_characters (void);
extern char *get_gdb_completer_quote_characters (void); extern char *get_gdb_completer_quote_characters (void);

View file

@ -36,6 +36,7 @@
#include "language.h" #include "language.h"
#include "symfile.h" #include "symfile.h"
#include "objfiles.h" #include "objfiles.h"
#include "completer.h"
#ifdef UI_OUT #ifdef UI_OUT
#include "ui-out.h" #include "ui-out.h"
#endif #endif
@ -1794,8 +1795,8 @@ _initialize_infcmd (void)
{ {
struct cmd_list_element *c; struct cmd_list_element *c;
c= add_com ("tty", class_run, tty_command, c = add_com ("tty", class_run, tty_command,
"Set terminal for future runs of program being debugged."); "Set terminal for future runs of program being debugged.");
c->completer = filename_completer; c->completer = filename_completer;
c = add_set_cmd ("args", class_run, var_string_noescape, c = add_set_cmd ("args", class_run, var_string_noescape,
@ -1899,25 +1900,30 @@ Argument N means do this N times (or till program stops for another reason).");
Argument N means do this N times (or till program stops for another reason)."); Argument N means do this N times (or till program stops for another reason).");
add_com_alias ("s", "step", class_run, 1); add_com_alias ("s", "step", class_run, 1);
add_com ("until", class_run, until_command, c = add_com ("until", class_run, until_command,
"Execute until the program reaches a source line greater than the current\n\ "Execute until the program reaches a source line greater than the current\n\
or a specified line or address or function (same args as break command).\n\ or a specified line or address or function (same args as break command).\n\
Execution will also stop upon exit from the current stack frame."); Execution will also stop upon exit from the current stack frame.");
c->completer = location_completer;
add_com_alias ("u", "until", class_run, 1); add_com_alias ("u", "until", class_run, 1);
add_com ("jump", class_run, jump_command, c = add_com ("jump", class_run, jump_command,
"Continue program being debugged at specified line or address.\n\ "Continue program being debugged at specified line or address.\n\
Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
for an address to start at."); for an address to start at.");
c->completer = location_completer;
if (xdb_commands) if (xdb_commands)
add_com ("go", class_run, go_command, {
"Usage: go <location>\n\ c = add_com ("go", class_run, go_command,
"Usage: go <location>\n\
Continue program being debugged, stopping at specified line or \n\ Continue program being debugged, stopping at specified line or \n\
address.\n\ address.\n\
Give as argument either LINENUM or *ADDR, where ADDR is an \n\ Give as argument either LINENUM or *ADDR, where ADDR is an \n\
expression for an address to start at.\n\ expression for an address to start at.\n\
This command is a combination of tbreak and jump."); This command is a combination of tbreak and jump.");
c->completer = location_completer;
}
if (xdb_commands) if (xdb_commands)
add_com_alias ("g", "go", class_run, 1); add_com_alias ("g", "go", class_run, 1);

View file

@ -37,6 +37,7 @@
#include "annotate.h" #include "annotate.h"
#include "symfile.h" /* for overlay functions */ #include "symfile.h" /* for overlay functions */
#include "objfiles.h" /* ditto */ #include "objfiles.h" /* ditto */
#include "completer.h" /* for completion functions */
#ifdef UI_OUT #ifdef UI_OUT
#include "ui-out.h" #include "ui-out.h"
#endif #endif
@ -2451,6 +2452,8 @@ print_insn (CORE_ADDR memaddr, struct ui_file *stream)
void void
_initialize_printcmd (void) _initialize_printcmd (void)
{ {
struct cmd_list_element *c;
current_display_number = -1; current_display_number = -1;
add_info ("address", address_info, add_info ("address", address_info,
@ -2473,11 +2476,12 @@ Defaults for format and size letters are those previously used.\n\
Default count is 1. Default address is following last thing printed\n\ Default count is 1. Default address is following last thing printed\n\
with this command or \"print\".", NULL)); with this command or \"print\".", NULL));
add_com ("disassemble", class_vars, disassemble_command, c = add_com ("disassemble", class_vars, disassemble_command,
"Disassemble a specified section of memory.\n\ "Disassemble a specified section of memory.\n\
Default is the function surrounding the pc of the selected frame.\n\ Default is the function surrounding the pc of the selected frame.\n\
With a single argument, the function surrounding that address is dumped.\n\ With a single argument, the function surrounding that address is dumped.\n\
Two arguments are taken as a range of memory to dump."); Two arguments are taken as a range of memory to dump.");
c->completer = location_completer;
if (xdb_commands) if (xdb_commands)
add_com_alias ("va", "disassemble", class_xdb, 0); add_com_alias ("va", "disassemble", class_xdb, 0);
@ -2555,11 +2559,12 @@ variable in the program being debugged. EXP is any valid expression.\n",
You can see these environment settings with the \"show\" command.", NULL)); You can see these environment settings with the \"show\" command.", NULL));
/* "call" is the same as "set", but handy for dbx users to call fns. */ /* "call" is the same as "set", but handy for dbx users to call fns. */
add_com ("call", class_vars, call_command, c = add_com ("call", class_vars, call_command,
"Call a function in the program.\n\ "Call a function in the program.\n\
The argument is the function name and arguments, in the notation of the\n\ The argument is the function name and arguments, in the notation of the\n\
current working language. The result is printed and saved in the value\n\ current working language. The result is printed and saved in the value\n\
history, if it is not void."); history, if it is not void.");
c->completer = location_completer;
add_cmd ("variable", class_vars, set_command, add_cmd ("variable", class_vars, set_command,
"Evaluate expression EXP and assign result to variable VAR, using assignment\n\ "Evaluate expression EXP and assign result to variable VAR, using assignment\n\
@ -2570,7 +2575,7 @@ variable in the program being debugged. EXP is any valid expression.\n\
This may usually be abbreviated to simply \"set\".", This may usually be abbreviated to simply \"set\".",
&setlist); &setlist);
add_com ("print", class_vars, print_command, c = add_com ("print", class_vars, print_command,
concat ("Print value of expression EXP.\n\ concat ("Print value of expression EXP.\n\
Variables accessible are those of the lexical environment of the selected\n\ Variables accessible are those of the lexical environment of the selected\n\
stack frame, plus all those whose scope is global or an entire file.\n\ stack frame, plus all those whose scope is global or an entire file.\n\
@ -2592,11 +2597,13 @@ resides in memory.\n",
"\n\ "\n\
EXP may be preceded with /FMT, where FMT is a format letter\n\ EXP may be preceded with /FMT, where FMT is a format letter\n\
but no count or size letter (see \"x\" command).", NULL)); but no count or size letter (see \"x\" command).", NULL));
c->completer = location_completer;
add_com_alias ("p", "print", class_vars, 1); add_com_alias ("p", "print", class_vars, 1);
add_com ("inspect", class_vars, inspect_command, c = add_com ("inspect", class_vars, inspect_command,
"Same as \"print\" command, except that if you are running in the epoch\n\ "Same as \"print\" command, except that if you are running in the epoch\n\
environment, the value is printed in its own window."); environment, the value is printed in its own window.");
c->completer = location_completer;
add_show_from_set ( add_show_from_set (
add_set_cmd ("max-symbolic-offset", no_class, var_uinteger, add_set_cmd ("max-symbolic-offset", no_class, var_uinteger,

View file

@ -2153,50 +2153,72 @@ operator_chars (char *p, char **end)
} }
/* Slave routine for sources_info. Force line breaks at ,'s. /* If FILE is not already in the table of files, return zero;
NAME is the name to print and *FIRST is nonzero if this is the first otherwise return non-zero. Optionally add FILE to the table if ADD
name printed. Set *FIRST to zero. */ is non-zero. If *FIRST is non-zero, forget the old table
static void contents. */
output_source_filename (char *name, int *first) static int
filename_seen (const char *file, int add, int *first)
{ {
/* Table of files printed so far. Since a single source file can /* Table of files seen so far. */
result in several partial symbol tables, we need to avoid printing static const char **tab = NULL;
it more than once. Note: if some of the psymtabs are read in and
some are not, it gets printed both under "Source files for which
symbols have been read" and "Source files for which symbols will
be read in on demand". I consider this a reasonable way to deal
with the situation. I'm not sure whether this can also happen for
symtabs; it doesn't hurt to check. */
static char **tab = NULL;
/* Allocated size of tab in elements. /* Allocated size of tab in elements.
Start with one 256-byte block (when using GNU malloc.c). Start with one 256-byte block (when using GNU malloc.c).
24 is the malloc overhead when range checking is in effect. */ 24 is the malloc overhead when range checking is in effect. */
static int tab_alloc_size = (256 - 24) / sizeof (char *); static int tab_alloc_size = (256 - 24) / sizeof (char *);
/* Current size of tab in elements. */ /* Current size of tab in elements. */
static int tab_cur_size; static int tab_cur_size;
const char **p;
char **p;
if (*first) if (*first)
{ {
if (tab == NULL) if (tab == NULL)
tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab)); tab = (const char **) xmalloc (tab_alloc_size * sizeof (*tab));
tab_cur_size = 0; tab_cur_size = 0;
} }
/* Is NAME in tab? */ /* Is FILE in tab? */
for (p = tab; p < tab + tab_cur_size; p++) for (p = tab; p < tab + tab_cur_size; p++)
if (STREQ (*p, name)) if (strcmp (*p, file) == 0)
return 1;
/* No; maybe add it to tab. */
if (add)
{
if (tab_cur_size == tab_alloc_size)
{
tab_alloc_size *= 2;
tab = (const char **) xrealloc ((char *) tab,
tab_alloc_size * sizeof (*tab));
}
tab[tab_cur_size++] = file;
}
return 0;
}
/* Slave routine for sources_info. Force line breaks at ,'s.
NAME is the name to print and *FIRST is nonzero if this is the first
name printed. Set *FIRST to zero. */
static void
output_source_filename (char *name, int *first)
{
/* Since a single source file can result in several partial symbol
tables, we need to avoid printing it more than once. Note: if
some of the psymtabs are read in and some are not, it gets
printed both under "Source files for which symbols have been
read" and "Source files for which symbols will be read in on
demand". I consider this a reasonable way to deal with the
situation. I'm not sure whether this can also happen for
symtabs; it doesn't hurt to check. */
/* Was NAME already seen? */
if (filename_seen (name, 1, first))
{
/* Yes; don't print it again. */ /* Yes; don't print it again. */
return; return;
/* No; add it to tab. */
if (tab_cur_size == tab_alloc_size)
{
tab_alloc_size *= 2;
tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab));
} }
tab[tab_cur_size++] = name; /* No; print it and reset *FIRST. */
if (*first) if (*first)
{ {
*first = 0; *first = 0;
@ -2871,9 +2893,9 @@ completion_list_add_name (char *symname, char *sym_text, int sym_text_len,
} }
} }
/* Return a NULL terminated array of all symbols (regardless of class) which /* Return a NULL terminated array of all symbols (regardless of class)
begin by matching TEXT. If the answer is no symbols, then the return value which begin by matching TEXT. If the answer is no symbols, then
is an array which contains only a NULL pointer. the return value is an array which contains only a NULL pointer.
Problem: All of the symbols have to be copied because readline frees them. Problem: All of the symbols have to be copied because readline frees them.
I'm not going to worry about this; hopefully there won't be that many. */ I'm not going to worry about this; hopefully there won't be that many. */
@ -2927,7 +2949,11 @@ make_symbol_completion_list (char *text, char *word)
else if (quote_found == '"') else if (quote_found == '"')
/* A double-quoted string is never a symbol, nor does it make sense /* A double-quoted string is never a symbol, nor does it make sense
to complete it any other way. */ to complete it any other way. */
return NULL; {
return_val = (char **) xmalloc (sizeof (char *));
return_val[0] = NULL;
return return_val;
}
else else
{ {
/* It is not a quoted string. Break it based on the characters /* It is not a quoted string. Break it based on the characters
@ -3059,6 +3085,277 @@ make_symbol_completion_list (char *text, char *word)
return (return_val); return (return_val);
} }
/* Like make_symbol_completion_list, but returns a list of symbols
defined in a source file FILE. */
char **
make_file_symbol_completion_list (char *text, char *word, char *srcfile)
{
register struct symbol *sym;
register struct symtab *s;
register struct block *b;
register int i;
/* The symbol we are completing on. Points in same buffer as text. */
char *sym_text;
/* Length of sym_text. */
int sym_text_len;
/* Now look for the symbol we are supposed to complete on.
FIXME: This should be language-specific. */
{
char *p;
char quote_found;
char *quote_pos = NULL;
/* First see if this is a quoted string. */
quote_found = '\0';
for (p = text; *p != '\0'; ++p)
{
if (quote_found != '\0')
{
if (*p == quote_found)
/* Found close quote. */
quote_found = '\0';
else if (*p == '\\' && p[1] == quote_found)
/* A backslash followed by the quote character
doesn't end the string. */
++p;
}
else if (*p == '\'' || *p == '"')
{
quote_found = *p;
quote_pos = p;
}
}
if (quote_found == '\'')
/* A string within single quotes can be a symbol, so complete on it. */
sym_text = quote_pos + 1;
else if (quote_found == '"')
/* A double-quoted string is never a symbol, nor does it make sense
to complete it any other way. */
{
return_val = (char **) xmalloc (sizeof (char *));
return_val[0] = NULL;
return return_val;
}
else
{
/* It is not a quoted string. Break it based on the characters
which are in symbols. */
while (p > text)
{
if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
--p;
else
break;
}
sym_text = p;
}
}
sym_text_len = strlen (sym_text);
return_val_size = 10;
return_val_index = 0;
return_val = (char **) xmalloc ((return_val_size + 1) * sizeof (char *));
return_val[0] = NULL;
/* Find the symtab for SRCFILE (this loads it if it was not yet read
in). */
s = lookup_symtab (srcfile);
if (s == NULL)
{
/* Maybe they typed the file with leading directories, while the
symbol tables record only its basename. */
char *tail = basename (srcfile);
if (tail > srcfile)
s = lookup_symtab (tail);
}
/* If we have no symtab for that file, return an empty list. */
if (s == NULL)
return (return_val);
/* Go through this symtab and check the externs and statics for
symbols which match. */
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
for (i = 0; i < BLOCK_NSYMS (b); i++)
{
sym = BLOCK_SYM (b, i);
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
}
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
for (i = 0; i < BLOCK_NSYMS (b); i++)
{
sym = BLOCK_SYM (b, i);
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
}
return (return_val);
}
/* A helper function for make_source_files_completion_list. It adds
another file name to a list of possible completions, growing the
list as necessary. */
static void
add_filename_to_list (const char *fname, char *text, char *word,
char ***list, int *list_used, int *list_alloced)
{
char *new;
size_t fnlen = strlen (fname);
if (*list_used + 1 >= *list_alloced)
{
*list_alloced *= 2;
*list = (char **) xrealloc ((char *) *list,
*list_alloced * sizeof (char *));
}
if (word == text)
{
/* Return exactly fname. */
new = xmalloc (fnlen + 5);
strcpy (new, fname);
}
else if (word > text)
{
/* Return some portion of fname. */
new = xmalloc (fnlen + 5);
strcpy (new, fname + (word - text));
}
else
{
/* Return some of TEXT plus fname. */
new = xmalloc (fnlen + (text - word) + 5);
strncpy (new, word, text - word);
new[text - word] = '\0';
strcat (new, fname);
}
(*list)[*list_used] = new;
(*list)[++*list_used] = NULL;
}
static int
not_interesting_fname (const char *fname)
{
static const char *illegal_aliens[] = {
"_globals_", /* inserted by coff_symtab_read */
NULL
};
int i;
for (i = 0; illegal_aliens[i]; i++)
{
if (strcmp (fname, illegal_aliens[i]) == 0)
return 1;
}
return 0;
}
/* Return a NULL terminated array of all source files whose names
begin with matching TEXT. The file names are looked up in the
symbol tables of this program. If the answer is no matchess, then
the return value is an array which contains only a NULL pointer. */
char **
make_source_files_completion_list (char *text, char *word)
{
register struct symtab *s;
register struct partial_symtab *ps;
register struct objfile *objfile;
int first = 1;
int list_alloced = 1;
int list_used = 0;
size_t text_len = strlen (text);
char **list = (char **) xmalloc (list_alloced * sizeof (char *));
char *base_name;
list[0] = NULL;
if (!have_full_symbols () && !have_partial_symbols ())
return list;
ALL_SYMTABS (objfile, s)
{
if (not_interesting_fname (s->filename))
continue;
if (!filename_seen (s->filename, 1, &first)
#if HAVE_DOS_BASED_FILE_SYSTEM
&& strncasecmp (s->filename, text, text_len) == 0
#else
&& strncmp (s->filename, text, text_len) == 0
#endif
)
{
/* This file matches for a completion; add it to the current
list of matches. */
add_filename_to_list (s->filename, text, word,
&list, &list_used, &list_alloced);
}
else
{
/* NOTE: We allow the user to type a base name when the
debug info records leading directories, but not the other
way around. This is what subroutines of breakpoint
command do when they parse file names. */
base_name = basename (s->filename);
if (base_name != s->filename
&& !filename_seen (base_name, 1, &first)
#if HAVE_DOS_BASED_FILE_SYSTEM
&& strncasecmp (base_name, text, text_len) == 0
#else
&& strncmp (base_name, text, text_len) == 0
#endif
)
add_filename_to_list (base_name, text, word,
&list, &list_used, &list_alloced);
}
}
ALL_PSYMTABS (objfile, ps)
{
if (not_interesting_fname (ps->filename))
continue;
if (!ps->readin)
{
if (!filename_seen (ps->filename, 1, &first)
#if HAVE_DOS_BASED_FILE_SYSTEM
&& strncasecmp (ps->filename, text, text_len) == 0
#else
&& strncmp (ps->filename, text, text_len) == 0
#endif
)
{
/* This file matches for a completion; add it to the
current list of matches. */
add_filename_to_list (ps->filename, text, word,
&list, &list_used, &list_alloced);
}
else
{
base_name = basename (ps->filename);
if (base_name != ps->filename
&& !filename_seen (base_name, 1, &first)
#if HAVE_DOS_BASED_FILE_SYSTEM
&& strncasecmp (base_name, text, text_len) == 0
#else
&& strncmp (base_name, text, text_len) == 0
#endif
)
add_filename_to_list (base_name, text, word,
&list, &list_used, &list_alloced);
}
}
}
return list;
}
/* Determine if PC is in the prologue of a function. The prologue is the area /* Determine if PC is in the prologue of a function. The prologue is the area
between the first instruction of a function, and the first executable line. between the first instruction of a function, and the first executable line.
Returns 1 if PC *might* be in prologue, 0 if definately *not* in prologue. Returns 1 if PC *might* be in prologue, 0 if definately *not* in prologue.

View file

@ -1359,8 +1359,12 @@ extern void select_source_symtab (struct symtab *);
extern char **make_symbol_completion_list (char *, char *); extern char **make_symbol_completion_list (char *, char *);
extern char **make_file_symbol_completion_list (char *, char *, char *);
extern struct symbol **make_symbol_overload_list (struct symbol *); extern struct symbol **make_symbol_overload_list (struct symbol *);
extern char **make_source_files_completion_list (char *, char *);
/* symtab.c */ /* symtab.c */
extern struct partial_symtab *find_main_psymtab (void); extern struct partial_symtab *find_main_psymtab (void);

View file

@ -33,6 +33,7 @@
#include "remote.h" #include "remote.h"
#include "linespec.h" #include "linespec.h"
#include "regcache.h" #include "regcache.h"
#include "completer.h"
#include "gdb-events.h" #include "gdb-events.h"
#include "ax.h" #include "ax.h"
@ -2799,12 +2800,13 @@ Arguments are tracepoint numbers, separated by spaces.\n\
No argument means enable all tracepoints.", No argument means enable all tracepoints.",
&enablelist); &enablelist);
add_com ("trace", class_trace, trace_command, c = add_com ("trace", class_trace, trace_command,
"Set a tracepoint at a specified line or function or address.\n\ "Set a tracepoint at a specified line or function or address.\n\
Argument may be a line number, function name, or '*' plus an address.\n\ Argument may be a line number, function name, or '*' plus an address.\n\
For a line number or function, trace at the start of its code.\n\ For a line number or function, trace at the start of its code.\n\
If an address is specified, trace at that exact address.\n\n\ If an address is specified, trace at that exact address.\n\n\
Do \"help tracepoints\" for info on other tracepoint commands."); Do \"help tracepoints\" for info on other tracepoint commands.");
c->completer = location_completer;
add_com_alias ("tp", "trace", class_alias, 0); add_com_alias ("tp", "trace", class_alias, 0);
add_com_alias ("tr", "trace", class_alias, 1); add_com_alias ("tr", "trace", class_alias, 1);