PR gdb/17960 - Move completion_tracker_t into the completion API.
Commit Message
The bug itself is easily demonstrated:
$ gdb -nx -q gdb
(gdb) b gdb.c:ma<TAB>
./../src/gdb/completer.c:837: internal-error: maybe_add_completion:
Assertion `tracker != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
This occurs because the code path in this case is:
complete_line
- complete_line_internal
-- location_completer
--- make_file_symbol_completion_list
(...)
---- completion_list_add_name
----- maybe_add_completion
----> gdb_assert (tracker != NULL);
The tracker in maybe_add_completion is a static global in symtab.c called
completion_tracker. It is initialized by
default_make_symbol_completion_list_break_on_1 (which is a defaulted
language vector method). In this case, this function is never called
and completion_tracker is left NULL/uninitialized.
This patch refactors the completion API, adding a completion_tracker_t
to the list of function arguments for all completion functions, removing
the (file) global completion_tracker in symtab.c that is the cause of this bug.
gdb/ChangeLog
PR gdb/17960
* cli/cli-decode.c (find_cmd): Use maybe_add_completion to
implement completion tracking.
* command.h (completer_ftype, completer_ftype_void,
set_cmd_completer, set_cmd_completer_handle_brkchars,
lookup_cmd, lookup_cmd_1, complete_on_cmdlist,
complete_on_enum): Move to completer.h.
* completer.c (location_completer): Use TRY_CATCH to catch
max completion exception from make_file_symbol_completion_list,
make_symbol_completion_list, and make_source_files_completion_list.
(complete_line_internal): Empty the tracker when a unique
command completion is found.
(complete_line): Instantiate a new tracker earlier and pass this
to complete_line_internal.
If the list of completions is bigger than those tracked,
completion tracking was not implemented for the requested completion;
re-filter the list for maximum completions. Otherwise simply
copy the result.
* completer.h (max_completions, new_completion_tracker,
make_cleanup_free_completion_tracker, enum maybe_add_completion_enum,
maybe_add_completion, throw_max_completions_reached_error): Move
declarations to earlier in file.
(completer_ftype, completer_ftype_void, set_cmd_completer,
set_cmd_completer_handle_brkchars, lookup_cmd, lookup_cmd_1,
complete_on_cmdlist, complete_on_enum): Move declarations here
from command.h.
* symtab.c (COMPLETION_LIST_ADD_SYMBOL,
MCOMPLETION_LIST_ADD_SYMBOL): Add `tracker' as first argument.
All users updated.
(struct add_name_data): Add `tracker' member.
(default_make_symbol_completion_list_break_on_1): Add tracker
to call data.
Do not instantiate a completion tracker here -- use the one
passed instead.
(add_filename_to_list): Implement completion tracking.
(struct add_partial_filename_data): Add `tracker' member.
(make_source_files_completion_list): Add tracker to call data.
* symtab.h: Include completer.h.
* ada-lang.c, breakpoint.c, cli/cli-cmds.c, cli/cli-decode.h,
corefile.c, cp-abi.c, f-lang.c, infrun.c, interps.c, language.h,
python/py-cmd.c, top.c, symtab.c: Updated for completion API change.
gdb/testsuite/ChangeLog
PR gdb/17960
* gdb.base/completion.exp: Add location completer tests.
---
gdb/ada-lang.c | 3 -
gdb/breakpoint.c | 6 +
gdb/cli/cli-cmds.c | 6 +
gdb/cli/cli-decode.c | 58 ++++++++---
gdb/cli/cli-decode.h | 1
gdb/command.h | 31 ------
gdb/completer.c | 177 +++++++++++++++++++++++----------
gdb/completer.h | 168 +++++++++++++++++++------------
gdb/corefile.c | 3 -
gdb/cp-abi.c | 3 -
gdb/f-lang.c | 6 +
gdb/infrun.c | 5 +
gdb/interps.c | 1
gdb/language.h | 3 -
gdb/python/py-cmd.c | 5 +
gdb/symtab.c | 166 ++++++++++++++++++-------------
gdb/symtab.h | 35 +++----
gdb/testsuite/gdb.base/completion.exp | 78 +++++++++++++++
gdb/top.c | 2
19 files changed, 492 insertions(+), 265 deletions(-)
Comments
Keith Seitz <keiths@redhat.com> writes:
> The bug itself is easily demonstrated:
>
> $ gdb -nx -q gdb
> (gdb) b gdb.c:ma<TAB>
> ./../src/gdb/completer.c:837: internal-error: maybe_add_completion:
> Assertion `tracker != NULL' failed.
> A problem internal to GDB has been detected,
> further debugging may prove unreliable.
> Quit this debugging session? (y or n)
Yeah.
Just didn't think of this case. Bleah.
High level thought.
A good next step after this patch would be to replace the "tracker"
argument we now pass around with a more general completion state
struct pointer.
Then we could, I think, get rid of the "return_val" global in symtab.c.
I haven't worked through the details so there may be some gotchas.
This doesn't have to be done as part of this patch, but OTOH now's
a good time to do this.
Further comments are prefixed with ====.
>
> This occurs because the code path in this case is:
> complete_line
> - complete_line_internal
> -- location_completer
> --- make_file_symbol_completion_list
> (...)
> ---- completion_list_add_name
> ----- maybe_add_completion
> ----> gdb_assert (tracker != NULL);
>
> The tracker in maybe_add_completion is a static global in symtab.c called
> completion_tracker. It is initialized by
> default_make_symbol_completion_list_break_on_1 (which is a defaulted
> language vector method). In this case, this function is never called
> and completion_tracker is left NULL/uninitialized.
>
> This patch refactors the completion API, adding a completion_tracker_t
> to the list of function arguments for all completion functions, removing
> the (file) global completion_tracker in symtab.c that is the cause of this bug.
>
> gdb/ChangeLog
>
> PR gdb/17960
> * cli/cli-decode.c (find_cmd): Use maybe_add_completion to
> implement completion tracking.
> * command.h (completer_ftype, completer_ftype_void,
> set_cmd_completer, set_cmd_completer_handle_brkchars,
> lookup_cmd, lookup_cmd_1, complete_on_cmdlist,
> complete_on_enum): Move to completer.h.
> * completer.c (location_completer): Use TRY_CATCH to catch
> max completion exception from make_file_symbol_completion_list,
> make_symbol_completion_list, and make_source_files_completion_list.
> (complete_line_internal): Empty the tracker when a unique
> command completion is found.
> (complete_line): Instantiate a new tracker earlier and pass this
> to complete_line_internal.
> If the list of completions is bigger than those tracked,
> completion tracking was not implemented for the requested completion;
> re-filter the list for maximum completions. Otherwise simply
> copy the result.
> * completer.h (max_completions, new_completion_tracker,
> make_cleanup_free_completion_tracker, enum maybe_add_completion_enum,
> maybe_add_completion, throw_max_completions_reached_error): Move
> declarations to earlier in file.
> (completer_ftype, completer_ftype_void, set_cmd_completer,
> set_cmd_completer_handle_brkchars, lookup_cmd, lookup_cmd_1,
> complete_on_cmdlist, complete_on_enum): Move declarations here
> from command.h.
> * symtab.c (COMPLETION_LIST_ADD_SYMBOL,
> MCOMPLETION_LIST_ADD_SYMBOL): Add `tracker' as first argument.
> All users updated.
> (struct add_name_data): Add `tracker' member.
> (default_make_symbol_completion_list_break_on_1): Add tracker
> to call data.
> Do not instantiate a completion tracker here -- use the one
> passed instead.
> (add_filename_to_list): Implement completion tracking.
> (struct add_partial_filename_data): Add `tracker' member.
> (make_source_files_completion_list): Add tracker to call data.
> * symtab.h: Include completer.h.
> * ada-lang.c, breakpoint.c, cli/cli-cmds.c, cli/cli-decode.h,
> corefile.c, cp-abi.c, f-lang.c, infrun.c, interps.c, language.h,
> python/py-cmd.c, top.c, symtab.c: Updated for completion API change.
====
I've been told that regardless of the tediousness,
one line per file:
* ada-lang.c: Updated for completion API change.
* ... and so on.
You could instead just say "All callers updated."
at the relevant points.
>
> gdb/testsuite/ChangeLog
>
> PR gdb/17960
> * gdb.base/completion.exp: Add location completer tests.
> ---
> gdb/ada-lang.c | 3 -
> gdb/breakpoint.c | 6 +
> gdb/cli/cli-cmds.c | 6 +
> gdb/cli/cli-decode.c | 58 ++++++++---
> gdb/cli/cli-decode.h | 1
> gdb/command.h | 31 ------
> gdb/completer.c | 177 +++++++++++++++++++++++----------
> gdb/completer.h | 168 +++++++++++++++++++------------
> gdb/corefile.c | 3 -
> gdb/cp-abi.c | 3 -
> gdb/f-lang.c | 6 +
> gdb/infrun.c | 5 +
> gdb/interps.c | 1
> gdb/language.h | 3 -
> gdb/python/py-cmd.c | 5 +
> gdb/symtab.c | 166 ++++++++++++++++++-------------
> gdb/symtab.h | 35 +++----
> gdb/testsuite/gdb.base/completion.exp | 78 +++++++++++++++
> gdb/top.c | 2
> 19 files changed, 492 insertions(+), 265 deletions(-)
>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 562627a..161e3aa 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -6191,7 +6191,8 @@ ada_complete_symbol_matcher (const char *name, void *user_data)
> the entire command on which completion is made. */
>
> static VEC (char_ptr) *
> -ada_make_symbol_completion_list (const char *text0, const char *word,
> +ada_make_symbol_completion_list (completion_tracker_t tracker,
> + const char *text0, const char *word,
> enum type_code code)
> {
> char *text;
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index a7cc6cb..2773f53 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -1020,6 +1020,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
>
> static VEC (char_ptr) *
> condition_completer (struct cmd_list_element *cmd,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> const char *space;
> @@ -1058,7 +1059,7 @@ condition_completer (struct cmd_list_element *cmd,
>
> /* We're completing the expression part. */
> text = skip_spaces_const (space);
> - return expression_completer (cmd, text, word);
> + return expression_completer (cmd, tracker, text, word);
> }
>
> /* condition N EXP -- set break condition of breakpoint N to EXP. */
> @@ -15393,11 +15394,12 @@ catching_syscall_number (int syscall_number)
> /* Complete syscall names. Used by "catch syscall". */
> static VEC (char_ptr) *
> catch_syscall_completer (struct cmd_list_element *cmd,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> const char **list = get_syscall_names (get_current_arch ());
> VEC (char_ptr) *retlist
> - = (list == NULL) ? NULL : complete_on_enum (list, word, word);
> + = (list == NULL) ? NULL : complete_on_enum (tracker, list, word, word);
>
> xfree (list);
> return retlist;
> diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
> index e46f036..c2b4604 100644
> --- a/gdb/cli/cli-cmds.c
> +++ b/gdb/cli/cli-cmds.c
> @@ -1344,7 +1344,7 @@ valid_command_p (const char *command)
> {
> struct cmd_list_element *c;
>
> - c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
> + c = lookup_cmd_1 (NULL, &command, cmdlist, NULL, 1);
>
> if (c == NULL || c == (struct cmd_list_element *) -1)
> return FALSE;
> @@ -1467,12 +1467,12 @@ alias_command (char *args, int from_tty)
> alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
> command_prefix = dyn_string_buf (command_prefix_dyn_string);
>
> - c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
> + c_command = lookup_cmd_1 (NULL, &command_prefix, cmdlist, NULL, 1);
> /* We've already tried to look up COMMAND. */
> gdb_assert (c_command != NULL
> && c_command != (struct cmd_list_element *) -1);
> gdb_assert (c_command->prefixlist != NULL);
> - c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
> + c_alias = lookup_cmd_1 (NULL, &alias_prefix, cmdlist, NULL, 1);
> if (c_alias != c_command)
> error (_("ALIAS and COMMAND prefixes do not match."));
>
> diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
> index 4ec6ec0..b31772c 100644
> --- a/gdb/cli/cli-decode.c
> +++ b/gdb/cli/cli-decode.c
> @@ -35,7 +35,8 @@ static struct cmd_list_element *delete_cmd (const char *name,
> struct cmd_list_element **posthook,
> struct cmd_list_element **posthookee);
>
> -static struct cmd_list_element *find_cmd (const char *command,
> +static struct cmd_list_element *find_cmd (completion_tracker_t tracker,
> + const char *command,
> int len,
> struct cmd_list_element *clist,
> int ignore_help_classes,
> @@ -649,6 +650,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class class,
>
> static VEC (char_ptr) *
> integer_unlimited_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> static const char * const keywords[] =
> @@ -657,7 +659,7 @@ integer_unlimited_completer (struct cmd_list_element *ignore,
> NULL,
> };
>
> - return complete_on_enum (keywords, text, word);
> + return complete_on_enum (tracker, keywords, text, word);
> }
>
> /* Add element named NAME to both the set and show command LISTs (the
> @@ -1215,22 +1217,43 @@ help_cmd_list (struct cmd_list_element *list, enum command_class class,
> found in nfound. */
>
> static struct cmd_list_element *
> -find_cmd (const char *command, int len, struct cmd_list_element *clist,
> +find_cmd (completion_tracker_t tracker,
> + const char *command, int len, struct cmd_list_element *clist,
> int ignore_help_classes, int *nfound)
> {
> struct cmd_list_element *found, *c;
> + int max_reached;
>
> found = (struct cmd_list_element *) NULL;
> *nfound = 0;
> - for (c = clist; c; c = c->next)
> + for (c = clist, max_reached = 0; c; c = c->next)
> if (!strncmp (command, c->name, len)
> && (!ignore_help_classes || c->func))
> {
> - found = c;
> - (*nfound)++;
> - if (c->name[len] == '\0')
> + enum maybe_add_completion_enum add_status;
> +
> + add_status = (tracker == NULL
> + ? MAYBE_ADD_COMPLETION_OK
> + : maybe_add_completion (tracker, c->name));
> + switch (add_status)
> {
> - *nfound = 1;
> + case MAYBE_ADD_COMPLETION_OK:
> + found = c;
> + (*nfound)++;
> + if (c->name[len] == '\0')
> + {
> + *nfound = 1;
> + return found;
> + }
> + break;
> + case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> + found = c;
> + (*nfound)++;
> + return found;
> + case MAYBE_ADD_COMPLETION_MAX_REACHED:
> + return found;
> + case MAYBE_ADD_COMPLETION_DUPLICATE:
> + continue;
> break;
> }
> }
> @@ -1336,7 +1359,8 @@ valid_user_defined_cmd_name_p (const char *name)
> the struct cmd_list_element is NULL). */
>
> struct cmd_list_element *
> -lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> +lookup_cmd_1 (completion_tracker_t tracker,
> + const char **text, struct cmd_list_element *clist,
> struct cmd_list_element **result_list, int ignore_help_classes)
> {
> char *command;
> @@ -1365,7 +1389,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
> /* Look it up. */
> found = 0;
> nfound = 0;
> - found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
> + found = find_cmd (tracker, command, len, clist, ignore_help_classes,
> + &nfound);
>
> /* We didn't find the command in the entered case, so lower case it
> and search again. */
> @@ -1377,7 +1402,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
>
> command[tmp] = isupper (x) ? tolower (x) : x;
> }
> - found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
> + found = find_cmd (tracker, command, len, clist, ignore_help_classes,
> + &nfound);
> }
>
> /* If nothing matches, we have a simple failure. */
> @@ -1414,7 +1440,7 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
>
> if (found->prefixlist)
> {
> - c = lookup_cmd_1 (text, *found->prefixlist, result_list,
> + c = lookup_cmd_1 (tracker, text, *found->prefixlist, result_list,
> ignore_help_classes);
> if (!c)
> {
> @@ -1491,7 +1517,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list, char *cmdtype,
> if (!*line)
> error (_("Lack of needed %scommand"), cmdtype);
>
> - c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
> + c = lookup_cmd_1 (NULL, line, list, &last_list, ignore_help_classes);
>
> if (!c)
> {
> @@ -1718,7 +1744,7 @@ lookup_cmd_composition (const char *text,
> /* Look it up. */
> *cmd = 0;
> nfound = 0;
> - *cmd = find_cmd (command, len, cur_list, 1, &nfound);
> + *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
>
> /* We didn't find the command in the entered case, so lower case
> it and search again.
> @@ -1731,7 +1757,7 @@ lookup_cmd_composition (const char *text,
>
> command[tmp] = isupper (x) ? tolower (x) : x;
> }
> - *cmd = find_cmd (command, len, cur_list, 1, &nfound);
> + *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
> }
>
> if (*cmd == CMD_LIST_AMBIGUOUS)
> @@ -1842,7 +1868,7 @@ complete_on_cmdlist (struct cmd_list_element *list,
> "oobar"; if WORD is "baz/foo", return "baz/foobar". */
>
> VEC (char_ptr) *
> -complete_on_enum (const char *const *enumlist,
> +complete_on_enum (completion_tracker_t ignore, const char *const *enumlist,
> const char *text, const char *word)
> {
> VEC (char_ptr) *matchlist = NULL;
> diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
> index ec89325..bbedb52 100644
> --- a/gdb/cli/cli-decode.h
> +++ b/gdb/cli/cli-decode.h
> @@ -23,6 +23,7 @@
>
> /* Include the public interfaces. */
> #include "command.h"
> +#include "completer.h"
>
> struct re_pattern_buffer;
>
> diff --git a/gdb/command.h b/gdb/command.h
> index 956eeaa..35d61bd 100644
> --- a/gdb/command.h
> +++ b/gdb/command.h
> @@ -156,19 +156,6 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty,
> extern void set_cmd_sfunc (struct cmd_list_element *cmd,
> cmd_sfunc_ftype *sfunc);
>
> -typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
> - const char *, const char *);
> -
> -typedef void completer_ftype_void (struct cmd_list_element *,
> - const char *, const char *);
> -
> -extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
> -
> -/* Set the completer_handle_brkchars callback. */
> -
> -extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
> - completer_ftype_void *);
> -
> /* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
> around in cmd objects to test the value of the commands sfunc(). */
> extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
> @@ -189,18 +176,6 @@ extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
> /* Return the type of the command. */
> extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
>
> -/* Flag for an ambiguous cmd_list result. */
> -#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
> -
> -extern struct cmd_list_element *lookup_cmd (const char **,
> - struct cmd_list_element *, char *,
> - int, int);
> -
====
Seems odd to remove CMD_LIST_AMBIGUOUS, lookup_cmd, lookup_cmd_1 here.
Can we keep them here, at least for now?
I can imagine the motivation is an inclusion order issue.
If we passed around struct completion_state instead of completion_tracker_t
then we could just forward declare it in command.h.
Another way, of course, if one wanted to just pass tracker, is to change the
type to struct completion_tracker and forward declare that in command.h.
> -extern struct cmd_list_element *lookup_cmd_1 (const char **,
> - struct cmd_list_element *,
> - struct cmd_list_element **,
> - int);
> -
> extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
> const char * );
>
> @@ -225,12 +200,6 @@ extern struct cmd_list_element *add_info (const char *,
> extern struct cmd_list_element *add_info_alias (const char *, const char *,
> int);
>
> -extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
> - const char *, const char *, int);
> -
> -extern VEC (char_ptr) *complete_on_enum (const char *const *enumlist,
> - const char *, const char *);
> -
> /* Functions that implement commands about CLI commands. */
>
> extern void help_list (struct cmd_list_element *, const char *,
> diff --git a/gdb/completer.c b/gdb/completer.c
> index add79cc..67644d1 100644
> --- a/gdb/completer.c
> +++ b/gdb/completer.c
> @@ -107,7 +107,8 @@ readline_line_completion_function (const char *text, int matches)
> /* This can be used for functions which don't want to complete on
> symbols but don't want to complete on anything else either. */
> VEC (char_ptr) *
> -noop_completer (struct cmd_list_element *ignore,
> +noop_completer (struct cmd_list_element *ignore,
> + completion_tracker_t ignore2,
> const char *text, const char *prefix)
> {
> return NULL;
> @@ -115,7 +116,8 @@ noop_completer (struct cmd_list_element *ignore,
>
> /* Complete on filenames. */
> VEC (char_ptr) *
> -filename_completer (struct cmd_list_element *ignore,
> +filename_completer (struct cmd_list_element *ignore,
> + completion_tracker_t ignore2,
> const char *text, const char *word)
> {
> int subsequent_name;
> @@ -184,7 +186,8 @@ filename_completer (struct cmd_list_element *ignore,
> etc. */
>
> VEC (char_ptr) *
> -location_completer (struct cmd_list_element *ignore,
> +location_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> int n_syms, n_files, ix;
> @@ -260,18 +263,41 @@ location_completer (struct cmd_list_element *ignore,
> symbols as well as on files. */
> if (colon)
> {
> - list = make_file_symbol_completion_list (symbol_start, word,
> - file_to_match);
> + struct gdb_exception e;
> +
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + list = make_file_symbol_completion_list (tracker, symbol_start,
> + word, file_to_match);
> + }
====
Why is this now wrapped in a try/catch?
And similarly below.
Is it because MAX_COMPLETIONS_REACHED_ERROR may be thrown?
I'd expect make_file_symbol_completion_list to catch it
and return the list collected thus far.
> + if (e.reason < 0)
> + list = NULL;
> xfree (file_to_match);
> }
> else
> {
> - list = make_symbol_completion_list (symbol_start, word);
> + struct gdb_exception e;
> +
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + list = make_symbol_completion_list (tracker, symbol_start, word);
> + }
> + if (e.reason < 0)
> + list = NULL;
> +
> /* 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);
> + {
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + fn_list = make_source_files_completion_list (tracker, text,
> + text);
> + }
> + if (e.reason < 0)
> + fn_list = NULL;
> + }
> }
>
> n_syms = VEC_length (char_ptr, list);
> @@ -326,7 +352,14 @@ location_completer (struct cmd_list_element *ignore,
> {
> /* 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);
> + struct gdb_exception e;
> +
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + list = make_symbol_completion_list (tracker, orig_text, word);
> + }
> + if (e.reason < 0)
> + list = NULL;
> }
>
> return list;
> @@ -389,7 +422,8 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
> names, but some language parsers also have support for completing
> field names. */
> VEC (char_ptr) *
> -expression_completer (struct cmd_list_element *ignore,
> +expression_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> struct type *type = NULL;
> @@ -434,7 +468,8 @@ expression_completer (struct cmd_list_element *ignore,
> VEC (char_ptr) *result;
> struct cleanup *cleanup = make_cleanup (xfree, fieldname);
>
> - result = make_symbol_completion_type (fieldname, fieldname, code);
> + result = make_symbol_completion_type (tracker, fieldname, fieldname,
> + code);
> do_cleanups (cleanup);
> return result;
> }
> @@ -448,7 +483,7 @@ expression_completer (struct cmd_list_element *ignore,
> ;
>
> /* Not ideal but it is what we used to do before... */
> - return location_completer (ignore, p, word);
> + return location_completer (ignore, tracker, p, word);
> }
>
> /* See definition in completer.h. */
> @@ -526,7 +561,7 @@ complete_line_internal_reason;
> */
>
> static VEC (char_ptr) *
> -complete_line_internal (const char *text,
> +complete_line_internal (completion_tracker_t tracker, const char *text,
> const char *line_buffer, int point,
> complete_line_internal_reason reason)
> {
> @@ -572,7 +607,21 @@ complete_line_internal (const char *text,
> }
> else
> {
> - c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
> + /* There are two possible scenarios:
> + 1) The user is searching for completions to a command
> + 2) The user is attempting to complete the argument of
> + a specific command.
> +
> + In either case, lookup_cmd_1 will increment the tracker.
> + However, for case #2, the tracker's results must be cleared,
> + since we don't want the actual command lookup to be counted
> + by that command's completer function. If we didn't do this,
> + we'd end up with an off-by-one error between the tracker
> + and the returned completion list. */
> + c = lookup_cmd_1 (tracker, &p, cmdlist, &result_list,
> + ignore_help_classes);
> + if (c != CMD_LIST_AMBIGUOUS && tracker != NULL)
> + htab_empty (tracker);
> }
>
> /* Move p up to the next interesting thing. */
> @@ -658,7 +707,7 @@ complete_line_internal (const char *text,
> else if (c->enums)
> {
> if (reason != handle_brkchars)
> - list = complete_on_enum (c->enums, p, word);
> + list = complete_on_enum (tracker, c->enums, p, word);
> rl_completer_word_break_characters =
> gdb_completer_command_word_break_characters;
> }
> @@ -698,7 +747,7 @@ complete_line_internal (const char *text,
> && c->completer_handle_brkchars != NULL)
> (*c->completer_handle_brkchars) (c, p, word);
> if (reason != handle_brkchars && c->completer != NULL)
> - list = (*c->completer) (c, p, word);
> + list = (*c->completer) (c, tracker, p, word);
> }
> }
> else
> @@ -744,7 +793,7 @@ complete_line_internal (const char *text,
> else if (c->enums)
> {
> if (reason != handle_brkchars)
> - list = complete_on_enum (c->enums, p, word);
> + list = complete_on_enum (tracker, c->enums, p, word);
> }
> else
> {
> @@ -774,7 +823,7 @@ complete_line_internal (const char *text,
> && c->completer_handle_brkchars != NULL)
> (*c->completer_handle_brkchars) (c, p, word);
> if (reason != handle_brkchars && c->completer != NULL)
> - list = (*c->completer) (c, p, word);
> + list = (*c->completer) (c, tracker, p, word);
> }
> }
> }
> @@ -825,7 +874,7 @@ make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
> /* See completer.h. */
>
> enum maybe_add_completion_enum
> -maybe_add_completion (completion_tracker_t tracker, char *name)
> +maybe_add_completion (completion_tracker_t tracker, const char *name)
> {
> void **slot;
>
> @@ -844,7 +893,7 @@ maybe_add_completion (completion_tracker_t tracker, char *name)
> if (*slot != HTAB_EMPTY_ENTRY)
> return MAYBE_ADD_COMPLETION_DUPLICATE;
>
> - *slot = name;
> + *slot = (void *) name;
>
> return (htab_elements (tracker) < max_completions
> ? MAYBE_ADD_COMPLETION_OK
> @@ -875,52 +924,75 @@ complete_line (const char *text, const char *line_buffer, int point)
> {
> VEC (char_ptr) *list;
> VEC (char_ptr) *result = NULL;
> - struct cleanup *cleanups;
> + struct cleanup *tracker_cleanup, *cleanups;
> completion_tracker_t tracker;
> char *candidate;
> int ix, max_reached;
>
> if (max_completions == 0)
> return NULL;
> - list = complete_line_internal (text, line_buffer, point,
> - handle_completions);
> - if (max_completions < 0)
> - return list;
>
> tracker = new_completion_tracker ();
> cleanups = make_cleanup_free_completion_tracker (&tracker);
> - make_cleanup_free_char_ptr_vec (list);
>
> - /* Do a final test for too many completions. Individual completers may
> - do some of this, but are not required to. Duplicates are also removed
> - here. Otherwise the user is left scratching his/her head: readline and
> - complete_command will remove duplicates, and if removal of duplicates
> - there brings the total under max_completions the user may think gdb quit
> - searching too early. */
> + list = complete_line_internal (tracker, text, line_buffer, point,
> + handle_completions);
>
> - for (ix = 0, max_reached = 0;
> - !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
> - ++ix)
> + if (max_completions < 0)
> {
> - enum maybe_add_completion_enum add_status;
> + do_cleanups (cleanups);
> + return list;
> + }
> +
> + make_cleanup_free_char_ptr_vec (list);
> +
> + /* If complete_line_internal returned more completions than were
> + recorded by the completion tracker, then the completer function that
> + was run does not support completion tracking. In this case,
> + do a final test for too many completions.
>
> - add_status = maybe_add_completion (tracker, candidate);
> + Duplicates are also removed here. Otherwise the user is left
> + scratching his/her head: readline and complete_command will remove
> + duplicates, and if removal of duplicates there brings the total under
> + max_completions the user may think gdb quit searching too early. */
>
> - switch (add_status)
> + if (VEC_length (char_ptr, list) > htab_elements (tracker))
> + {
> + /* Clear the tracker so that we can re-use it to count the number
> + of returned completions. */
> + htab_empty (tracker);
> +
> + for (ix = 0, max_reached = 0;
> + !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
> + ++ix)
> {
> - case MAYBE_ADD_COMPLETION_OK:
> - VEC_safe_push (char_ptr, result, xstrdup (candidate));
> - break;
> - case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> - VEC_safe_push (char_ptr, result, xstrdup (candidate));
> - max_reached = 1;
> - break;
> - case MAYBE_ADD_COMPLETION_MAX_REACHED:
> - gdb_assert_not_reached ("more than max completions reached");
> - case MAYBE_ADD_COMPLETION_DUPLICATE:
> - break;
> + enum maybe_add_completion_enum add_status;
> +
> + add_status = maybe_add_completion (tracker, candidate);
> +
> + switch (add_status)
> + {
> + case MAYBE_ADD_COMPLETION_OK:
> + VEC_safe_push (char_ptr, result, xstrdup (candidate));
> + break;
> + case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> + VEC_safe_push (char_ptr, result, xstrdup (candidate));
> + max_reached = 1;
> + break;
> + case MAYBE_ADD_COMPLETION_MAX_REACHED:
> + gdb_assert_not_reached ("more than max completions reached");
> + case MAYBE_ADD_COMPLETION_DUPLICATE:
> + break;
> + }
> }
> }
> + else
> + {
> + /* There is a valid tracker for the completion -- simply copy
> + the returned list into the return result. */
> + for (ix = 0; VEC_iterate (char_ptr, list, ix, candidate); ++ix)
> + VEC_safe_push (char_ptr, result, xstrdup (candidate));
====
Can we just return list instead of making a copy of it?
E.g.,
if (VEC_length (char_ptr, list) <= htab_elements (tracker))
{
discard_cleanups (list_cleanups);
do_cleanups (cleanups);
return list;
}
/* Clear the tracker so that we can re-use it to count the number
of returned completions. */
...
> + }
>
> do_cleanups (cleanups);
>
> @@ -929,10 +1001,11 @@ complete_line (const char *text, const char *line_buffer, int point)
>
> /* Complete on command names. Used by "help". */
> VEC (char_ptr) *
> -command_completer (struct cmd_list_element *ignore,
> +command_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> - return complete_line_internal (word, text,
> + return complete_line_internal (tracker, word, text,
> strlen (text), handle_help);
> }
>
> @@ -940,6 +1013,7 @@ command_completer (struct cmd_list_element *ignore,
>
> VEC (char_ptr) *
> signal_completer (struct cmd_list_element *ignore,
> + completion_tracker_t ignore2,
> const char *text, const char *word)
> {
> VEC (char_ptr) *return_val = NULL;
> @@ -970,6 +1044,7 @@ signal_completer (struct cmd_list_element *ignore,
>
> VEC (char_ptr) *
> reg_or_group_completer (struct cmd_list_element *ignore,
> + completion_tracker_t ingore2,
> const char *text, const char *word)
> {
> VEC (char_ptr) *result = NULL;
> @@ -1013,7 +1088,7 @@ gdb_completion_word_break_characters (void)
> {
> VEC (char_ptr) *list;
>
> - list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point,
> + list = complete_line_internal (NULL, rl_line_buffer, rl_line_buffer, rl_point,
> handle_brkchars);
> gdb_assert (list == NULL);
> return rl_completer_word_break_characters;
> diff --git a/gdb/completer.h b/gdb/completer.h
> index 56e1a2b..7bc0543 100644
> --- a/gdb/completer.h
> +++ b/gdb/completer.h
> @@ -18,7 +18,6 @@
> #define COMPLETER_H 1
>
> #include "gdb_vecs.h"
> -#include "command.h"
>
> /* Types of functions in struct match_list_displayer. */
>
> @@ -33,6 +32,70 @@ typedef void mld_erase_entire_line_ftype (const struct match_list_displayer *);
> typedef void mld_beep_ftype (const struct match_list_displayer *);
> typedef int mld_read_key_ftype (const struct match_list_displayer *);
>
> +/* Maximum number of candidates to consider before the completer
> + bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
> + disable limiting. */
> +
> +extern int max_completions;
> +
> +/* Object to track how many unique completions have been generated.
> + Used to limit the size of generated completion lists. */
> +
> +typedef htab_t completion_tracker_t;
> +
> +/* Create a new completion tracker.
> + The result is a hash table to track added completions, or NULL
> + if max_completions <= 0. If max_completions < 0, tracking is disabled.
> + If max_completions == 0, the max is indeed zero. */
> +
> +extern completion_tracker_t new_completion_tracker (void);
> +
> +/* Make a cleanup to free a completion tracker, and reset its pointer
> + to NULL. */
> +
> +extern struct cleanup *make_cleanup_free_completion_tracker
> + (completion_tracker_t *tracker_ptr);
> +
> +/* Return values for maybe_add_completion. */
> +
> +enum maybe_add_completion_enum
> +{
> + /* NAME has been recorded and max_completions has not been reached,
> + or completion tracking is disabled (max_completions < 0). */
> + MAYBE_ADD_COMPLETION_OK,
> +
> + /* NAME has been recorded and max_completions has been reached
> + (thus the caller can stop searching). */
> + MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
> +
> + /* max-completions entries has been reached.
> + Whether NAME is a duplicate or not is not determined. */
> + MAYBE_ADD_COMPLETION_MAX_REACHED,
> +
> + /* NAME has already been recorded.
> + Note that this is never returned if completion tracking is disabled
> + (max_completions < 0). */
> + MAYBE_ADD_COMPLETION_DUPLICATE
> +};
> +
> +/* Add the completion NAME to the list of generated completions if
> + it is not there already.
> + If max_completions is negative, nothing is done, not even watching
> + for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
> +
> + If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
> + record at least one more completion. The final list will be pruned to
> + max_completions, but recording at least one more than max_completions is
> + the signal to the completion machinery that too many completions were
> + found. */
> +
> +extern enum maybe_add_completion_enum
> + maybe_add_completion (completion_tracker_t tracker, const char *name);
> +
> +/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
> +
> +extern void throw_max_completions_reached_error (void);
> +
> /* Interface between CLI/TUI and gdb_match_list_displayer. */
>
> struct match_list_displayer
> @@ -76,106 +139,83 @@ extern char *readline_line_completion_function (const char *text,
> int matches);
>
> extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
> + completion_tracker_t,
> const char *, const char *);
>
> extern char *get_gdb_completer_quote_characters (void);
>
> extern char *gdb_completion_word_break_characters (void);
>
> -/* Set the word break characters array to the corresponding set of
> - chars, based on FN. This function is useful for cases when the
> - completer doesn't know the type of the completion until some
> - calculation is done (e.g., for Python functions). */
> -
> -extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
> -
> -/* Exported to linespec.c */
> -
> -extern const char *skip_quoted_chars (const char *, const char *,
> - const char *);
> -
> -extern const char *skip_quoted (const char *);
> -
> -/* Maximum number of candidates to consider before the completer
> - bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
> - disable limiting. */
> -
> -extern int max_completions;
> -
> -/* Object to track how many unique completions have been generated.
> - Used to limit the size of generated completion lists. */
> +typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
> + completion_tracker_t,
> + const char *, const char *);
>
> -typedef htab_t completion_tracker_t;
> +typedef void completer_ftype_void (struct cmd_list_element *,
> + const char *, const char *);
>
> -/* Create a new completion tracker.
> - The result is a hash table to track added completions, or NULL
> - if max_completions <= 0. If max_completions < 0, tracking is disabled.
> - If max_completions == 0, the max is indeed zero. */
> +extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
>
> -extern completion_tracker_t new_completion_tracker (void);
> +/* Set the completer_handle_brkchars callback. */
>
> -/* Make a cleanup to free a completion tracker, and reset its pointer
> - to NULL. */
> +extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
> + completer_ftype_void *);
>
> -extern struct cleanup *make_cleanup_free_completion_tracker
> - (completion_tracker_t *tracker_ptr);
> -
> -/* Return values for maybe_add_completion. */
> +/* Set the word break characters array to the corresponding set of
> + chars, based on FN. This function is useful for cases when the
> + completer doesn't know the type of the completion until some
> + calculation is done (e.g., for Python functions). */
>
> -enum maybe_add_completion_enum
> -{
> - /* NAME has been recorded and max_completions has not been reached,
> - or completion tracking is disabled (max_completions < 0). */
> - MAYBE_ADD_COMPLETION_OK,
> +extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
>
> - /* NAME has been recorded and max_completions has been reached
> - (thus the caller can stop searching). */
> - MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
> +extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
> + const char *, const char *, int);
>
> - /* max-completions entries has been reached.
> - Whether NAME is a duplicate or not is not determined. */
> - MAYBE_ADD_COMPLETION_MAX_REACHED,
> +extern VEC (char_ptr) *complete_on_enum (completion_tracker_t,
> + const char *const *enumlist,
> + const char *, const char *);
>
> - /* NAME has already been recorded.
> - Note that this is never returned if completion tracking is disabled
> - (max_completions < 0). */
> - MAYBE_ADD_COMPLETION_DUPLICATE
> -};
> +/* Flag for an ambiguous cmd_list result. */
> +#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
>
> -/* Add the completion NAME to the list of generated completions if
> - it is not there already.
> - If max_completions is negative, nothing is done, not even watching
> - for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
> +extern struct cmd_list_element *lookup_cmd (const char **,
> + struct cmd_list_element *, char *,
> + int, int);
>
> - If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
> - record at least one more completion. The final list will be pruned to
> - max_completions, but recording at least one more than max_completions is
> - the signal to the completion machinery that too many completions were
> - found. */
> +extern struct cmd_list_element *lookup_cmd_1 (completion_tracker_t,
> + const char **,
> + struct cmd_list_element *,
> + struct cmd_list_element **,
> + int);
>
> -extern enum maybe_add_completion_enum
> - maybe_add_completion (completion_tracker_t tracker, char *name);
> +/* Exported to linespec.c */
>
> -/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
> +extern const char *skip_quoted_chars (const char *, const char *,
> + const char *);
>
> -extern void throw_max_completions_reached_error (void);
> +extern const char *skip_quoted (const char *);
>
> #endif /* defined (COMPLETER_H) */
> diff --git a/gdb/corefile.c b/gdb/corefile.c
> index a042e6d..309a93d 100644
> --- a/gdb/corefile.c
> +++ b/gdb/corefile.c
> @@ -469,6 +469,7 @@ set_gnutarget_command (char *ignore, int from_tty,
>
> static VEC (char_ptr) *
> complete_set_gnutarget (struct cmd_list_element *cmd,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> static const char **bfd_targets;
> @@ -486,7 +487,7 @@ complete_set_gnutarget (struct cmd_list_element *cmd,
> bfd_targets[last + 1] = NULL;
> }
>
> - return complete_on_enum (bfd_targets, text, word);
> + return complete_on_enum (tracker, bfd_targets, text, word);
> }
>
> /* Set the gnutarget. */
> diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c
> index 9316c4c..4086d0c 100644
> --- a/gdb/cp-abi.c
> +++ b/gdb/cp-abi.c
> @@ -355,6 +355,7 @@ set_cp_abi_cmd (char *args, int from_tty)
>
> static VEC (char_ptr) *
> cp_abi_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> static const char **cp_abi_names;
> @@ -369,7 +370,7 @@ cp_abi_completer (struct cmd_list_element *ignore,
> cp_abi_names[i] = NULL;
> }
>
> - return complete_on_enum (cp_abi_names, text, word);
> + return complete_on_enum (tracker, cp_abi_names, text, word);
> }
>
> /* Show the currently selected C++ ABI. */
> diff --git a/gdb/f-lang.c b/gdb/f-lang.c
> index 8b61028..d772cfa 100644
> --- a/gdb/f-lang.c
> +++ b/gdb/f-lang.c
> @@ -229,10 +229,12 @@ f_word_break_characters (void)
> class. */
>
> static VEC (char_ptr) *
> -f_make_symbol_completion_list (const char *text, const char *word,
> +f_make_symbol_completion_list (completion_tracker_t tracker,
> + const char *text, const char *word,
> enum type_code code)
> {
> - return default_make_symbol_completion_list_break_on (text, word, ":", code);
> + return default_make_symbol_completion_list_break_on (tracker, text, word,
> + ":", code);
> }
>
> const struct language_defn f_language_defn =
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 15589b6..75fe2e3 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6934,6 +6934,7 @@ Are you sure you want to change it? "),
>
> static VEC (char_ptr) *
> handle_completer (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
> @@ -6951,8 +6952,8 @@ handle_completer (struct cmd_list_element *ignore,
> NULL,
> };
>
> - vec_signals = signal_completer (ignore, text, word);
> - vec_keywords = complete_on_enum (keywords, word, word);
> + vec_signals = signal_completer (ignore, tracker, text, word);
> + vec_keywords = complete_on_enum (tracker, keywords, word, word);
>
> return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
> VEC_free (char_ptr, vec_signals);
> diff --git a/gdb/interps.c b/gdb/interps.c
> index 90b5b2d..2215ac1 100644
> --- a/gdb/interps.c
> +++ b/gdb/interps.c
> @@ -438,6 +438,7 @@ interpreter_exec_cmd (char *args, int from_tty)
> /* List the possible interpreters which could complete the given text. */
> static VEC (char_ptr) *
> interpreter_completer (struct cmd_list_element *ignore,
> + completion_tracker_t ingore2,
> const char *text, const char *word)
> {
> int textlen;
> diff --git a/gdb/language.h b/gdb/language.h
> index 436fd6e..b095093 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -301,7 +301,8 @@ struct language_defn
> completion is being made. If CODE is TYPE_CODE_UNDEF, then all
> symbols should be examined; otherwise, only STRUCT_DOMAIN
> symbols whose type has a code of CODE should be matched. */
> - VEC (char_ptr) *(*la_make_symbol_completion_list) (const char *text,
> + VEC (char_ptr) *(*la_make_symbol_completion_list) (completion_tracker_t,
> + const char *text,
> const char *word,
> enum type_code code);
>
> diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
> index a5e96d6..2f95b46 100644
> --- a/gdb/python/py-cmd.c
> +++ b/gdb/python/py-cmd.c
> @@ -347,6 +347,7 @@ cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
>
> static VEC (char_ptr) *
> cmdpy_completer (struct cmd_list_element *command,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> PyObject *resultobj = NULL;
> @@ -378,7 +379,7 @@ cmdpy_completer (struct cmd_list_element *command,
> PyErr_Clear ();
> }
> else if (value >= 0 && value < (long) N_COMPLETERS)
> - result = completers[value].completer (command, text, word);
> + result = completers[value].completer (command, tracker, text, word);
> }
> else
> {
> @@ -485,7 +486,7 @@ gdbpy_parse_command_name (const char *name,
> prefix_text[i + 1] = '\0';
>
> prefix_text2 = prefix_text;
> - elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
> + elt = lookup_cmd_1 (NULL, &prefix_text2, *start_list, NULL, 1);
> if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
> {
> PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 5302afa..9f04966 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -4994,29 +4994,21 @@ do_free_completion_list (void *list)
>
> static VEC (char_ptr) *return_val;
>
> -#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
> - completion_list_add_name \
> - (SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
> +#define COMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
> + completion_list_add_name \
> + (tracker, SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
>
> -#define MCOMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
> - completion_list_add_name \
> - (MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
> -
> -/* Tracker for how many unique completions have been generated. Used
> - to terminate completion list generation early if the list has grown
> - to a size so large as to be useless. This helps avoid GDB seeming
> - to lock up in the event the user requests to complete on something
> - vague that necessitates the time consuming expansion of many symbol
> - tables. */
> -
> -static completion_tracker_t completion_tracker;
> +#define MCOMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
> + completion_list_add_name \
> + ((tracker), MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
>
> /* Test to see if the symbol specified by SYMNAME (which is already
> demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
> characters. If so, add it to the current completion list. */
>
> static void
> -completion_list_add_name (const char *symname,
> +completion_list_add_name (completion_tracker_t tracker,
> + const char *symname,
> const char *sym_text, int sym_text_len,
> const char *text, const char *word)
> {
> @@ -5051,7 +5043,7 @@ completion_list_add_name (const char *symname,
> strcat (new, symname);
> }
>
> - add_status = maybe_add_completion (completion_tracker, new);
> + add_status = maybe_add_completion (tracker, new);
>
> switch (add_status)
> {
> @@ -5075,7 +5067,8 @@ completion_list_add_name (const char *symname,
> again and feed all the selectors into the mill. */
>
> static void
> -completion_list_objc_symbol (struct minimal_symbol *msymbol,
> +completion_list_objc_symbol (completion_tracker_t tracker,
> + struct minimal_symbol *msymbol,
> const char *sym_text, int sym_text_len,
> const char *text, const char *word)
> {
> @@ -5093,7 +5086,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
>
> if (sym_text[0] == '[')
> /* Complete on shortened method method. */
> - completion_list_add_name (method + 1, sym_text, sym_text_len, text, word);
> + completion_list_add_name (tracker, method + 1, sym_text, sym_text_len,
> + text, word);
>
> while ((strlen (method) + 1) >= tmplen)
> {
> @@ -5114,9 +5108,11 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
> memcpy (tmp, method, (category - method));
> tmp[category - method] = ' ';
> memcpy (tmp + (category - method) + 1, selector, strlen (selector) + 1);
> - completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
> + completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
> + word);
> if (sym_text[0] == '[')
> - completion_list_add_name (tmp + 1, sym_text, sym_text_len, text, word);
> + completion_list_add_name (tracker, tmp + 1, sym_text, sym_text_len,
> + text, word);
> }
>
> if (selector != NULL)
> @@ -5127,7 +5123,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
> if (tmp2 != NULL)
> *tmp2 = '\0';
>
> - completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
> + completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
> + word);
> }
> }
>
> @@ -5178,9 +5175,9 @@ language_search_unquoted_string (const char *text, const char *p)
> }
>
> static void
> -completion_list_add_fields (struct symbol *sym, const char *sym_text,
> - int sym_text_len, const char *text,
> - const char *word)
> +completion_list_add_fields (completion_tracker_t tracker, struct symbol *sym,
> + const char *sym_text, int sym_text_len,
> + const char *text, const char *word)
> {
> if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
> {
> @@ -5191,7 +5188,7 @@ completion_list_add_fields (struct symbol *sym, const char *sym_text,
> if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
> for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
> if (TYPE_FIELD_NAME (t, j))
> - completion_list_add_name (TYPE_FIELD_NAME (t, j),
> + completion_list_add_name (tracker, TYPE_FIELD_NAME (t, j),
> sym_text, sym_text_len, text, word);
> }
> }
> @@ -5206,6 +5203,7 @@ struct add_name_data
> int sym_text_len;
> const char *text;
> const char *word;
> + completion_tracker_t tracker;
>
> /* Extra argument required for add_symtab_completions. */
> enum type_code code;
> @@ -5221,7 +5219,7 @@ add_macro_name (const char *name, const struct macro_definition *ignore,
> {
> struct add_name_data *datum = (struct add_name_data *) user_data;
>
> - completion_list_add_name (name,
> + completion_list_add_name (datum->tracker, name,
> datum->sym_text, datum->sym_text_len,
> datum->text, datum->word);
> }
> @@ -5240,6 +5238,7 @@ symbol_completion_matcher (const char *name, void *user_data)
>
> static void
> add_symtab_completions (struct compunit_symtab *cust,
> + completion_tracker_t tracker,
> const char *sym_text, int sym_text_len,
> const char *text, const char *word,
> enum type_code code)
> @@ -5258,7 +5257,7 @@ add_symtab_completions (struct compunit_symtab *cust,
> if (code == TYPE_CODE_UNDEF
> || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
> && TYPE_CODE (SYMBOL_TYPE (sym)) == code))
> - COMPLETION_LIST_ADD_SYMBOL (sym,
> + COMPLETION_LIST_ADD_SYMBOL (tracker, sym,
> sym_text, sym_text_len,
> text, word);
> }
> @@ -5274,14 +5273,15 @@ symtab_expansion_callback (struct compunit_symtab *symtab,
> {
> struct add_name_data *datum = (struct add_name_data *) user_data;
>
> - add_symtab_completions (symtab,
> + add_symtab_completions (symtab, datum->tracker,
> datum->sym_text, datum->sym_text_len,
> datum->text, datum->word,
> datum->code);
> }
>
> static void
> -default_make_symbol_completion_list_break_on_1 (const char *text,
> +default_make_symbol_completion_list_break_on_1 (completion_tracker_t tracker,
> + const char *text,
> const char *word,
> const char *break_on,
> enum type_code code)
> @@ -5302,7 +5302,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> /* Length of sym_text. */
> int sym_text_len;
> struct add_name_data datum;
> - struct cleanup *cleanups;
>
> /* Now look for the symbol we are supposed to complete on. */
> {
> @@ -5373,14 +5372,12 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> }
> gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '(');
>
> - completion_tracker = new_completion_tracker ();
> - cleanups = make_cleanup_free_completion_tracker (&completion_tracker);
> -
> datum.sym_text = sym_text;
> datum.sym_text_len = sym_text_len;
> datum.text = text;
> datum.word = word;
> datum.code = code;
> + datum.tracker = tracker;
>
> /* At this point scan through the misc symbol vectors and add each
> symbol you find to the list. Eventually we want to ignore
> @@ -5392,17 +5389,17 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> ALL_MSYMBOLS (objfile, msymbol)
> {
> QUIT;
> - MCOMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text,
> - word);
> + MCOMPLETION_LIST_ADD_SYMBOL (tracker, msymbol, sym_text,
> + sym_text_len, text, word);
>
> - completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text,
> - word);
> + completion_list_objc_symbol (tracker, msymbol, sym_text,
> + sym_text_len, text, word);
> }
> }
>
> /* Add completions for all currently loaded symbol tables. */
> ALL_COMPUNITS (objfile, cust)
> - add_symtab_completions (cust, sym_text, sym_text_len, text, word,
> + add_symtab_completions (cust, tracker, sym_text, sym_text_len, text, word,
> code);
>
> /* Look through the partial symtabs for all symbols which begin
> @@ -5430,15 +5427,15 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> {
> if (code == TYPE_CODE_UNDEF)
> {
> - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
> - word);
> - completion_list_add_fields (sym, sym_text, sym_text_len, text,
> - word);
> + COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
> + sym_text_len, text, word);
> + completion_list_add_fields (tracker, sym, sym_text,
> + sym_text_len, text, word);
> }
> else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
> && TYPE_CODE (SYMBOL_TYPE (sym)) == code)
> - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
> - word);
> + COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
> + sym_text_len, text, word);
> }
>
> /* Stop when we encounter an enclosing function. Do not stop for
> @@ -5455,11 +5452,13 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> {
> if (surrounding_static_block != NULL)
> ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
> - completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
> + completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
> + text, word);
>
> if (surrounding_global_block != NULL)
> ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
> - completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
> + completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
> + text, word);
> }
>
> /* Skip macros if we are completing a struct tag -- arguable but
> @@ -5487,12 +5486,11 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
> /* User-defined macros are always visible. */
> macro_for_each (macro_user_macros, add_macro_name, &datum);
> }
> -
> - do_cleanups (cleanups);
> }
>
> VEC (char_ptr) *
> -default_make_symbol_completion_list_break_on (const char *text,
> +default_make_symbol_completion_list_break_on (completion_tracker_t tracker,
> + const char *text,
> const char *word,
> const char *break_on,
> enum type_code code)
> @@ -5505,7 +5503,7 @@ default_make_symbol_completion_list_break_on (const char *text,
>
> TRY_CATCH (except, RETURN_MASK_ERROR)
> {
> - default_make_symbol_completion_list_break_on_1 (text, word,
> + default_make_symbol_completion_list_break_on_1 (tracker, text, word,
> break_on, code);
> }
> if (except.reason < 0)
> @@ -5519,10 +5517,12 @@ default_make_symbol_completion_list_break_on (const char *text,
> }
>
> VEC (char_ptr) *
> -default_make_symbol_completion_list (const char *text, const char *word,
> +default_make_symbol_completion_list (completion_tracker_t tracker,
> + const char *text, const char *word,
> enum type_code code)
> {
> - return default_make_symbol_completion_list_break_on (text, word, "", code);
> + return default_make_symbol_completion_list_break_on (tracker, text, word,
> + "", code);
> }
>
> /* Return a vector of all symbols (regardless of class) which begin by
> @@ -5530,9 +5530,10 @@ default_make_symbol_completion_list (const char *text, const char *word,
> is NULL. */
>
> VEC (char_ptr) *
> -make_symbol_completion_list (const char *text, const char *word)
> +make_symbol_completion_list (completion_tracker_t tracker, const char *text,
> + const char *word)
> {
> - return current_language->la_make_symbol_completion_list (text, word,
> + return current_language->la_make_symbol_completion_list (tracker, text, word,
> TYPE_CODE_UNDEF);
> }
>
> @@ -5540,13 +5541,14 @@ make_symbol_completion_list (const char *text, const char *word)
> symbols whose type code is CODE. */
>
> VEC (char_ptr) *
> -make_symbol_completion_type (const char *text, const char *word,
> - enum type_code code)
> +make_symbol_completion_type (completion_tracker_t tracker, const char *text,
> + const char *word, enum type_code code)
> {
> gdb_assert (code == TYPE_CODE_UNION
> || code == TYPE_CODE_STRUCT
> || code == TYPE_CODE_ENUM);
> - return current_language->la_make_symbol_completion_list (text, word, code);
> + return current_language->la_make_symbol_completion_list (tracker, text,
> + word, code);
> }
>
> /* Like make_symbol_completion_list, but suitable for use as a
> @@ -5554,16 +5556,18 @@ make_symbol_completion_type (const char *text, const char *word,
>
> VEC (char_ptr) *
> make_symbol_completion_list_fn (struct cmd_list_element *ignore,
> + completion_tracker_t tracker,
> const char *text, const char *word)
> {
> - return make_symbol_completion_list (text, word);
> + return make_symbol_completion_list (tracker, text, word);
> }
>
> /* Like make_symbol_completion_list, but returns a list of symbols
> defined in a source file FILE. */
>
> VEC (char_ptr) *
> -make_file_symbol_completion_list (const char *text, const char *word,
> +make_file_symbol_completion_list (completion_tracker_t tracker,
> + const char *text, const char *word,
> const char *srcfile)
> {
> struct symbol *sym;
> @@ -5645,13 +5649,15 @@ make_file_symbol_completion_list (const char *text, const char *word,
> b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), GLOBAL_BLOCK);
> ALL_BLOCK_SYMBOLS (b, iter, sym)
> {
> - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
> + COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
> + word);
> }
>
> b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), STATIC_BLOCK);
> ALL_BLOCK_SYMBOLS (b, iter, sym)
> {
> - COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
> + COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
> + word);
> }
>
> return (return_val);
> @@ -5662,11 +5668,13 @@ make_file_symbol_completion_list (const char *text, const char *word,
> list as necessary. */
>
> static void
> -add_filename_to_list (const char *fname, const char *text, const char *word,
> +add_filename_to_list (completion_tracker_t tracker,
> + const char *fname, const char *text, const char *word,
> VEC (char_ptr) **list)
> {
> char *new;
> size_t fnlen = strlen (fname);
> + enum maybe_add_completion_enum add_status;
>
> if (word == text)
> {
> @@ -5688,7 +5696,22 @@ add_filename_to_list (const char *fname, const char *text, const char *word,
> new[text - word] = '\0';
> strcat (new, fname);
> }
> - VEC_safe_push (char_ptr, *list, new);
> +
> + add_status = maybe_add_completion (tracker, new);
> + switch (add_status)
> + {
> + case MAYBE_ADD_COMPLETION_OK:
> + VEC_safe_push (char_ptr, *list, new);
> + break;
> + case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
> + VEC_safe_push (char_ptr, *list, new);
> + /* fall through */
> + case MAYBE_ADD_COMPLETION_MAX_REACHED:
====
memory leak of new in MAYBE_ADD_COMPLETION_MAX_REACHED case.
> + throw_max_completions_reached_error ();
> + break;
> + case MAYBE_ADD_COMPLETION_DUPLICATE:
> + xfree (new);
> + }
> }
>
> static int
> @@ -5717,6 +5740,7 @@ struct add_partial_filename_data
> const char *word;
> int text_len;
> VEC (char_ptr) **list;
> + completion_tracker_t tracker;
> };
>
> /* A callback for map_partial_symbol_filenames. */
> @@ -5734,7 +5758,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
> {
> /* This file matches for a completion; add it to the
> current list of matches. */
> - add_filename_to_list (filename, data->text, data->word, data->list);
> + add_filename_to_list (data->tracker, filename, data->text, data->word,
> + data->list);
> }
> else
> {
> @@ -5743,7 +5768,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
> if (base_name != filename
> && !filename_seen (data->filename_seen_cache, base_name, 1)
> && filename_ncmp (base_name, data->text, data->text_len) == 0)
> - add_filename_to_list (base_name, data->text, data->word, data->list);
> + add_filename_to_list (data->tracker, base_name, data->text,
> + data->word, data->list);
> }
> }
>
> @@ -5753,7 +5779,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
> NULL. */
>
> VEC (char_ptr) *
> -make_source_files_completion_list (const char *text, const char *word)
> +make_source_files_completion_list (completion_tracker_t tracker,
> + const char *text, const char *word)
> {
> struct compunit_symtab *cu;
> struct symtab *s;
> @@ -5783,7 +5810,7 @@ make_source_files_completion_list (const char *text, const char *word)
> {
> /* This file matches for a completion; add it to the current
> list of matches. */
> - add_filename_to_list (s->filename, text, word, &list);
> + add_filename_to_list (tracker, s->filename, text, word, &list);
> }
> else
> {
> @@ -5795,7 +5822,7 @@ make_source_files_completion_list (const char *text, const char *word)
> if (base_name != s->filename
> && !filename_seen (filename_seen_cache, base_name, 1)
> && filename_ncmp (base_name, text, text_len) == 0)
> - add_filename_to_list (base_name, text, word, &list);
> + add_filename_to_list (tracker, base_name, text, word, &list);
> }
> }
>
> @@ -5804,6 +5831,7 @@ make_source_files_completion_list (const char *text, const char *word)
> datum.word = word;
> datum.text_len = text_len;
> datum.list = &list;
> + datum.tracker = tracker;
> map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
> 0 /*need_fullname*/);
>
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 0eb3a5b..572738a 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -23,6 +23,7 @@
> #include "vec.h"
> #include "gdb_vecs.h"
> #include "gdbtypes.h"
> +#include "completer.h"
>
> /* Opaque declarations. */
> struct ui_file;
> @@ -1444,24 +1445,22 @@ extern void forget_cached_source_info (void);
> extern void select_source_symtab (struct symtab *);
>
> extern VEC (char_ptr) *default_make_symbol_completion_list_break_on
> - (const char *text, const char *word, const char *break_on,
> - enum type_code code);
> -extern VEC (char_ptr) *default_make_symbol_completion_list (const char *,
> - const char *,
> - enum type_code);
> -extern VEC (char_ptr) *make_symbol_completion_list (const char *, const char *);
> -extern VEC (char_ptr) *make_symbol_completion_type (const char *, const char *,
> - enum type_code);
> -extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *,
> - const char *,
> - const char *);
> -
> -extern VEC (char_ptr) *make_file_symbol_completion_list (const char *,
> - const char *,
> - const char *);
> -
> -extern VEC (char_ptr) *make_source_files_completion_list (const char *,
> - const char *);
> + (completion_tracker_t tracker, const char *text, const char *word,
> + const char *break_on, enum type_code code);
> +extern VEC (char_ptr) *default_make_symbol_completion_list
> + (completion_tracker_t tracker, const char *, const char *, enum type_code);
> +extern VEC (char_ptr) *make_symbol_completion_list
> + (completion_tracker_t tracker, const char *, const char *);
> +extern VEC (char_ptr) *make_symbol_completion_type
> + (completion_tracker_t, const char *, const char *, enum type_code);
> +extern VEC (char_ptr) *make_symbol_completion_list_fn
> + (struct cmd_list_element *, completion_tracker_t, const char *, const char *);
> +
> +extern VEC (char_ptr) *make_file_symbol_completion_list
> + (completion_tracker_t, const char *, const char *, const char *);
> +
> +extern VEC (char_ptr) *make_source_files_completion_list
> + (completion_tracker_t, const char *, const char *);
>
> /* symtab.c */
>
> diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp
> index f77bfe2..5afd851 100644
> --- a/gdb/testsuite/gdb.base/completion.exp
> +++ b/gdb/testsuite/gdb.base/completion.exp
> @@ -777,6 +777,84 @@ gdb_test_multiple "" "$test" {
> }
>
> #
> +# Tests for the location completer
> +#
> +
> +# Turn off pending breakpoint support so that we don't get queried
> +# all the time.
> +gdb_test_no_output "set breakpoint pending off"
> +
> +set subsrc [string range $srcfile 0 [expr {[string length $srcfile] - 3}]]
> +set test "tab complete break $subsrc"
> +send_gdb "break $subsrc\t\t"
> +gdb_test_multiple "" $test {
> + -re "break\.c.*break1\.c.*$gdb_prompt " {
> + send_gdb "1\t\n"
> + gdb_test_multiple "" $test {
> + -re ".*Function \"$srcfile2\" not defined\..*$gdb_prompt " {
> + pass $test
> + }
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> + }
> + }
> +
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> +}
> +
> +gdb_test "complete break $subsrc" "break\.c.*break1\.c"
> +
> +# gdb/17960
> +set test "tab complete break $srcfile:ma"
> +send_gdb "break $srcfile:ma\t"
> +gdb_test_multiple "" $test {
> + -re "break $srcfile:main " {
> + send_gdb "\n"
> + gdb_test_multiple "" $test {
> + -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
> + pass $test
> + gdb_test_no_output "delete breakpoint \$bpnum" \
> + "delete breakpoint for $test"
> + }
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> + }
> + }
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> +}
> +
> +gdb_test "complete break $srcfile:ma" "break\.c:main"
> +
> +set test "tab complete break need"
> +send_gdb "break need\t"
> +gdb_test_multiple "" $test {
> + -re "break need_malloc " {
> + send_gdb "\n"
> + gdb_test_multiple "" $test {
> + -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
> + pass $test
> + gdb_test_no_output "delete breakpoint \$bpnum" \
> + "delete breakpoint for $test"
> + }
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> + }
> + }
> + -re "$gdb_prompt p$" {
> + fail $test
> + }
> +}
> +
> +gdb_test "complete break need" "need_malloc"
> +
> +#
> # Completion limiting.
> #
>
> diff --git a/gdb/top.c b/gdb/top.c
> index 8242e12..af5d923 100644
> --- a/gdb/top.c
> +++ b/gdb/top.c
> @@ -1673,7 +1673,7 @@ set_verbose (char *args, int from_tty, struct cmd_list_element *c)
> const char *cmdname = "verbose";
> struct cmd_list_element *showcmd;
>
> - showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
> + showcmd = lookup_cmd_1 (NULL, &cmdname, showlist, NULL, 1);
> gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
>
> if (info_verbose)
@@ -6191,7 +6191,8 @@ ada_complete_symbol_matcher (const char *name, void *user_data)
the entire command on which completion is made. */
static VEC (char_ptr) *
-ada_make_symbol_completion_list (const char *text0, const char *word,
+ada_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text0, const char *word,
enum type_code code)
{
char *text;
@@ -1020,6 +1020,7 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
static VEC (char_ptr) *
condition_completer (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
const char *space;
@@ -1058,7 +1059,7 @@ condition_completer (struct cmd_list_element *cmd,
/* We're completing the expression part. */
text = skip_spaces_const (space);
- return expression_completer (cmd, text, word);
+ return expression_completer (cmd, tracker, text, word);
}
/* condition N EXP -- set break condition of breakpoint N to EXP. */
@@ -15393,11 +15394,12 @@ catching_syscall_number (int syscall_number)
/* Complete syscall names. Used by "catch syscall". */
static VEC (char_ptr) *
catch_syscall_completer (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
const char **list = get_syscall_names (get_current_arch ());
VEC (char_ptr) *retlist
- = (list == NULL) ? NULL : complete_on_enum (list, word, word);
+ = (list == NULL) ? NULL : complete_on_enum (tracker, list, word, word);
xfree (list);
return retlist;
@@ -1344,7 +1344,7 @@ valid_command_p (const char *command)
{
struct cmd_list_element *c;
- c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
+ c = lookup_cmd_1 (NULL, &command, cmdlist, NULL, 1);
if (c == NULL || c == (struct cmd_list_element *) -1)
return FALSE;
@@ -1467,12 +1467,12 @@ alias_command (char *args, int from_tty)
alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
command_prefix = dyn_string_buf (command_prefix_dyn_string);
- c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
+ c_command = lookup_cmd_1 (NULL, &command_prefix, cmdlist, NULL, 1);
/* We've already tried to look up COMMAND. */
gdb_assert (c_command != NULL
&& c_command != (struct cmd_list_element *) -1);
gdb_assert (c_command->prefixlist != NULL);
- c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
+ c_alias = lookup_cmd_1 (NULL, &alias_prefix, cmdlist, NULL, 1);
if (c_alias != c_command)
error (_("ALIAS and COMMAND prefixes do not match."));
@@ -35,7 +35,8 @@ static struct cmd_list_element *delete_cmd (const char *name,
struct cmd_list_element **posthook,
struct cmd_list_element **posthookee);
-static struct cmd_list_element *find_cmd (const char *command,
+static struct cmd_list_element *find_cmd (completion_tracker_t tracker,
+ const char *command,
int len,
struct cmd_list_element *clist,
int ignore_help_classes,
@@ -649,6 +650,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class class,
static VEC (char_ptr) *
integer_unlimited_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char * const keywords[] =
@@ -657,7 +659,7 @@ integer_unlimited_completer (struct cmd_list_element *ignore,
NULL,
};
- return complete_on_enum (keywords, text, word);
+ return complete_on_enum (tracker, keywords, text, word);
}
/* Add element named NAME to both the set and show command LISTs (the
@@ -1215,22 +1217,43 @@ help_cmd_list (struct cmd_list_element *list, enum command_class class,
found in nfound. */
static struct cmd_list_element *
-find_cmd (const char *command, int len, struct cmd_list_element *clist,
+find_cmd (completion_tracker_t tracker,
+ const char *command, int len, struct cmd_list_element *clist,
int ignore_help_classes, int *nfound)
{
struct cmd_list_element *found, *c;
+ int max_reached;
found = (struct cmd_list_element *) NULL;
*nfound = 0;
- for (c = clist; c; c = c->next)
+ for (c = clist, max_reached = 0; c; c = c->next)
if (!strncmp (command, c->name, len)
&& (!ignore_help_classes || c->func))
{
- found = c;
- (*nfound)++;
- if (c->name[len] == '\0')
+ enum maybe_add_completion_enum add_status;
+
+ add_status = (tracker == NULL
+ ? MAYBE_ADD_COMPLETION_OK
+ : maybe_add_completion (tracker, c->name));
+ switch (add_status)
{
- *nfound = 1;
+ case MAYBE_ADD_COMPLETION_OK:
+ found = c;
+ (*nfound)++;
+ if (c->name[len] == '\0')
+ {
+ *nfound = 1;
+ return found;
+ }
+ break;
+ case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
+ found = c;
+ (*nfound)++;
+ return found;
+ case MAYBE_ADD_COMPLETION_MAX_REACHED:
+ return found;
+ case MAYBE_ADD_COMPLETION_DUPLICATE:
+ continue;
break;
}
}
@@ -1336,7 +1359,8 @@ valid_user_defined_cmd_name_p (const char *name)
the struct cmd_list_element is NULL). */
struct cmd_list_element *
-lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
+lookup_cmd_1 (completion_tracker_t tracker,
+ const char **text, struct cmd_list_element *clist,
struct cmd_list_element **result_list, int ignore_help_classes)
{
char *command;
@@ -1365,7 +1389,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
/* Look it up. */
found = 0;
nfound = 0;
- found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+ found = find_cmd (tracker, command, len, clist, ignore_help_classes,
+ &nfound);
/* We didn't find the command in the entered case, so lower case it
and search again. */
@@ -1377,7 +1402,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
command[tmp] = isupper (x) ? tolower (x) : x;
}
- found = find_cmd (command, len, clist, ignore_help_classes, &nfound);
+ found = find_cmd (tracker, command, len, clist, ignore_help_classes,
+ &nfound);
}
/* If nothing matches, we have a simple failure. */
@@ -1414,7 +1440,7 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
if (found->prefixlist)
{
- c = lookup_cmd_1 (text, *found->prefixlist, result_list,
+ c = lookup_cmd_1 (tracker, text, *found->prefixlist, result_list,
ignore_help_classes);
if (!c)
{
@@ -1491,7 +1517,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list, char *cmdtype,
if (!*line)
error (_("Lack of needed %scommand"), cmdtype);
- c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+ c = lookup_cmd_1 (NULL, line, list, &last_list, ignore_help_classes);
if (!c)
{
@@ -1718,7 +1744,7 @@ lookup_cmd_composition (const char *text,
/* Look it up. */
*cmd = 0;
nfound = 0;
- *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+ *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
/* We didn't find the command in the entered case, so lower case
it and search again.
@@ -1731,7 +1757,7 @@ lookup_cmd_composition (const char *text,
command[tmp] = isupper (x) ? tolower (x) : x;
}
- *cmd = find_cmd (command, len, cur_list, 1, &nfound);
+ *cmd = find_cmd (NULL, command, len, cur_list, 1, &nfound);
}
if (*cmd == CMD_LIST_AMBIGUOUS)
@@ -1842,7 +1868,7 @@ complete_on_cmdlist (struct cmd_list_element *list,
"oobar"; if WORD is "baz/foo", return "baz/foobar". */
VEC (char_ptr) *
-complete_on_enum (const char *const *enumlist,
+complete_on_enum (completion_tracker_t ignore, const char *const *enumlist,
const char *text, const char *word)
{
VEC (char_ptr) *matchlist = NULL;
@@ -23,6 +23,7 @@
/* Include the public interfaces. */
#include "command.h"
+#include "completer.h"
struct re_pattern_buffer;
@@ -156,19 +156,6 @@ typedef void cmd_sfunc_ftype (char *args, int from_tty,
extern void set_cmd_sfunc (struct cmd_list_element *cmd,
cmd_sfunc_ftype *sfunc);
-typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
- const char *, const char *);
-
-typedef void completer_ftype_void (struct cmd_list_element *,
- const char *, const char *);
-
-extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
-
-/* Set the completer_handle_brkchars callback. */
-
-extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
- completer_ftype_void *);
-
/* HACK: cagney/2002-02-23: Code, mostly in tracepoints.c, grubs
around in cmd objects to test the value of the commands sfunc(). */
extern int cmd_cfunc_eq (struct cmd_list_element *cmd,
@@ -189,18 +176,6 @@ extern void execute_cmd_post_hook (struct cmd_list_element *cmd);
/* Return the type of the command. */
extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
-/* Flag for an ambiguous cmd_list result. */
-#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
-
-extern struct cmd_list_element *lookup_cmd (const char **,
- struct cmd_list_element *, char *,
- int, int);
-
-extern struct cmd_list_element *lookup_cmd_1 (const char **,
- struct cmd_list_element *,
- struct cmd_list_element **,
- int);
-
extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
const char * );
@@ -225,12 +200,6 @@ extern struct cmd_list_element *add_info (const char *,
extern struct cmd_list_element *add_info_alias (const char *, const char *,
int);
-extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
- const char *, const char *, int);
-
-extern VEC (char_ptr) *complete_on_enum (const char *const *enumlist,
- const char *, const char *);
-
/* Functions that implement commands about CLI commands. */
extern void help_list (struct cmd_list_element *, const char *,
@@ -107,7 +107,8 @@ readline_line_completion_function (const char *text, int matches)
/* This can be used for functions which don't want to complete on
symbols but don't want to complete on anything else either. */
VEC (char_ptr) *
-noop_completer (struct cmd_list_element *ignore,
+noop_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *prefix)
{
return NULL;
@@ -115,7 +116,8 @@ noop_completer (struct cmd_list_element *ignore,
/* Complete on filenames. */
VEC (char_ptr) *
-filename_completer (struct cmd_list_element *ignore,
+filename_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *word)
{
int subsequent_name;
@@ -184,7 +186,8 @@ filename_completer (struct cmd_list_element *ignore,
etc. */
VEC (char_ptr) *
-location_completer (struct cmd_list_element *ignore,
+location_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
int n_syms, n_files, ix;
@@ -260,18 +263,41 @@ location_completer (struct cmd_list_element *ignore,
symbols as well as on files. */
if (colon)
{
- list = make_file_symbol_completion_list (symbol_start, word,
- file_to_match);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_file_symbol_completion_list (tracker, symbol_start,
+ word, file_to_match);
+ }
+ if (e.reason < 0)
+ list = NULL;
xfree (file_to_match);
}
else
{
- list = make_symbol_completion_list (symbol_start, word);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_symbol_completion_list (tracker, symbol_start, word);
+ }
+ if (e.reason < 0)
+ list = NULL;
+
/* 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);
+ {
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ fn_list = make_source_files_completion_list (tracker, text,
+ text);
+ }
+ if (e.reason < 0)
+ fn_list = NULL;
+ }
}
n_syms = VEC_length (char_ptr, list);
@@ -326,7 +352,14 @@ location_completer (struct cmd_list_element *ignore,
{
/* 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);
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ list = make_symbol_completion_list (tracker, orig_text, word);
+ }
+ if (e.reason < 0)
+ list = NULL;
}
return list;
@@ -389,7 +422,8 @@ add_struct_fields (struct type *type, VEC (char_ptr) **output,
names, but some language parsers also have support for completing
field names. */
VEC (char_ptr) *
-expression_completer (struct cmd_list_element *ignore,
+expression_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
struct type *type = NULL;
@@ -434,7 +468,8 @@ expression_completer (struct cmd_list_element *ignore,
VEC (char_ptr) *result;
struct cleanup *cleanup = make_cleanup (xfree, fieldname);
- result = make_symbol_completion_type (fieldname, fieldname, code);
+ result = make_symbol_completion_type (tracker, fieldname, fieldname,
+ code);
do_cleanups (cleanup);
return result;
}
@@ -448,7 +483,7 @@ expression_completer (struct cmd_list_element *ignore,
;
/* Not ideal but it is what we used to do before... */
- return location_completer (ignore, p, word);
+ return location_completer (ignore, tracker, p, word);
}
/* See definition in completer.h. */
@@ -526,7 +561,7 @@ complete_line_internal_reason;
*/
static VEC (char_ptr) *
-complete_line_internal (const char *text,
+complete_line_internal (completion_tracker_t tracker, const char *text,
const char *line_buffer, int point,
complete_line_internal_reason reason)
{
@@ -572,7 +607,21 @@ complete_line_internal (const char *text,
}
else
{
- c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
+ /* There are two possible scenarios:
+ 1) The user is searching for completions to a command
+ 2) The user is attempting to complete the argument of
+ a specific command.
+
+ In either case, lookup_cmd_1 will increment the tracker.
+ However, for case #2, the tracker's results must be cleared,
+ since we don't want the actual command lookup to be counted
+ by that command's completer function. If we didn't do this,
+ we'd end up with an off-by-one error between the tracker
+ and the returned completion list. */
+ c = lookup_cmd_1 (tracker, &p, cmdlist, &result_list,
+ ignore_help_classes);
+ if (c != CMD_LIST_AMBIGUOUS && tracker != NULL)
+ htab_empty (tracker);
}
/* Move p up to the next interesting thing. */
@@ -658,7 +707,7 @@ complete_line_internal (const char *text,
else if (c->enums)
{
if (reason != handle_brkchars)
- list = complete_on_enum (c->enums, p, word);
+ list = complete_on_enum (tracker, c->enums, p, word);
rl_completer_word_break_characters =
gdb_completer_command_word_break_characters;
}
@@ -698,7 +747,7 @@ complete_line_internal (const char *text,
&& c->completer_handle_brkchars != NULL)
(*c->completer_handle_brkchars) (c, p, word);
if (reason != handle_brkchars && c->completer != NULL)
- list = (*c->completer) (c, p, word);
+ list = (*c->completer) (c, tracker, p, word);
}
}
else
@@ -744,7 +793,7 @@ complete_line_internal (const char *text,
else if (c->enums)
{
if (reason != handle_brkchars)
- list = complete_on_enum (c->enums, p, word);
+ list = complete_on_enum (tracker, c->enums, p, word);
}
else
{
@@ -774,7 +823,7 @@ complete_line_internal (const char *text,
&& c->completer_handle_brkchars != NULL)
(*c->completer_handle_brkchars) (c, p, word);
if (reason != handle_brkchars && c->completer != NULL)
- list = (*c->completer) (c, p, word);
+ list = (*c->completer) (c, tracker, p, word);
}
}
}
@@ -825,7 +874,7 @@ make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
/* See completer.h. */
enum maybe_add_completion_enum
-maybe_add_completion (completion_tracker_t tracker, char *name)
+maybe_add_completion (completion_tracker_t tracker, const char *name)
{
void **slot;
@@ -844,7 +893,7 @@ maybe_add_completion (completion_tracker_t tracker, char *name)
if (*slot != HTAB_EMPTY_ENTRY)
return MAYBE_ADD_COMPLETION_DUPLICATE;
- *slot = name;
+ *slot = (void *) name;
return (htab_elements (tracker) < max_completions
? MAYBE_ADD_COMPLETION_OK
@@ -875,52 +924,75 @@ complete_line (const char *text, const char *line_buffer, int point)
{
VEC (char_ptr) *list;
VEC (char_ptr) *result = NULL;
- struct cleanup *cleanups;
+ struct cleanup *tracker_cleanup, *cleanups;
completion_tracker_t tracker;
char *candidate;
int ix, max_reached;
if (max_completions == 0)
return NULL;
- list = complete_line_internal (text, line_buffer, point,
- handle_completions);
- if (max_completions < 0)
- return list;
tracker = new_completion_tracker ();
cleanups = make_cleanup_free_completion_tracker (&tracker);
- make_cleanup_free_char_ptr_vec (list);
- /* Do a final test for too many completions. Individual completers may
- do some of this, but are not required to. Duplicates are also removed
- here. Otherwise the user is left scratching his/her head: readline and
- complete_command will remove duplicates, and if removal of duplicates
- there brings the total under max_completions the user may think gdb quit
- searching too early. */
+ list = complete_line_internal (tracker, text, line_buffer, point,
+ handle_completions);
- for (ix = 0, max_reached = 0;
- !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
- ++ix)
+ if (max_completions < 0)
{
- enum maybe_add_completion_enum add_status;
+ do_cleanups (cleanups);
+ return list;
+ }
+
+ make_cleanup_free_char_ptr_vec (list);
+
+ /* If complete_line_internal returned more completions than were
+ recorded by the completion tracker, then the completer function that
+ was run does not support completion tracking. In this case,
+ do a final test for too many completions.
- add_status = maybe_add_completion (tracker, candidate);
+ Duplicates are also removed here. Otherwise the user is left
+ scratching his/her head: readline and complete_command will remove
+ duplicates, and if removal of duplicates there brings the total under
+ max_completions the user may think gdb quit searching too early. */
- switch (add_status)
+ if (VEC_length (char_ptr, list) > htab_elements (tracker))
+ {
+ /* Clear the tracker so that we can re-use it to count the number
+ of returned completions. */
+ htab_empty (tracker);
+
+ for (ix = 0, max_reached = 0;
+ !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
+ ++ix)
{
- case MAYBE_ADD_COMPLETION_OK:
- VEC_safe_push (char_ptr, result, xstrdup (candidate));
- break;
- case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
- VEC_safe_push (char_ptr, result, xstrdup (candidate));
- max_reached = 1;
- break;
- case MAYBE_ADD_COMPLETION_MAX_REACHED:
- gdb_assert_not_reached ("more than max completions reached");
- case MAYBE_ADD_COMPLETION_DUPLICATE:
- break;
+ enum maybe_add_completion_enum add_status;
+
+ add_status = maybe_add_completion (tracker, candidate);
+
+ switch (add_status)
+ {
+ case MAYBE_ADD_COMPLETION_OK:
+ VEC_safe_push (char_ptr, result, xstrdup (candidate));
+ break;
+ case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
+ VEC_safe_push (char_ptr, result, xstrdup (candidate));
+ max_reached = 1;
+ break;
+ case MAYBE_ADD_COMPLETION_MAX_REACHED:
+ gdb_assert_not_reached ("more than max completions reached");
+ case MAYBE_ADD_COMPLETION_DUPLICATE:
+ break;
+ }
}
}
+ else
+ {
+ /* There is a valid tracker for the completion -- simply copy
+ the returned list into the return result. */
+ for (ix = 0; VEC_iterate (char_ptr, list, ix, candidate); ++ix)
+ VEC_safe_push (char_ptr, result, xstrdup (candidate));
+ }
do_cleanups (cleanups);
@@ -929,10 +1001,11 @@ complete_line (const char *text, const char *line_buffer, int point)
/* Complete on command names. Used by "help". */
VEC (char_ptr) *
-command_completer (struct cmd_list_element *ignore,
+command_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
- return complete_line_internal (word, text,
+ return complete_line_internal (tracker, word, text,
strlen (text), handle_help);
}
@@ -940,6 +1013,7 @@ command_completer (struct cmd_list_element *ignore,
VEC (char_ptr) *
signal_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ignore2,
const char *text, const char *word)
{
VEC (char_ptr) *return_val = NULL;
@@ -970,6 +1044,7 @@ signal_completer (struct cmd_list_element *ignore,
VEC (char_ptr) *
reg_or_group_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ingore2,
const char *text, const char *word)
{
VEC (char_ptr) *result = NULL;
@@ -1013,7 +1088,7 @@ gdb_completion_word_break_characters (void)
{
VEC (char_ptr) *list;
- list = complete_line_internal (rl_line_buffer, rl_line_buffer, rl_point,
+ list = complete_line_internal (NULL, rl_line_buffer, rl_line_buffer, rl_point,
handle_brkchars);
gdb_assert (list == NULL);
return rl_completer_word_break_characters;
@@ -18,7 +18,6 @@
#define COMPLETER_H 1
#include "gdb_vecs.h"
-#include "command.h"
/* Types of functions in struct match_list_displayer. */
@@ -33,6 +32,70 @@ typedef void mld_erase_entire_line_ftype (const struct match_list_displayer *);
typedef void mld_beep_ftype (const struct match_list_displayer *);
typedef int mld_read_key_ftype (const struct match_list_displayer *);
+/* Maximum number of candidates to consider before the completer
+ bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
+ disable limiting. */
+
+extern int max_completions;
+
+/* Object to track how many unique completions have been generated.
+ Used to limit the size of generated completion lists. */
+
+typedef htab_t completion_tracker_t;
+
+/* Create a new completion tracker.
+ The result is a hash table to track added completions, or NULL
+ if max_completions <= 0. If max_completions < 0, tracking is disabled.
+ If max_completions == 0, the max is indeed zero. */
+
+extern completion_tracker_t new_completion_tracker (void);
+
+/* Make a cleanup to free a completion tracker, and reset its pointer
+ to NULL. */
+
+extern struct cleanup *make_cleanup_free_completion_tracker
+ (completion_tracker_t *tracker_ptr);
+
+/* Return values for maybe_add_completion. */
+
+enum maybe_add_completion_enum
+{
+ /* NAME has been recorded and max_completions has not been reached,
+ or completion tracking is disabled (max_completions < 0). */
+ MAYBE_ADD_COMPLETION_OK,
+
+ /* NAME has been recorded and max_completions has been reached
+ (thus the caller can stop searching). */
+ MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
+
+ /* max-completions entries has been reached.
+ Whether NAME is a duplicate or not is not determined. */
+ MAYBE_ADD_COMPLETION_MAX_REACHED,
+
+ /* NAME has already been recorded.
+ Note that this is never returned if completion tracking is disabled
+ (max_completions < 0). */
+ MAYBE_ADD_COMPLETION_DUPLICATE
+};
+
+/* Add the completion NAME to the list of generated completions if
+ it is not there already.
+ If max_completions is negative, nothing is done, not even watching
+ for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
+
+ If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
+ record at least one more completion. The final list will be pruned to
+ max_completions, but recording at least one more than max_completions is
+ the signal to the completion machinery that too many completions were
+ found. */
+
+extern enum maybe_add_completion_enum
+ maybe_add_completion (completion_tracker_t tracker, const char *name);
+
+/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
+
+extern void throw_max_completions_reached_error (void);
+
/* Interface between CLI/TUI and gdb_match_list_displayer. */
struct match_list_displayer
@@ -76,106 +139,83 @@ extern char *readline_line_completion_function (const char *text,
int matches);
extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
+ completion_tracker_t,
const char *, const char *);
extern char *get_gdb_completer_quote_characters (void);
extern char *gdb_completion_word_break_characters (void);
-/* Set the word break characters array to the corresponding set of
- chars, based on FN. This function is useful for cases when the
- completer doesn't know the type of the completion until some
- calculation is done (e.g., for Python functions). */
-
-extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
-
-/* Exported to linespec.c */
-
-extern const char *skip_quoted_chars (const char *, const char *,
- const char *);
-
-extern const char *skip_quoted (const char *);
-
-/* Maximum number of candidates to consider before the completer
- bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
- disable limiting. */
-
-extern int max_completions;
-
-/* Object to track how many unique completions have been generated.
- Used to limit the size of generated completion lists. */
+typedef VEC (char_ptr) *completer_ftype (struct cmd_list_element *,
+ completion_tracker_t,
+ const char *, const char *);
-typedef htab_t completion_tracker_t;
+typedef void completer_ftype_void (struct cmd_list_element *,
+ const char *, const char *);
-/* Create a new completion tracker.
- The result is a hash table to track added completions, or NULL
- if max_completions <= 0. If max_completions < 0, tracking is disabled.
- If max_completions == 0, the max is indeed zero. */
+extern void set_cmd_completer (struct cmd_list_element *, completer_ftype *);
-extern completion_tracker_t new_completion_tracker (void);
+/* Set the completer_handle_brkchars callback. */
-/* Make a cleanup to free a completion tracker, and reset its pointer
- to NULL. */
+extern void set_cmd_completer_handle_brkchars (struct cmd_list_element *,
+ completer_ftype_void *);
-extern struct cleanup *make_cleanup_free_completion_tracker
- (completion_tracker_t *tracker_ptr);
-
-/* Return values for maybe_add_completion. */
+/* Set the word break characters array to the corresponding set of
+ chars, based on FN. This function is useful for cases when the
+ completer doesn't know the type of the completion until some
+ calculation is done (e.g., for Python functions). */
-enum maybe_add_completion_enum
-{
- /* NAME has been recorded and max_completions has not been reached,
- or completion tracking is disabled (max_completions < 0). */
- MAYBE_ADD_COMPLETION_OK,
+extern void set_gdb_completion_word_break_characters (completer_ftype *fn);
- /* NAME has been recorded and max_completions has been reached
- (thus the caller can stop searching). */
- MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
+extern VEC (char_ptr) *complete_on_cmdlist (struct cmd_list_element *,
+ const char *, const char *, int);
- /* max-completions entries has been reached.
- Whether NAME is a duplicate or not is not determined. */
- MAYBE_ADD_COMPLETION_MAX_REACHED,
+extern VEC (char_ptr) *complete_on_enum (completion_tracker_t,
+ const char *const *enumlist,
+ const char *, const char *);
- /* NAME has already been recorded.
- Note that this is never returned if completion tracking is disabled
- (max_completions < 0). */
- MAYBE_ADD_COMPLETION_DUPLICATE
-};
+/* Flag for an ambiguous cmd_list result. */
+#define CMD_LIST_AMBIGUOUS ((struct cmd_list_element *) -1)
-/* Add the completion NAME to the list of generated completions if
- it is not there already.
- If max_completions is negative, nothing is done, not even watching
- for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
+extern struct cmd_list_element *lookup_cmd (const char **,
+ struct cmd_list_element *, char *,
+ int, int);
- If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
- record at least one more completion. The final list will be pruned to
- max_completions, but recording at least one more than max_completions is
- the signal to the completion machinery that too many completions were
- found. */
+extern struct cmd_list_element *lookup_cmd_1 (completion_tracker_t,
+ const char **,
+ struct cmd_list_element *,
+ struct cmd_list_element **,
+ int);
-extern enum maybe_add_completion_enum
- maybe_add_completion (completion_tracker_t tracker, char *name);
+/* Exported to linespec.c */
-/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
+extern const char *skip_quoted_chars (const char *, const char *,
+ const char *);
-extern void throw_max_completions_reached_error (void);
+extern const char *skip_quoted (const char *);
#endif /* defined (COMPLETER_H) */
@@ -469,6 +469,7 @@ set_gnutarget_command (char *ignore, int from_tty,
static VEC (char_ptr) *
complete_set_gnutarget (struct cmd_list_element *cmd,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char **bfd_targets;
@@ -486,7 +487,7 @@ complete_set_gnutarget (struct cmd_list_element *cmd,
bfd_targets[last + 1] = NULL;
}
- return complete_on_enum (bfd_targets, text, word);
+ return complete_on_enum (tracker, bfd_targets, text, word);
}
/* Set the gnutarget. */
@@ -355,6 +355,7 @@ set_cp_abi_cmd (char *args, int from_tty)
static VEC (char_ptr) *
cp_abi_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
static const char **cp_abi_names;
@@ -369,7 +370,7 @@ cp_abi_completer (struct cmd_list_element *ignore,
cp_abi_names[i] = NULL;
}
- return complete_on_enum (cp_abi_names, text, word);
+ return complete_on_enum (tracker, cp_abi_names, text, word);
}
/* Show the currently selected C++ ABI. */
@@ -229,10 +229,12 @@ f_word_break_characters (void)
class. */
static VEC (char_ptr) *
-f_make_symbol_completion_list (const char *text, const char *word,
+f_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
enum type_code code)
{
- return default_make_symbol_completion_list_break_on (text, word, ":", code);
+ return default_make_symbol_completion_list_break_on (tracker, text, word,
+ ":", code);
}
const struct language_defn f_language_defn =
@@ -6934,6 +6934,7 @@ Are you sure you want to change it? "),
static VEC (char_ptr) *
handle_completer (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
@@ -6951,8 +6952,8 @@ handle_completer (struct cmd_list_element *ignore,
NULL,
};
- vec_signals = signal_completer (ignore, text, word);
- vec_keywords = complete_on_enum (keywords, word, word);
+ vec_signals = signal_completer (ignore, tracker, text, word);
+ vec_keywords = complete_on_enum (tracker, keywords, word, word);
return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
VEC_free (char_ptr, vec_signals);
@@ -438,6 +438,7 @@ interpreter_exec_cmd (char *args, int from_tty)
/* List the possible interpreters which could complete the given text. */
static VEC (char_ptr) *
interpreter_completer (struct cmd_list_element *ignore,
+ completion_tracker_t ingore2,
const char *text, const char *word)
{
int textlen;
@@ -301,7 +301,8 @@ struct language_defn
completion is being made. If CODE is TYPE_CODE_UNDEF, then all
symbols should be examined; otherwise, only STRUCT_DOMAIN
symbols whose type has a code of CODE should be matched. */
- VEC (char_ptr) *(*la_make_symbol_completion_list) (const char *text,
+ VEC (char_ptr) *(*la_make_symbol_completion_list) (completion_tracker_t,
+ const char *text,
const char *word,
enum type_code code);
@@ -347,6 +347,7 @@ cmdpy_completer_handle_brkchars (struct cmd_list_element *command,
static VEC (char_ptr) *
cmdpy_completer (struct cmd_list_element *command,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
PyObject *resultobj = NULL;
@@ -378,7 +379,7 @@ cmdpy_completer (struct cmd_list_element *command,
PyErr_Clear ();
}
else if (value >= 0 && value < (long) N_COMPLETERS)
- result = completers[value].completer (command, text, word);
+ result = completers[value].completer (command, tracker, text, word);
}
else
{
@@ -485,7 +486,7 @@ gdbpy_parse_command_name (const char *name,
prefix_text[i + 1] = '\0';
prefix_text2 = prefix_text;
- elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
+ elt = lookup_cmd_1 (NULL, &prefix_text2, *start_list, NULL, 1);
if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
{
PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
@@ -4994,29 +4994,21 @@ do_free_completion_list (void *list)
static VEC (char_ptr) *return_val;
-#define COMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
- completion_list_add_name \
- (SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
+#define COMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
+ completion_list_add_name \
+ (tracker, SYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
-#define MCOMPLETION_LIST_ADD_SYMBOL(symbol, sym_text, len, text, word) \
- completion_list_add_name \
- (MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
-
-/* Tracker for how many unique completions have been generated. Used
- to terminate completion list generation early if the list has grown
- to a size so large as to be useless. This helps avoid GDB seeming
- to lock up in the event the user requests to complete on something
- vague that necessitates the time consuming expansion of many symbol
- tables. */
-
-static completion_tracker_t completion_tracker;
+#define MCOMPLETION_LIST_ADD_SYMBOL(tracker, symbol, sym_text, len, text, word) \
+ completion_list_add_name \
+ ((tracker), MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
/* Test to see if the symbol specified by SYMNAME (which is already
demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
characters. If so, add it to the current completion list. */
static void
-completion_list_add_name (const char *symname,
+completion_list_add_name (completion_tracker_t tracker,
+ const char *symname,
const char *sym_text, int sym_text_len,
const char *text, const char *word)
{
@@ -5051,7 +5043,7 @@ completion_list_add_name (const char *symname,
strcat (new, symname);
}
- add_status = maybe_add_completion (completion_tracker, new);
+ add_status = maybe_add_completion (tracker, new);
switch (add_status)
{
@@ -5075,7 +5067,8 @@ completion_list_add_name (const char *symname,
again and feed all the selectors into the mill. */
static void
-completion_list_objc_symbol (struct minimal_symbol *msymbol,
+completion_list_objc_symbol (completion_tracker_t tracker,
+ struct minimal_symbol *msymbol,
const char *sym_text, int sym_text_len,
const char *text, const char *word)
{
@@ -5093,7 +5086,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
if (sym_text[0] == '[')
/* Complete on shortened method method. */
- completion_list_add_name (method + 1, sym_text, sym_text_len, text, word);
+ completion_list_add_name (tracker, method + 1, sym_text, sym_text_len,
+ text, word);
while ((strlen (method) + 1) >= tmplen)
{
@@ -5114,9 +5108,11 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
memcpy (tmp, method, (category - method));
tmp[category - method] = ' ';
memcpy (tmp + (category - method) + 1, selector, strlen (selector) + 1);
- completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+ completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
+ word);
if (sym_text[0] == '[')
- completion_list_add_name (tmp + 1, sym_text, sym_text_len, text, word);
+ completion_list_add_name (tracker, tmp + 1, sym_text, sym_text_len,
+ text, word);
}
if (selector != NULL)
@@ -5127,7 +5123,8 @@ completion_list_objc_symbol (struct minimal_symbol *msymbol,
if (tmp2 != NULL)
*tmp2 = '\0';
- completion_list_add_name (tmp, sym_text, sym_text_len, text, word);
+ completion_list_add_name (tracker, tmp, sym_text, sym_text_len, text,
+ word);
}
}
@@ -5178,9 +5175,9 @@ language_search_unquoted_string (const char *text, const char *p)
}
static void
-completion_list_add_fields (struct symbol *sym, const char *sym_text,
- int sym_text_len, const char *text,
- const char *word)
+completion_list_add_fields (completion_tracker_t tracker, struct symbol *sym,
+ const char *sym_text, int sym_text_len,
+ const char *text, const char *word)
{
if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
{
@@ -5191,7 +5188,7 @@ completion_list_add_fields (struct symbol *sym, const char *sym_text,
if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
if (TYPE_FIELD_NAME (t, j))
- completion_list_add_name (TYPE_FIELD_NAME (t, j),
+ completion_list_add_name (tracker, TYPE_FIELD_NAME (t, j),
sym_text, sym_text_len, text, word);
}
}
@@ -5206,6 +5203,7 @@ struct add_name_data
int sym_text_len;
const char *text;
const char *word;
+ completion_tracker_t tracker;
/* Extra argument required for add_symtab_completions. */
enum type_code code;
@@ -5221,7 +5219,7 @@ add_macro_name (const char *name, const struct macro_definition *ignore,
{
struct add_name_data *datum = (struct add_name_data *) user_data;
- completion_list_add_name (name,
+ completion_list_add_name (datum->tracker, name,
datum->sym_text, datum->sym_text_len,
datum->text, datum->word);
}
@@ -5240,6 +5238,7 @@ symbol_completion_matcher (const char *name, void *user_data)
static void
add_symtab_completions (struct compunit_symtab *cust,
+ completion_tracker_t tracker,
const char *sym_text, int sym_text_len,
const char *text, const char *word,
enum type_code code)
@@ -5258,7 +5257,7 @@ add_symtab_completions (struct compunit_symtab *cust,
if (code == TYPE_CODE_UNDEF
|| (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
&& TYPE_CODE (SYMBOL_TYPE (sym)) == code))
- COMPLETION_LIST_ADD_SYMBOL (sym,
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym,
sym_text, sym_text_len,
text, word);
}
@@ -5274,14 +5273,15 @@ symtab_expansion_callback (struct compunit_symtab *symtab,
{
struct add_name_data *datum = (struct add_name_data *) user_data;
- add_symtab_completions (symtab,
+ add_symtab_completions (symtab, datum->tracker,
datum->sym_text, datum->sym_text_len,
datum->text, datum->word,
datum->code);
}
static void
-default_make_symbol_completion_list_break_on_1 (const char *text,
+default_make_symbol_completion_list_break_on_1 (completion_tracker_t tracker,
+ const char *text,
const char *word,
const char *break_on,
enum type_code code)
@@ -5302,7 +5302,6 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
/* Length of sym_text. */
int sym_text_len;
struct add_name_data datum;
- struct cleanup *cleanups;
/* Now look for the symbol we are supposed to complete on. */
{
@@ -5373,14 +5372,12 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
}
gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '(');
- completion_tracker = new_completion_tracker ();
- cleanups = make_cleanup_free_completion_tracker (&completion_tracker);
-
datum.sym_text = sym_text;
datum.sym_text_len = sym_text_len;
datum.text = text;
datum.word = word;
datum.code = code;
+ datum.tracker = tracker;
/* At this point scan through the misc symbol vectors and add each
symbol you find to the list. Eventually we want to ignore
@@ -5392,17 +5389,17 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
ALL_MSYMBOLS (objfile, msymbol)
{
QUIT;
- MCOMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text,
- word);
+ MCOMPLETION_LIST_ADD_SYMBOL (tracker, msymbol, sym_text,
+ sym_text_len, text, word);
- completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text,
- word);
+ completion_list_objc_symbol (tracker, msymbol, sym_text,
+ sym_text_len, text, word);
}
}
/* Add completions for all currently loaded symbol tables. */
ALL_COMPUNITS (objfile, cust)
- add_symtab_completions (cust, sym_text, sym_text_len, text, word,
+ add_symtab_completions (cust, tracker, sym_text, sym_text_len, text, word,
code);
/* Look through the partial symtabs for all symbols which begin
@@ -5430,15 +5427,15 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
{
if (code == TYPE_CODE_UNDEF)
{
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
- word);
- completion_list_add_fields (sym, sym_text, sym_text_len, text,
- word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
+ sym_text_len, text, word);
+ completion_list_add_fields (tracker, sym, sym_text,
+ sym_text_len, text, word);
}
else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
&& TYPE_CODE (SYMBOL_TYPE (sym)) == code)
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
- word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text,
+ sym_text_len, text, word);
}
/* Stop when we encounter an enclosing function. Do not stop for
@@ -5455,11 +5452,13 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
{
if (surrounding_static_block != NULL)
ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
- completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
+ completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
+ text, word);
if (surrounding_global_block != NULL)
ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
- completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
+ completion_list_add_fields (tracker, sym, sym_text, sym_text_len,
+ text, word);
}
/* Skip macros if we are completing a struct tag -- arguable but
@@ -5487,12 +5486,11 @@ default_make_symbol_completion_list_break_on_1 (const char *text,
/* User-defined macros are always visible. */
macro_for_each (macro_user_macros, add_macro_name, &datum);
}
-
- do_cleanups (cleanups);
}
VEC (char_ptr) *
-default_make_symbol_completion_list_break_on (const char *text,
+default_make_symbol_completion_list_break_on (completion_tracker_t tracker,
+ const char *text,
const char *word,
const char *break_on,
enum type_code code)
@@ -5505,7 +5503,7 @@ default_make_symbol_completion_list_break_on (const char *text,
TRY_CATCH (except, RETURN_MASK_ERROR)
{
- default_make_symbol_completion_list_break_on_1 (text, word,
+ default_make_symbol_completion_list_break_on_1 (tracker, text, word,
break_on, code);
}
if (except.reason < 0)
@@ -5519,10 +5517,12 @@ default_make_symbol_completion_list_break_on (const char *text,
}
VEC (char_ptr) *
-default_make_symbol_completion_list (const char *text, const char *word,
+default_make_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
enum type_code code)
{
- return default_make_symbol_completion_list_break_on (text, word, "", code);
+ return default_make_symbol_completion_list_break_on (tracker, text, word,
+ "", code);
}
/* Return a vector of all symbols (regardless of class) which begin by
@@ -5530,9 +5530,10 @@ default_make_symbol_completion_list (const char *text, const char *word,
is NULL. */
VEC (char_ptr) *
-make_symbol_completion_list (const char *text, const char *word)
+make_symbol_completion_list (completion_tracker_t tracker, const char *text,
+ const char *word)
{
- return current_language->la_make_symbol_completion_list (text, word,
+ return current_language->la_make_symbol_completion_list (tracker, text, word,
TYPE_CODE_UNDEF);
}
@@ -5540,13 +5541,14 @@ make_symbol_completion_list (const char *text, const char *word)
symbols whose type code is CODE. */
VEC (char_ptr) *
-make_symbol_completion_type (const char *text, const char *word,
- enum type_code code)
+make_symbol_completion_type (completion_tracker_t tracker, const char *text,
+ const char *word, enum type_code code)
{
gdb_assert (code == TYPE_CODE_UNION
|| code == TYPE_CODE_STRUCT
|| code == TYPE_CODE_ENUM);
- return current_language->la_make_symbol_completion_list (text, word, code);
+ return current_language->la_make_symbol_completion_list (tracker, text,
+ word, code);
}
/* Like make_symbol_completion_list, but suitable for use as a
@@ -5554,16 +5556,18 @@ make_symbol_completion_type (const char *text, const char *word,
VEC (char_ptr) *
make_symbol_completion_list_fn (struct cmd_list_element *ignore,
+ completion_tracker_t tracker,
const char *text, const char *word)
{
- return make_symbol_completion_list (text, word);
+ return make_symbol_completion_list (tracker, text, word);
}
/* Like make_symbol_completion_list, but returns a list of symbols
defined in a source file FILE. */
VEC (char_ptr) *
-make_file_symbol_completion_list (const char *text, const char *word,
+make_file_symbol_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word,
const char *srcfile)
{
struct symbol *sym;
@@ -5645,13 +5649,15 @@ make_file_symbol_completion_list (const char *text, const char *word,
b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), GLOBAL_BLOCK);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
+ word);
}
b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), STATIC_BLOCK);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
+ COMPLETION_LIST_ADD_SYMBOL (tracker, sym, sym_text, sym_text_len, text,
+ word);
}
return (return_val);
@@ -5662,11 +5668,13 @@ make_file_symbol_completion_list (const char *text, const char *word,
list as necessary. */
static void
-add_filename_to_list (const char *fname, const char *text, const char *word,
+add_filename_to_list (completion_tracker_t tracker,
+ const char *fname, const char *text, const char *word,
VEC (char_ptr) **list)
{
char *new;
size_t fnlen = strlen (fname);
+ enum maybe_add_completion_enum add_status;
if (word == text)
{
@@ -5688,7 +5696,22 @@ add_filename_to_list (const char *fname, const char *text, const char *word,
new[text - word] = '\0';
strcat (new, fname);
}
- VEC_safe_push (char_ptr, *list, new);
+
+ add_status = maybe_add_completion (tracker, new);
+ switch (add_status)
+ {
+ case MAYBE_ADD_COMPLETION_OK:
+ VEC_safe_push (char_ptr, *list, new);
+ break;
+ case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
+ VEC_safe_push (char_ptr, *list, new);
+ /* fall through */
+ case MAYBE_ADD_COMPLETION_MAX_REACHED:
+ throw_max_completions_reached_error ();
+ break;
+ case MAYBE_ADD_COMPLETION_DUPLICATE:
+ xfree (new);
+ }
}
static int
@@ -5717,6 +5740,7 @@ struct add_partial_filename_data
const char *word;
int text_len;
VEC (char_ptr) **list;
+ completion_tracker_t tracker;
};
/* A callback for map_partial_symbol_filenames. */
@@ -5734,7 +5758,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
{
/* This file matches for a completion; add it to the
current list of matches. */
- add_filename_to_list (filename, data->text, data->word, data->list);
+ add_filename_to_list (data->tracker, filename, data->text, data->word,
+ data->list);
}
else
{
@@ -5743,7 +5768,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
if (base_name != filename
&& !filename_seen (data->filename_seen_cache, base_name, 1)
&& filename_ncmp (base_name, data->text, data->text_len) == 0)
- add_filename_to_list (base_name, data->text, data->word, data->list);
+ add_filename_to_list (data->tracker, base_name, data->text,
+ data->word, data->list);
}
}
@@ -5753,7 +5779,8 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
NULL. */
VEC (char_ptr) *
-make_source_files_completion_list (const char *text, const char *word)
+make_source_files_completion_list (completion_tracker_t tracker,
+ const char *text, const char *word)
{
struct compunit_symtab *cu;
struct symtab *s;
@@ -5783,7 +5810,7 @@ make_source_files_completion_list (const char *text, const char *word)
{
/* This file matches for a completion; add it to the current
list of matches. */
- add_filename_to_list (s->filename, text, word, &list);
+ add_filename_to_list (tracker, s->filename, text, word, &list);
}
else
{
@@ -5795,7 +5822,7 @@ make_source_files_completion_list (const char *text, const char *word)
if (base_name != s->filename
&& !filename_seen (filename_seen_cache, base_name, 1)
&& filename_ncmp (base_name, text, text_len) == 0)
- add_filename_to_list (base_name, text, word, &list);
+ add_filename_to_list (tracker, base_name, text, word, &list);
}
}
@@ -5804,6 +5831,7 @@ make_source_files_completion_list (const char *text, const char *word)
datum.word = word;
datum.text_len = text_len;
datum.list = &list;
+ datum.tracker = tracker;
map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
0 /*need_fullname*/);
@@ -23,6 +23,7 @@
#include "vec.h"
#include "gdb_vecs.h"
#include "gdbtypes.h"
+#include "completer.h"
/* Opaque declarations. */
struct ui_file;
@@ -1444,24 +1445,22 @@ extern void forget_cached_source_info (void);
extern void select_source_symtab (struct symtab *);
extern VEC (char_ptr) *default_make_symbol_completion_list_break_on
- (const char *text, const char *word, const char *break_on,
- enum type_code code);
-extern VEC (char_ptr) *default_make_symbol_completion_list (const char *,
- const char *,
- enum type_code);
-extern VEC (char_ptr) *make_symbol_completion_list (const char *, const char *);
-extern VEC (char_ptr) *make_symbol_completion_type (const char *, const char *,
- enum type_code);
-extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *,
- const char *,
- const char *);
-
-extern VEC (char_ptr) *make_file_symbol_completion_list (const char *,
- const char *,
- const char *);
-
-extern VEC (char_ptr) *make_source_files_completion_list (const char *,
- const char *);
+ (completion_tracker_t tracker, const char *text, const char *word,
+ const char *break_on, enum type_code code);
+extern VEC (char_ptr) *default_make_symbol_completion_list
+ (completion_tracker_t tracker, const char *, const char *, enum type_code);
+extern VEC (char_ptr) *make_symbol_completion_list
+ (completion_tracker_t tracker, const char *, const char *);
+extern VEC (char_ptr) *make_symbol_completion_type
+ (completion_tracker_t, const char *, const char *, enum type_code);
+extern VEC (char_ptr) *make_symbol_completion_list_fn
+ (struct cmd_list_element *, completion_tracker_t, const char *, const char *);
+
+extern VEC (char_ptr) *make_file_symbol_completion_list
+ (completion_tracker_t, const char *, const char *, const char *);
+
+extern VEC (char_ptr) *make_source_files_completion_list
+ (completion_tracker_t, const char *, const char *);
/* symtab.c */
@@ -777,6 +777,84 @@ gdb_test_multiple "" "$test" {
}
#
+# Tests for the location completer
+#
+
+# Turn off pending breakpoint support so that we don't get queried
+# all the time.
+gdb_test_no_output "set breakpoint pending off"
+
+set subsrc [string range $srcfile 0 [expr {[string length $srcfile] - 3}]]
+set test "tab complete break $subsrc"
+send_gdb "break $subsrc\t\t"
+gdb_test_multiple "" $test {
+ -re "break\.c.*break1\.c.*$gdb_prompt " {
+ send_gdb "1\t\n"
+ gdb_test_multiple "" $test {
+ -re ".*Function \"$srcfile2\" not defined\..*$gdb_prompt " {
+ pass $test
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break $subsrc" "break\.c.*break1\.c"
+
+# gdb/17960
+set test "tab complete break $srcfile:ma"
+send_gdb "break $srcfile:ma\t"
+gdb_test_multiple "" $test {
+ -re "break $srcfile:main " {
+ send_gdb "\n"
+ gdb_test_multiple "" $test {
+ -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
+ pass $test
+ gdb_test_no_output "delete breakpoint \$bpnum" \
+ "delete breakpoint for $test"
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break $srcfile:ma" "break\.c:main"
+
+set test "tab complete break need"
+send_gdb "break need\t"
+gdb_test_multiple "" $test {
+ -re "break need_malloc " {
+ send_gdb "\n"
+ gdb_test_multiple "" $test {
+ -re ".*Breakpoint.*at .*/$srcfile, line .*$gdb_prompt " {
+ pass $test
+ gdb_test_no_output "delete breakpoint \$bpnum" \
+ "delete breakpoint for $test"
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+ }
+ }
+ -re "$gdb_prompt p$" {
+ fail $test
+ }
+}
+
+gdb_test "complete break need" "need_malloc"
+
+#
# Completion limiting.
#
@@ -1673,7 +1673,7 @@ set_verbose (char *args, int from_tty, struct cmd_list_element *c)
const char *cmdname = "verbose";
struct cmd_list_element *showcmd;
- showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+ showcmd = lookup_cmd_1 (NULL, &cmdname, showlist, NULL, 1);
gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
if (info_verbose)