#include "target.h"
#include "reggroups.h"
#include "user-regs.h"
+#include "arch-utils.h"
#include "cli/cli-decode.h"
int computed_type_name = 0;
const char *type_name = NULL;
- CHECK_TYPEDEF (type);
+ type = check_typedef (type);
for (i = 0; i < TYPE_NFIELDS (type); ++i)
{
if (i < TYPE_N_BASECLASSES (type))
struct type *type = NULL;
char *fieldname;
const char *p;
- volatile struct gdb_exception except;
enum type_code code = TYPE_CODE_UNDEF;
/* Perform a tentative parse of the expression, to see whether a
field completion is required. */
fieldname = NULL;
- TRY_CATCH (except, RETURN_MASK_ERROR)
+ TRY
{
type = parse_expression_for_completion (text, &fieldname, &code);
}
- if (except.reason < 0)
- return NULL;
+ CATCH (except, RETURN_MASK_ERROR)
+ {
+ return NULL;
+ }
+ END_CATCH
+
if (fieldname && type)
{
for (;;)
{
- CHECK_TYPEDEF (type);
+ type = check_typedef (type);
if (TYPE_CODE (type) != TYPE_CODE_PTR
&& TYPE_CODE (type) != TYPE_CODE_REF)
break;
return list;
}
-/* Generate completions all at once. Returns a vector of strings.
- Each element is allocated with xmalloc. It can also return NULL if
- there are no completions.
+
+/* See completer.h. */
+
+int max_completions = 200;
+
+/* See completer.h. */
+
+completion_tracker_t
+new_completion_tracker (void)
+{
+ if (max_completions <= 0)
+ return NULL;
+
+ return htab_create_alloc (max_completions,
+ htab_hash_string, (htab_eq) streq,
+ NULL, xcalloc, xfree);
+}
+
+/* Cleanup routine to free a completion tracker and reset the pointer
+ to NULL. */
+
+static void
+free_completion_tracker (void *p)
+{
+ completion_tracker_t *tracker_ptr = p;
+
+ htab_delete (*tracker_ptr);
+ *tracker_ptr = NULL;
+}
+
+/* See completer.h. */
+
+struct cleanup *
+make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
+{
+ if (*tracker_ptr == NULL)
+ return make_cleanup (null_cleanup, NULL);
+
+ return make_cleanup (free_completion_tracker, tracker_ptr);
+}
+
+/* See completer.h. */
+
+enum maybe_add_completion_enum
+maybe_add_completion (completion_tracker_t tracker, char *name)
+{
+ void **slot;
+
+ if (max_completions < 0)
+ return MAYBE_ADD_COMPLETION_OK;
+ if (max_completions == 0)
+ return MAYBE_ADD_COMPLETION_MAX_REACHED;
+
+ gdb_assert (tracker != NULL);
+
+ if (htab_elements (tracker) >= max_completions)
+ return MAYBE_ADD_COMPLETION_MAX_REACHED;
+
+ slot = htab_find_slot (tracker, name, INSERT);
+
+ if (*slot != HTAB_EMPTY_ENTRY)
+ return MAYBE_ADD_COMPLETION_DUPLICATE;
+
+ *slot = name;
+
+ return (htab_elements (tracker) < max_completions
+ ? MAYBE_ADD_COMPLETION_OK
+ : MAYBE_ADD_COMPLETION_OK_MAX_REACHED);
+}
+
+void
+throw_max_completions_reached_error (void)
+{
+ throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
+}
+
+/* Generate completions all at once. Returns a vector of unique strings
+ allocated with xmalloc. Returns NULL if there are no completions
+ or if max_completions is 0. If max_completions is non-negative, this will
+ return at most max_completions strings.
TEXT is the caller's idea of the "word" we are looking at.
VEC (char_ptr) *
complete_line (const char *text, const char *line_buffer, int point)
{
- return complete_line_internal (text, line_buffer,
- point, handle_completions);
+ VEC (char_ptr) *list;
+ VEC (char_ptr) *result = NULL;
+ struct 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. */
+
+ for (ix = 0, max_reached = 0;
+ !max_reached && VEC_iterate (char_ptr, list, ix, candidate);
+ ++ix)
+ {
+ 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;
+ }
+ }
+
+ do_cleanups (cleanups);
+
+ return result;
}
/* Complete on command names. Used by "help". */
{
VEC (char_ptr) *return_val = NULL;
size_t len = strlen (word);
- enum gdb_signal signum;
+ int signum;
const char *signame;
for (signum = GDB_SIGNAL_FIRST; signum != GDB_SIGNAL_LAST; ++signum)
if (signum == GDB_SIGNAL_0)
continue;
- signame = gdb_signal_to_name (signum);
+ signame = gdb_signal_to_name ((enum gdb_signal) signum);
/* Ignore the unknown signal case. */
if (!signame || strcmp (signame, "?") == 0)
return return_val;
}
-/* Complete on a register or reggroup. */
+/* Bit-flags for selecting what the register and/or register-group
+ completer should complete on. */
-VEC (char_ptr) *
-reg_or_group_completer (struct cmd_list_element *ignore,
- const char *text, const char *word)
+enum reg_completer_targets
+ {
+ complete_register_names = 0x1,
+ complete_reggroup_names = 0x2
+ };
+
+/* Complete register names and/or reggroup names based on the value passed
+ in TARGETS. At least one bit in TARGETS must be set. */
+
+static VEC (char_ptr) *
+reg_or_group_completer_1 (struct cmd_list_element *ignore,
+ const char *text, const char *word,
+ enum reg_completer_targets targets)
{
VEC (char_ptr) *result = NULL;
size_t len = strlen (word);
struct gdbarch *gdbarch;
- struct reggroup *group;
const char *name;
- int i;
- if (!target_has_registers)
- return result;
+ gdb_assert ((targets & (complete_register_names
+ | complete_reggroup_names)) != 0);
+ gdbarch = get_current_arch ();
- gdbarch = get_frame_arch (get_selected_frame (NULL));
-
- for (i = 0;
- (name = user_reg_map_regnum_to_name (gdbarch, i)) != NULL;
- i++)
+ if ((targets & complete_register_names) != 0)
{
- if (*name != '\0' && strncmp (word, name, len) == 0)
- VEC_safe_push (char_ptr, result, xstrdup (name));
+ int i;
+
+ for (i = 0;
+ (name = user_reg_map_regnum_to_name (gdbarch, i)) != NULL;
+ i++)
+ {
+ if (*name != '\0' && strncmp (word, name, len) == 0)
+ VEC_safe_push (char_ptr, result, xstrdup (name));
+ }
}
- for (group = reggroup_next (gdbarch, NULL);
- group != NULL;
- group = reggroup_next (gdbarch, group))
+ if ((targets & complete_reggroup_names) != 0)
{
- name = reggroup_name (group);
- if (strncmp (word, name, len) == 0)
- VEC_safe_push (char_ptr, result, xstrdup (name));
+ struct reggroup *group;
+
+ for (group = reggroup_next (gdbarch, NULL);
+ group != NULL;
+ group = reggroup_next (gdbarch, group))
+ {
+ name = reggroup_name (group);
+ if (strncmp (word, name, len) == 0)
+ VEC_safe_push (char_ptr, result, xstrdup (name));
+ }
}
return result;
}
+/* Perform completion on register and reggroup names. */
+
+VEC (char_ptr) *
+reg_or_group_completer (struct cmd_list_element *ignore,
+ const char *text, const char *word)
+{
+ return reg_or_group_completer_1 (ignore, text, word,
+ (complete_register_names
+ | complete_reggroup_names));
+}
+
+/* Perform completion on reggroup names. */
+
+VEC (char_ptr) *
+reggroup_completer (struct cmd_list_element *ignore,
+ const char *text, const char *word)
+{
+ return reg_or_group_completer_1 (ignore, text, word,
+ complete_reggroup_names);
+}
/* Get the list of chars that are considered as word breaks
for the current command. */
{
return skip_quoted_chars (str, NULL, NULL);
}
+
+/* Return a message indicating that the maximum number of completions
+ has been reached and that there may be more. */
+
+const char *
+get_max_completions_reached_message (void)
+{
+ return _("*** List may be truncated, max-completions reached. ***");
+}
\f
/* GDB replacement for rl_display_match_list.
Readline doesn't provide a clean interface for TUI(curses).
return displayer->width;
}
+extern int _rl_completion_prefix_display_length;
+extern int _rl_print_completions_horizontally;
+
+EXTERN_C int _rl_qsort_string_compare (const void *, const void *);
+typedef int QSFUNC (const void *, const void *);
+
/* GDB version of readline/complete.c:rl_display_match_list.
- See gdb_display_match_list for a description of MATCHES, LEN, MAX. */
+ See gdb_display_match_list for a description of MATCHES, LEN, MAX.
+ Returns non-zero if all matches are displayed. */
-static void
+static int
gdb_display_match_list_1 (char **matches, int len, int max,
const struct match_list_displayer *displayer)
{
int i, j, k, l, common_length, sind;
char *temp, *t;
int page_completions = displayer->height != INT_MAX && pagination_enabled;
- extern int _rl_completion_prefix_display_length;
- extern int _rl_qsort_string_compare (const void *, const void *);
- extern int _rl_print_completions_horizontally;
- typedef int QSFUNC (const void *, const void *);
/* Find the length of the prefix common to all items: length as displayed
characters (common_length) and as a byte index into the matches (sind) */
{
lines = gdb_display_match_list_pager (lines, displayer);
if (lines < 0)
- return;
+ return 0;
}
}
}
{
lines = gdb_display_match_list_pager (lines, displayer);
if (lines < 0)
- return;
+ return 0;
}
}
else
}
displayer->crlf (displayer);
}
+
+ return 1;
}
/* Utility for displaying completion list matches, used by both CLI and TUI.
MATCHES is the list of strings, in argv format, LEN is the number of
- strings in MATCHES, and MAX is the length of the longest string in MATCHES.
-
- This function handles the LIST_MAYBE_TRUNCATED marker that we add to the
- completion list.
-
- Note: While LIST_MAYBE_TRUNCATED contributes to MAX, it's not long enough
- that we worry about it. */
+ strings in MATCHES, and MAX is the length of the longest string in
+ MATCHES. */
void
gdb_display_match_list (char **matches, int len, int max,
const struct match_list_displayer *displayer)
{
+ /* Readline will never call this if complete_line returned NULL. */
+ gdb_assert (max_completions != 0);
+
+ /* complete_line will never return more than this. */
+ if (max_completions > 0)
+ gdb_assert (len <= max_completions);
+
if (rl_completion_query_items > 0 && len >= rl_completion_query_items)
{
char msg[100];
}
}
- gdb_display_match_list_1 (matches, len, max, displayer);
+ if (gdb_display_match_list_1 (matches, len, max, displayer))
+ {
+ /* Note: MAX_COMPLETIONS may be -1 or zero, but LEN is always > 0. */
+ if (len == max_completions)
+ {
+ /* The maximum number of completions has been reached. Warn the user
+ that there may be more. */
+ const char *message = get_max_completions_reached_message ();
+
+ displayer->puts (displayer, message);
+ displayer->crlf (displayer);
+ }
+ }
+}
+\f
+extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
+
+void
+_initialize_completer (void)
+{
+ add_setshow_zuinteger_unlimited_cmd ("max-completions", no_class,
+ &max_completions, _("\
+Set maximum number of completion candidates."), _("\
+Show maximum number of completion candidates."), _("\
+Use this to limit the number of candidates considered\n\
+during completion. Specifying \"unlimited\" or -1\n\
+disables limiting. Note that setting either no limit or\n\
+a very large limit can make completion slow."),
+ NULL, NULL, &setlist, &showlist);
}