@@ -1781,7 +1781,7 @@ complete_on_cmdlist (struct completer_data *cdata,
commands. If we see no matching commands in the first pass, and
if we did happen to see a matching deprecated command, we do
another loop to collect those. */
- for (pass = 0; matchlist == 0 && pass < 2; ++pass)
+ for (pass = 0; get_completion_count (cdata) == 0 && pass < 2; ++pass)
{
for (ptr = list; ptr; ptr = ptr->next)
if (!strncmp (ptr->name, text, textlen)
@@ -214,6 +214,20 @@ filename_completer (struct completer_data *cdata,
return return_val;
}
+/* A hashtable traversal function to remove leading file name
+ components, as required by rl_complete. See more detailed explanation
+ in location_completer for more. */
+
+static int
+remove_leading_fn_component (void **slot, void *calldata)
+{
+ char *fn = *slot;
+ int offset = *(int *) calldata;
+
+ memmove (fn, fn + offset, strlen (fn) + 1 - offset);
+ return 1;
+}
+
/* Complete on locations, which might be of two possible forms:
file:line
@@ -303,21 +317,25 @@ location_completer (struct completer_data *cdata,
{
list = make_file_symbol_completion_list (cdata, symbol_start, word,
file_to_match);
+ n_syms = get_completion_count (cdata);
+ n_files = 0;
xfree (file_to_match);
}
else
{
list = make_symbol_completion_list (cdata, symbol_start, word);
+ n_syms = get_completion_count (cdata);
+ n_files = 0;
/* 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 (cdata, text, text);
+ {
+ fn_list = make_source_files_completion_list (cdata, text, text);
+ n_files = get_completion_count (cdata) - n_syms;
+ }
}
- n_syms = VEC_length (char_ptr, list);
- n_files = VEC_length (char_ptr, fn_list);
-
/* Catenate fn_list[] onto the end of list[]. */
if (!n_syms)
{
@@ -340,7 +358,7 @@ location_completer (struct completer_data *cdata,
}
else if (n_files)
{
- char *fn;
+ int offset = word - text;
/* If we only have file names as possible completion, we should
bring them in sync with what rl_complete expects. The
@@ -355,13 +373,10 @@ location_completer (struct completer_data *cdata,
the full "/foo/bar" and "/foo/baz" strings. This produces
wrong results when, e.g., there's only one possible
completion, because rl_complete will prepend "/foo/" to each
- candidate completion. The loop below removes that leading
+ candidate completion. The callback below removes that leading
part. */
- for (ix = 0; VEC_iterate (char_ptr, list, ix, fn); ++ix)
- {
- memmove (fn, fn + (word - text),
- strlen (fn) + 1 - (word - text));
- }
+ htab_traverse (cdata->tracker, remove_leading_fn_component,
+ &offset);
}
else if (!n_syms)
{
@@ -857,14 +872,67 @@ new_completer_data (int size)
/* Free the completion data represented by P. */
static void
-free_completer_data (void *p)
+free_completer_data (struct completer_data *cdata)
{
- struct completer_data *cdata = p;
-
htab_delete (cdata->tracker);
xfree (cdata);
}
+/* A hashtable traversal function to free the elements of the table. */
+
+static int
+free_entry_callback (void **slot, void *calldata)
+{
+ char *element = *slot;
+
+ xfree (element);
+ return 1;
+}
+
+/* A cleanup function to free all data associated with the completer_data
+ given by P. */
+
+static void
+free_all_completer_data (void *p)
+{
+ struct completer_data *cdata = p;
+
+ htab_traverse (cdata->tracker, free_entry_callback, NULL);
+ free_completer_data (cdata);
+}
+
+/* A hashtable traversal function to turn the hashtable keys
+ into a vector. */
+
+static int
+vectorize_htab (void **slot, void *calldata)
+{
+ char *element = *slot;
+ VEC (char_ptr) **vector = calldata;
+
+ VEC_safe_push (char_ptr, *vector, element);
+ return 1;
+}
+
+/* See completer.h. */
+
+VEC (char_ptr) *
+get_completion_list (const struct completer_data *cdata)
+{
+ VEC (char_ptr) *result = NULL;
+
+ htab_traverse (cdata->tracker, vectorize_htab, &result);
+ return result;
+}
+
+/* See completer.h. */
+
+size_t
+get_completion_count (const struct completer_data *cdata)
+{
+ return htab_elements (cdata->tracker);
+}
+
/* 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
@@ -881,12 +949,11 @@ maybe_add_completion (struct completer_data *cdata, char *name)
{
void **slot;
- if (max_completions < 0)
- return MAYBE_ADD_COMPLETION_OK;
if (max_completions == 0)
return MAYBE_ADD_COMPLETION_MAX_REACHED;
- if (htab_elements (cdata->tracker) >= max_completions)
+ if (max_completions > 0
+ && htab_elements (cdata->tracker) >= max_completions)
return MAYBE_ADD_COMPLETION_MAX_REACHED;
slot = htab_find_slot (cdata->tracker, name, INSERT);
@@ -896,7 +963,8 @@ maybe_add_completion (struct completer_data *cdata, char *name)
*slot = name;
- return (htab_elements (cdata->tracker) < max_completions
+ return ((max_completions < 0
+ || htab_elements (cdata->tracker) < max_completions)
? MAYBE_ADD_COMPLETION_OK
: MAYBE_ADD_COMPLETION_OK_MAX_REACHED);
}
@@ -961,66 +1029,20 @@ throw_max_completions_reached_error (void)
VEC (char_ptr) *
complete_line (const char *text, const char *line_buffer, int point)
{
- VEC (char_ptr) *list;
- VEC (char_ptr) *result = NULL;
- struct cleanup *cdata_cleanup, *list_cleanup;
- char *candidate;
- int ix;
+ VEC (char_ptr) *result;
+ struct cleanup *cdata_cleanup;
struct completer_data *cdata;
if (max_completions == 0)
return NULL;
cdata = new_completer_data (max_completions);
- cdata_cleanup = make_cleanup (free_completer_data, cdata);
- list = complete_line_internal (cdata, text, line_buffer, point,
- handle_completions);
- if (max_completions < 0)
- {
- do_cleanups (cdata_cleanup);
- return list;
- }
-
- list_cleanup = 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.
-
- 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. */
-
- if (VEC_length (char_ptr, list) > htab_elements (cdata->tracker))
- {
- enum add_completion_status max_reached = ADD_COMPLETION_OK;
-
- /* Clear the tracker so that we can re-use it to count the number
- of returned completions. */
- htab_empty (cdata->tracker);
-
- for (ix = 0; (max_reached == ADD_COMPLETION_OK
- && VEC_iterate (char_ptr, list, ix, candidate)); ++ix)
- {
- max_reached = add_completion (cdata, &result, xstrdup (candidate));
- }
-
- /* The return result has been assembled and the original list from
- complete_line_internal is no longer needed. Free it. */
- do_cleanups (list_cleanup);
- }
- else
- {
- /* There is a valid tracker for the completion -- simply return
- the completed list. */
- discard_cleanups (list_cleanup);
- result = list;
- }
-
- do_cleanups (cdata_cleanup);
-
+ cdata_cleanup = make_cleanup (free_all_completer_data, cdata);
+ complete_line_internal (cdata, text, line_buffer, point,
+ handle_completions);
+ result = get_completion_list (cdata);
+ discard_cleanups (cdata_cleanup);
+ free_completer_data (cdata);
return result;
}
@@ -1123,10 +1145,12 @@ gdb_completion_word_break_characters (void)
struct cleanup *cleanup;
cdata = new_completer_data (max_completions);
- cleanup = make_cleanup (free_completer_data, cdata);
- list = complete_line_internal (cdata, rl_line_buffer, rl_line_buffer,
- rl_point, handle_brkchars);
- do_cleanups (cleanup);
+ cleanup = make_cleanup (free_all_completer_data, cdata);
+ complete_line_internal (cdata, rl_line_buffer, rl_line_buffer,
+ rl_point, handle_brkchars);
+ list = get_completion_list (cdata);
+ discard_cleanups (cleanup);
+ free_completer_data (cdata);
gdb_assert (list == NULL);
return rl_completer_word_break_characters;
}
@@ -128,6 +128,15 @@ extern const char *skip_quoted (const char *);
extern int get_maximum_completions (void);
+/* Get the list of completions. */
+
+extern VEC (char_ptr) *
+ get_completion_list (const struct completer_data *cdata);
+
+/* Get the number of completions in CDATA. */
+
+extern size_t get_completion_count (const struct completer_data *cdata);
+
/* Return values for add_completion. */
enum add_completion_status
@@ -402,7 +402,7 @@ cmdpy_completer (struct completer_data *cdata,
/* If we got some results, ignore problems. Otherwise, report
the problem. */
- if (result != NULL && PyErr_Occurred ())
+ if (get_completion_count (cdata) > 0 && PyErr_Occurred ())
PyErr_Clear ();
}