From c94fdfd0a8821bf0bfa3518f5f65b58f1aa629c2 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 11 Jun 2001 16:05:25 +0000 Subject: [PATCH] * 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". --- gdb/ChangeLog | 43 ++++++ gdb/breakpoint.c | 43 +++--- gdb/completer.c | 177 ++++++++++++++++++++++- gdb/completer.h | 2 + gdb/infcmd.c | 22 +-- gdb/printcmd.c | 19 ++- gdb/symtab.c | 357 +++++++++++++++++++++++++++++++++++++++++++---- gdb/symtab.h | 4 + gdb/tracepoint.c | 6 +- 9 files changed, 607 insertions(+), 66 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 748c522b2f4..166b3f6f332 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,46 @@ +2001-06-11 Eli Zaretskii + + * 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 * gnu-regex.c: Eliminate obsolete check for _MSC_VER. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 01d47e28788..6824e388ac4 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -40,6 +40,7 @@ #include "symfile.h" #include "objfiles.h" #include "linespec.h" +#include "completer.h" #ifdef UI_OUT #include "ui-out.h" #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\ expression to be evaluated whenever breakpoint N is reached. "); - add_com ("tbreak", class_breakpoint, tbreak_command, - "Set a temporary breakpoint. Args like \"break\" command.\n\ + c = add_com ("tbreak", class_breakpoint, tbreak_command, + "Set a temporary breakpoint. Args like \"break\" command.\n\ Like \"break\" except the breakpoint is only temporary,\n\ so it will be deleted when hit. Equivalent to \"break\" followed\n\ by using \"enable delete\" on the breakpoint number."); - add_com ("txbreak", class_breakpoint, tbreak_at_finish_command, - "Set temporary breakpoint at procedure exit. Either there should\n\ + c->completer = location_completer; + + c = add_com ("txbreak", class_breakpoint, tbreak_at_finish_command, + "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; - add_com ("hbreak", class_breakpoint, hbreak_command, - "Set a hardware assisted breakpoint. Args like \"break\" command.\n\ + 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\ some target hardware may not have this support."); + c->completer = location_completer; - add_com ("thbreak", class_breakpoint, thbreak_command, - "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\ + c = add_com ("thbreak", class_breakpoint, thbreak_command, + "Set a temporary hardware assisted breakpoint. Args like \"break\" command.\n\ Like \"hbreak\" except the breakpoint is only temporary,\n\ so it will be deleted when hit."); + c->completer = location_completer; add_prefix_cmd ("enable", class_breakpoint, enable_command, "Enable some breakpoints.\n\ @@ -7701,8 +7707,8 @@ is executing in.\n\ \n\ See also the \"delete\" command which clears breakpoints by number.", NULL)); - add_com ("break", class_breakpoint, break_command, - concat ("Set breakpoint at specified line or function.\n\ + c = add_com ("break", class_breakpoint, break_command, + concat ("Set breakpoint at specified line or function.\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 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\ \n\ 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 ("br", "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\ by using \"enable delete\" on the catchpoint number."); - add_com ("watch", class_breakpoint, watch_command, - "Set a watchpoint for an expression.\n\ + c = add_com ("watch", class_breakpoint, watch_command, + "Set a watchpoint for an expression.\n\ A watchpoint stops execution of your program whenever the value of\n\ an expression changes."); + c->completer = location_completer; - add_com ("rwatch", class_breakpoint, rwatch_command, - "Set a read watchpoint for an expression.\n\ + c = add_com ("rwatch", class_breakpoint, rwatch_command, + "Set a read watchpoint for an expression.\n\ A watchpoint stops execution of your program whenever the value of\n\ an expression is read."); + c->completer = location_completer; - add_com ("awatch", class_breakpoint, awatch_command, - "Set a watchpoint for an expression.\n\ + c = add_com ("awatch", class_breakpoint, awatch_command, + "Set a watchpoint for an expression.\n\ A watchpoint stops execution of your program whenever the value of\n\ an expression is either read or written."); + c->completer = location_completer; add_info ("watchpoints", breakpoints_info, "Synonym for ``info breakpoints''."); diff --git a/gdb/completer.c b/gdb/completer.c index db16d1f9e80..19db617f9cd 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -22,12 +22,14 @@ #include "symtab.h" #include "gdbtypes.h" #include "expression.h" +#include "filenames.h" /* for DOSish file names */ /* FIXME: This is needed because of lookup_cmd_1(). We should be calling a hook instead so we eliminate the CLI dependency. */ #include "gdbcmd.h" -/* Needed for rl_completer_word_break_characters() */ +/* Needed for rl_completer_word_break_characters() and for + filename_completion_function. */ #include /* 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*|\"';:?><"; #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 can't include '"' because the gdb C parser treats such quoted sequences as strings. */ @@ -95,8 +101,6 @@ get_gdb_completer_quote_characters (void) char ** filename_completer (char *text, char *word) { - /* From readline. */ -extern char *filename_completion_function (char *, int); int subsequent_name; char **return_val; int return_val_used; @@ -170,6 +174,153 @@ extern char *filename_completion_function (char *, int); 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 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 command, just the last word. To this 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. */ for (p = word; p > tmp_command @@ -372,6 +523,16 @@ line_completion_function (char *text, int matches, char *line_buffer, int point) rl_completer_word_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); } } @@ -430,6 +591,14 @@ line_completion_function (char *text, int matches, char *line_buffer, int point) rl_completer_word_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); } } diff --git a/gdb/completer.h b/gdb/completer.h index abb3b8c8a4a..ae27395a2b8 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -23,6 +23,8 @@ extern char *line_completion_function (char *, int, char *, int); 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_quote_characters (void); diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 0831d7c27d2..3f8572ed323 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -36,6 +36,7 @@ #include "language.h" #include "symfile.h" #include "objfiles.h" +#include "completer.h" #ifdef UI_OUT #include "ui-out.h" #endif @@ -1794,8 +1795,8 @@ _initialize_infcmd (void) { struct cmd_list_element *c; - c= add_com ("tty", class_run, tty_command, - "Set terminal for future runs of program being debugged."); + c = add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); c->completer = filename_completer; 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)."); add_com_alias ("s", "step", class_run, 1); - add_com ("until", class_run, until_command, - "Execute until the program reaches a source line greater than the current\n\ + c = add_com ("until", class_run, until_command, + "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\ 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 ("jump", class_run, jump_command, - "Continue program being debugged at specified line or address.\n\ + c = add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ for an address to start at."); + c->completer = location_completer; if (xdb_commands) - add_com ("go", class_run, go_command, - "Usage: go \n\ + { + c = add_com ("go", class_run, go_command, + "Usage: go \n\ Continue program being debugged, stopping at specified line or \n\ address.\n\ Give as argument either LINENUM or *ADDR, where ADDR is an \n\ expression for an address to start at.\n\ This command is a combination of tbreak and jump."); + c->completer = location_completer; + } if (xdb_commands) add_com_alias ("g", "go", class_run, 1); diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 66dc512df67..746a0646cc0 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -37,6 +37,7 @@ #include "annotate.h" #include "symfile.h" /* for overlay functions */ #include "objfiles.h" /* ditto */ +#include "completer.h" /* for completion functions */ #ifdef UI_OUT #include "ui-out.h" #endif @@ -2451,6 +2452,8 @@ print_insn (CORE_ADDR memaddr, struct ui_file *stream) void _initialize_printcmd (void) { + struct cmd_list_element *c; + current_display_number = -1; 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\ with this command or \"print\".", NULL)); - add_com ("disassemble", class_vars, disassemble_command, - "Disassemble a specified section of memory.\n\ + c = add_com ("disassemble", class_vars, disassemble_command, + "Disassemble a specified section of memory.\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\ Two arguments are taken as a range of memory to dump."); + c->completer = location_completer; if (xdb_commands) 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)); /* "call" is the same as "set", but handy for dbx users to call fns. */ - add_com ("call", class_vars, call_command, - "Call a function in the program.\n\ + c = add_com ("call", class_vars, call_command, + "Call a function in the program.\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\ history, if it is not void."); + c->completer = location_completer; add_cmd ("variable", class_vars, set_command, "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\".", &setlist); - add_com ("print", class_vars, print_command, + c = add_com ("print", class_vars, print_command, concat ("Print value of expression EXP.\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\ @@ -2592,11 +2597,13 @@ resides in memory.\n", "\n\ EXP may be preceded with /FMT, where FMT is a format letter\n\ but no count or size letter (see \"x\" command).", NULL)); + c->completer = location_completer; 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\ environment, the value is printed in its own window."); + c->completer = location_completer; add_show_from_set ( add_set_cmd ("max-symbolic-offset", no_class, var_uinteger, diff --git a/gdb/symtab.c b/gdb/symtab.c index 108ace764d6..3b3bb54727d 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2153,50 +2153,72 @@ operator_chars (char *p, char **end) } -/* 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) +/* If FILE is not already in the table of files, return zero; + otherwise return non-zero. Optionally add FILE to the table if ADD + is non-zero. If *FIRST is non-zero, forget the old table + contents. */ +static int +filename_seen (const char *file, int add, int *first) { - /* Table of files printed so far. 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. */ - static char **tab = NULL; + /* Table of files seen so far. */ + static const char **tab = NULL; /* Allocated size of tab in elements. Start with one 256-byte block (when using GNU malloc.c). 24 is the malloc overhead when range checking is in effect. */ static int tab_alloc_size = (256 - 24) / sizeof (char *); /* Current size of tab in elements. */ static int tab_cur_size; - - char **p; + const char **p; if (*first) { if (tab == NULL) - tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab)); + tab = (const char **) xmalloc (tab_alloc_size * sizeof (*tab)); tab_cur_size = 0; } - /* Is NAME in tab? */ + /* Is FILE in tab? */ for (p = tab; p < tab + tab_cur_size; p++) - if (STREQ (*p, name)) - /* Yes; don't print it again. */ - return; - /* No; add it to tab. */ - if (tab_cur_size == tab_alloc_size) + if (strcmp (*p, file) == 0) + return 1; + + /* No; maybe add it to tab. */ + if (add) { - tab_alloc_size *= 2; - tab = (char **) xrealloc ((char *) tab, tab_alloc_size * sizeof (*tab)); + 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; } - tab[tab_cur_size++] = name; + 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. */ + return; + } + /* No; print it and reset *FIRST. */ if (*first) { *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 - begin by matching TEXT. If the answer is no symbols, then the return value - is an array which contains only a NULL pointer. +/* Return a NULL terminated array of all symbols (regardless of class) + which begin by matching TEXT. If the answer is no symbols, then + 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. 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 == '"') /* A double-quoted string is never a symbol, nor does it make sense to complete it any other way. */ - return NULL; + { + 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 @@ -3059,6 +3085,277 @@ make_symbol_completion_list (char *text, char *word) 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 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. diff --git a/gdb/symtab.h b/gdb/symtab.h index bbde658f091..f76062806df 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1359,8 +1359,12 @@ extern void select_source_symtab (struct symtab *); 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 char **make_source_files_completion_list (char *, char *); + /* symtab.c */ extern struct partial_symtab *find_main_psymtab (void); diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index a5027c79d37..9a83322f823 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -33,6 +33,7 @@ #include "remote.h" #include "linespec.h" #include "regcache.h" +#include "completer.h" #include "gdb-events.h" #include "ax.h" @@ -2799,12 +2800,13 @@ Arguments are tracepoint numbers, separated by spaces.\n\ No argument means enable all tracepoints.", &enablelist); - add_com ("trace", class_trace, trace_command, - "Set a tracepoint at a specified line or function or address.\n\ + c = add_com ("trace", class_trace, trace_command, + "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\ 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\ Do \"help tracepoints\" for info on other tracepoint commands."); + c->completer = location_completer; add_com_alias ("tp", "trace", class_alias, 0); add_com_alias ("tr", "trace", class_alias, 1); -- 2.30.2