/* Line completion stuff for GDB, the GNU debugger.
- Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ Copyright (C) 2000-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "expression.h"
#include "filenames.h" /* For DOSish file names. */
#include "language.h"
-#include "gdb_signals.h"
+#include "common/gdb_signals.h"
#include "target.h"
#include "reggroups.h"
#include "user-regs.h"
return line_buffer + point;
}
-/* See completer.h. */
+/* Find the completion word point for TEXT, emulating the algorithm
+ readline uses to find the word point, using WORD_BREAK_CHARACTERS
+ as word break characters. */
-const char *
-advance_to_expression_complete_word_point (completion_tracker &tracker,
- const char *text)
+static const char *
+advance_to_completion_word (completion_tracker &tracker,
+ const char *word_break_characters,
+ const char *text)
{
gdb_rl_completion_word_info info;
- info.word_break_characters
- = current_language->la_word_break_characters ();
+ info.word_break_characters = word_break_characters;
info.quote_characters = gdb_completer_quote_characters;
info.basic_quote_characters = rl_basic_quote_characters;
+ int delimiter;
const char *start
- = gdb_rl_find_completion_word (&info, NULL, NULL, text);
+ = gdb_rl_find_completion_word (&info, NULL, &delimiter, text);
tracker.advance_custom_word_point_by (start - text);
+ if (delimiter)
+ {
+ tracker.set_quote_char (delimiter);
+ tracker.set_suppress_append_ws (true);
+ }
+
return start;
}
/* See completer.h. */
+const char *
+advance_to_expression_complete_word_point (completion_tracker &tracker,
+ const char *text)
+{
+ const char *brk_chars = current_language->la_word_break_characters ();
+ return advance_to_completion_word (tracker, brk_chars, text);
+}
+
+/* See completer.h. */
+
+const char *
+advance_to_filename_complete_word_point (completion_tracker &tracker,
+ const char *text)
+{
+ const char *brk_chars = gdb_completer_file_name_break_characters;
+ return advance_to_completion_word (tracker, brk_chars, text);
+}
+
+/* See completer.h. */
+
bool
completion_tracker::completes_to_completion_word (const char *word)
{
return false;
}
+/* See completer.h. */
+
+void
+complete_nested_command_line (completion_tracker &tracker, const char *text)
+{
+ /* Must be called from a custom-word-point completer. */
+ gdb_assert (tracker.use_custom_word_point ());
+
+ /* Disable the custom word point temporarily, because we want to
+ probe whether the command we're completing itself uses a custom
+ word point. */
+ tracker.set_use_custom_word_point (false);
+ size_t save_custom_word_point = tracker.custom_word_point ();
+
+ int quote_char = '\0';
+ const char *word = completion_find_completion_word (tracker, text,
+ "e_char);
+
+ if (tracker.use_custom_word_point ())
+ {
+ /* The command we're completing uses a custom word point, so the
+ tracker already contains the matches. We're done. */
+ return;
+ }
+
+ /* Restore the custom word point settings. */
+ tracker.set_custom_word_point (save_custom_word_point);
+ tracker.set_use_custom_word_point (true);
+
+ /* Run the handle_completions completer phase. */
+ complete_line (tracker, word, text, strlen (text));
+}
+
/* Complete on linespecs, which might be of two possible forms:
file:line
before: "b -function 'not_loaded_function_yet()'"
after: "b -function 'not_loaded_function_yet()' "
*/
- gdb::unique_xmalloc_ptr<char> text_copy
- (xstrdup (text));
- tracker.add_completion (std::move (text_copy));
+ tracker.add_completion (make_unique_xstrdup (text));
}
else if (quoted_arg_end[1] == ' ')
{
static void
add_struct_fields (struct type *type, completion_list &output,
- char *fieldname, int namelen)
+ const char *fieldname, int namelen)
{
int i;
int computed_type_name = 0;
{
if (!computed_type_name)
{
- type_name = type_name_no_tag (type);
+ type_name = TYPE_NAME (type);
computed_type_name = 1;
}
/* Omit constructors from the completion list. */
const char *text, const char *word)
{
struct type *type = NULL;
- char *fieldname;
+ gdb::unique_xmalloc_ptr<char> fieldname;
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
+ try
{
type = parse_expression_for_completion (text, &fieldname, &code);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
return;
}
- END_CATCH
- if (fieldname && type)
+ if (fieldname != nullptr && type)
{
for (;;)
{
if (TYPE_CODE (type) == TYPE_CODE_UNION
|| TYPE_CODE (type) == TYPE_CODE_STRUCT)
{
- int flen = strlen (fieldname);
completion_list result;
- add_struct_fields (type, result, fieldname, flen);
- xfree (fieldname);
+ add_struct_fields (type, result, fieldname.get (),
+ strlen (fieldname.get ()));
tracker.add_completions (std::move (result));
return;
}
}
- else if (fieldname && code != TYPE_CODE_UNDEF)
+ else if (fieldname != nullptr && code != TYPE_CODE_UNDEF)
{
- struct cleanup *cleanup = make_cleanup (xfree, fieldname);
-
- collect_symbol_completion_matches_type (tracker, fieldname, fieldname,
- code);
- do_cleanups (cleanup);
+ collect_symbol_completion_matches_type (tracker, fieldname.get (),
+ fieldname.get (), code);
return;
}
- xfree (fieldname);
complete_files_symbols (tracker, text, word);
}
break;
}
+ /* Move the custom word point back too. */
+ tracker.advance_custom_word_point_by (q - p);
+
if (reason != handle_brkchars)
complete_on_cmdlist (result_list, tracker, q, word,
ignore_help_classes);
const char *line_buffer, int point,
complete_line_internal_reason reason)
{
- TRY
+ try
{
complete_line_internal_1 (tracker, text, line_buffer, point, reason);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
- throw_exception (except);
+ throw;
}
- END_CATCH
}
/* See completer.h. */
completion_tracker::completion_tracker ()
{
m_entries_hash = htab_create_alloc (INITIAL_COMPLETION_HTAB_SIZE,
- htab_hash_string, (htab_eq) streq,
+ htab_hash_string, streq_hash,
NULL, xcalloc, xfree);
}
htab_delete (m_entries_hash);
m_entries_hash = htab_create_alloc (INITIAL_COMPLETION_HTAB_SIZE,
- htab_hash_string, (htab_eq) streq,
+ htab_hash_string, streq_hash,
NULL, xcalloc, xfree);
}
bool
completion_tracker::maybe_add_completion
(gdb::unique_xmalloc_ptr<char> name,
- completion_match_for_lcd *match_for_lcd)
+ completion_match_for_lcd *match_for_lcd,
+ const char *text, const char *word)
{
void **slot;
if (match_for_lcd_str == NULL)
match_for_lcd_str = name.get ();
- recompute_lowest_common_denominator (match_for_lcd_str);
+ gdb::unique_xmalloc_ptr<char> lcd
+ = make_completion_match_str (match_for_lcd_str, text, word);
+
+ recompute_lowest_common_denominator (std::move (lcd));
*slot = name.get ();
m_entries_vec.push_back (std::move (name));
void
completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name,
- completion_match_for_lcd *match_for_lcd)
+ completion_match_for_lcd *match_for_lcd,
+ const char *text, const char *word)
{
- if (!maybe_add_completion (std::move (name), match_for_lcd))
+ if (!maybe_add_completion (std::move (name), match_for_lcd, text, word))
throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
}
return gdb::unique_xmalloc_ptr<char> (newobj);
}
+/* See complete.h. */
+
+completion_result
+complete (const char *line, char const **word, int *quote_char)
+{
+ completion_tracker tracker_handle_brkchars;
+ completion_tracker tracker_handle_completions;
+ completion_tracker *tracker;
+
+ /* The WORD should be set to the end of word to complete. We initialize
+ to the completion point which is assumed to be at the end of LINE.
+ This leaves WORD to be initialized to a sensible value in cases
+ completion_find_completion_word() fails i.e., throws an exception.
+ See bug 24587. */
+ *word = line + strlen (line);
+
+ try
+ {
+ *word = completion_find_completion_word (tracker_handle_brkchars,
+ line, quote_char);
+
+ /* Completers that provide a custom word point in the
+ handle_brkchars phase also compute their completions then.
+ Completers that leave the completion word handling to readline
+ must be called twice. */
+ if (tracker_handle_brkchars.use_custom_word_point ())
+ tracker = &tracker_handle_brkchars;
+ else
+ {
+ complete_line (tracker_handle_completions, *word, line, strlen (line));
+ tracker = &tracker_handle_completions;
+ }
+ }
+ catch (const gdb_exception &ex)
+ {
+ return {};
+ }
+
+ return tracker->build_completion_result (*word, *word - line, strlen (line));
+}
+
+
/* Generate completions all at once. Does nothing if max_completions
is 0. If max_completions is non-negative, this will collect at
most max_completions strings.
continue;
if (strncasecmp (signame, word, len) == 0)
- {
- gdb::unique_xmalloc_ptr<char> copy (xstrdup (signame));
- tracker.add_completion (std::move (copy));
- }
+ tracker.add_completion (make_unique_xstrdup (signame));
}
}
i++)
{
if (*name != '\0' && strncmp (word, name, len) == 0)
- {
- gdb::unique_xmalloc_ptr<char> copy (xstrdup (name));
- tracker.add_completion (std::move (copy));
- }
+ tracker.add_completion (make_unique_xstrdup (name));
}
}
{
name = reggroup_name (group);
if (strncmp (word, name, len) == 0)
- {
- gdb::unique_xmalloc_ptr<char> copy (xstrdup (name));
- tracker.add_completion (std::move (copy));
- }
+ tracker.add_completion (make_unique_xstrdup (name));
}
}
}
{
gdb_assert (tracker.custom_word_point () > 0);
rl_point = tracker.custom_word_point () - 1;
+
+ gdb_assert (rl_point >= 0 && rl_point < strlen (rl_line_buffer));
+
gdb_custom_word_point_brkchars[0] = rl_line_buffer[rl_point];
rl_completer_word_break_characters = gdb_custom_word_point_brkchars;
rl_completer_quote_characters = NULL;
/* New completion starting. */
current_completion.aborted = false;
- TRY
+ try
{
return gdb_completion_word_break_characters_throw ();
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
/* Set this to that gdb_rl_attempted_completion_function knows
to abort early. */
current_completion.aborted = true;
}
- END_CATCH
return NULL;
}
/* See completer.h. */
void
-completion_tracker::recompute_lowest_common_denominator (const char *new_match)
+completion_tracker::recompute_lowest_common_denominator
+ (gdb::unique_xmalloc_ptr<char> &&new_match_up)
{
if (m_lowest_common_denominator == NULL)
{
/* We don't have a lowest common denominator yet, so simply take
- the whole NEW_MATCH as being it. */
- m_lowest_common_denominator = xstrdup (new_match);
+ the whole NEW_MATCH_UP as being it. */
+ m_lowest_common_denominator = new_match_up.release ();
m_lowest_common_denominator_unique = true;
}
else
{
/* Find the common denominator between the currently-known
- lowest common denominator and NEW_MATCH. That becomes the
+ lowest common denominator and NEW_MATCH_UP. That becomes the
new lowest common denominator. */
size_t i;
+ const char *new_match = new_match_up.get ();
for (i = 0;
(new_match[i] != '\0'
/* See completer.h. */
void
-completion_tracker::advance_custom_word_point_by (size_t len)
+completion_tracker::advance_custom_word_point_by (int len)
{
m_custom_word_point += len;
}
/* We don't rely on readline appending the quote char as
delimiter as then readline wouldn't append the ' ' after the
completion. */
- char buf[2] = { quote_char () };
+ char buf[2] = { (char) quote_char () };
match_list[0] = reconcat (match_list[0], match_list[0],
buf, (char *) NULL);
if (current_completion.aborted)
return NULL;
- TRY
+ try
{
return gdb_rl_attempted_completion_function_throw (text, start, end);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
}
- END_CATCH
return NULL;
}