+}
+
+/* Helper for the make_completion_match_str overloads. Returns NULL
+ as an indication that we want MATCH_NAME exactly. It is up to the
+ caller to xstrdup that string if desired. */
+
+static char *
+make_completion_match_str_1 (const char *match_name,
+ const char *text, const char *word)
+{
+ char *newobj;
+
+ if (word == text)
+ {
+ /* Return NULL as an indication that we want MATCH_NAME
+ exactly. */
+ return NULL;
+ }
+ else if (word > text)
+ {
+ /* Return some portion of MATCH_NAME. */
+ newobj = xstrdup (match_name + (word - text));
+ }
+ else
+ {
+ /* Return some of WORD plus MATCH_NAME. */
+ size_t len = strlen (match_name);
+ newobj = (char *) xmalloc (text - word + len + 1);
+ memcpy (newobj, word, text - word);
+ memcpy (newobj + (text - word), match_name, len + 1);
+ }
+
+ return newobj;
+}
+
+/* See completer.h. */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (const char *match_name,
+ const char *text, const char *word)
+{
+ char *newobj = make_completion_match_str_1 (match_name, text, word);
+ if (newobj == NULL)
+ newobj = xstrdup (match_name);
+ return gdb::unique_xmalloc_ptr<char> (newobj);
+}
+
+/* See completer.h. */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (gdb::unique_xmalloc_ptr<char> &&match_name,
+ const char *text, const char *word)
+{
+ char *newobj = make_completion_match_str_1 (match_name.get (), text, word);
+ if (newobj == NULL)
+ return std::move (match_name);
+ 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.
+
+ TEXT is the caller's idea of the "word" we are looking at.
+
+ LINE_BUFFER is available to be looked at; it contains the entire
+ text of the line.
+
+ POINT is the offset in that line of the cursor. You
+ should pretend that the line ends at POINT. */
+
+void
+complete_line (completion_tracker &tracker,
+ const char *text, const char *line_buffer, int point)
+{
+ if (max_completions == 0)
+ return;
+ complete_line_internal (tracker, text, line_buffer, point,
+ handle_completions);
+}
+
+/* Complete on command names. Used by "help". */
+
+void
+command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ complete_line_internal (tracker, word, text,
+ strlen (text), handle_help);
+}
+
+/* The corresponding completer_handle_brkchars implementation. */
+
+static void
+command_completer_handle_brkchars (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ set_rl_completer_word_break_characters
+ (gdb_completer_command_word_break_characters);
+}
+
+/* Complete on signals. */
+
+void
+signal_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ size_t len = strlen (word);
+ int signum;
+ const char *signame;
+
+ for (signum = GDB_SIGNAL_FIRST; signum != GDB_SIGNAL_LAST; ++signum)
+ {
+ /* Can't handle this, so skip it. */
+ if (signum == GDB_SIGNAL_0)
+ continue;
+
+ signame = gdb_signal_to_name ((enum gdb_signal) signum);
+
+ /* Ignore the unknown signal case. */
+ if (!signame || strcmp (signame, "?") == 0)
+ continue;
+
+ if (strncasecmp (signame, word, len) == 0)
+ tracker.add_completion (make_unique_xstrdup (signame));
+ }
+}
+
+/* Bit-flags for selecting what the register and/or register-group
+ completer should complete on. */
+
+enum reg_completer_target
+ {
+ complete_register_names = 0x1,
+ complete_reggroup_names = 0x2
+ };
+DEF_ENUM_FLAGS_TYPE (enum reg_completer_target, reg_completer_targets);
+
+/* Complete register names and/or reggroup names based on the value passed
+ in TARGETS. At least one bit in TARGETS must be set. */
+
+static void
+reg_or_group_completer_1 (completion_tracker &tracker,
+ const char *text, const char *word,
+ reg_completer_targets targets)
+{
+ size_t len = strlen (word);
+ struct gdbarch *gdbarch;
+ const char *name;
+
+ gdb_assert ((targets & (complete_register_names
+ | complete_reggroup_names)) != 0);
+ gdbarch = get_current_arch ();
+
+ if ((targets & complete_register_names) != 0)
+ {
+ int i;
+
+ for (i = 0;
+ (name = user_reg_map_regnum_to_name (gdbarch, i)) != NULL;
+ i++)
+ {
+ if (*name != '\0' && strncmp (word, name, len) == 0)
+ tracker.add_completion (make_unique_xstrdup (name));
+ }
+ }
+
+ if ((targets & complete_reggroup_names) != 0)
+ {
+ 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)
+ tracker.add_completion (make_unique_xstrdup (name));
+ }
+ }
+}
+
+/* Perform completion on register and reggroup names. */
+
+void
+reg_or_group_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ reg_or_group_completer_1 (tracker, text, word,
+ (complete_register_names
+ | complete_reggroup_names));
+}
+
+/* Perform completion on reggroup names. */
+
+void
+reggroup_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ reg_or_group_completer_1 (tracker, text, word,
+ complete_reggroup_names);
+}
+
+/* The default completer_handle_brkchars implementation. */
+
+static void
+default_completer_handle_brkchars (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+ set_rl_completer_word_break_characters
+ (current_language->word_break_characters ());
+}
+
+/* See definition in completer.h. */
+
+completer_handle_brkchars_ftype *
+completer_handle_brkchars_func_for_completer (completer_ftype *fn)
+{
+ if (fn == filename_completer)
+ return filename_completer_handle_brkchars;
+
+ if (fn == location_completer)
+ return location_completer_handle_brkchars;
+
+ if (fn == command_completer)
+ return command_completer_handle_brkchars;
+
+ return default_completer_handle_brkchars;
+}
+
+/* Used as brkchars when we want to tell readline we have a custom
+ word point. We do that by making our rl_completion_word_break_hook
+ set RL_POINT to the desired word point, and return the character at
+ the word break point as the break char. This is two bytes in order
+ to fit one break character plus the terminating null. */
+static char gdb_custom_word_point_brkchars[2];
+
+/* Since rl_basic_quote_characters is not completer-specific, we save
+ its original value here, in order to be able to restore it in
+ gdb_rl_attempted_completion_function. */
+static const char *gdb_org_rl_basic_quote_characters = rl_basic_quote_characters;
+
+/* Get the list of chars that are considered as word breaks
+ for the current command. */
+
+static char *
+gdb_completion_word_break_characters_throw ()
+{
+ /* New completion starting. Get rid of the previous tracker and
+ start afresh. */
+ delete current_completion.tracker;
+ current_completion.tracker = new completion_tracker ();
+
+ completion_tracker &tracker = *current_completion.tracker;
+
+ complete_line_internal (tracker, NULL, rl_line_buffer,
+ rl_point, handle_brkchars);
+
+ if (tracker.use_custom_word_point ())
+ {
+ 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;
+
+ /* Clear this too, so that if we're completing a quoted string,
+ readline doesn't consider the quote character a delimiter.
+ If we didn't do this, readline would auto-complete {b
+ 'fun<tab>} to {'b 'function()'}, i.e., add the terminating
+ \', but, it wouldn't append the separator space either, which
+ is not desirable. So instead we take care of appending the
+ quote character to the LCD ourselves, in
+ gdb_rl_attempted_completion_function. Since this global is
+ not just completer-specific, we'll restore it back to the
+ default in gdb_rl_attempted_completion_function. */
+ rl_basic_quote_characters = NULL;
+ }
+
+ return rl_completer_word_break_characters;
+}
+
+char *
+gdb_completion_word_break_characters ()
+{
+ /* New completion starting. */
+ current_completion.aborted = false;
+
+ try
+ {
+ return gdb_completion_word_break_characters_throw ();
+ }
+ catch (const gdb_exception &ex)
+ {
+ /* Set this to that gdb_rl_attempted_completion_function knows
+ to abort early. */
+ current_completion.aborted = true;
+ }
+
+ return NULL;
+}
+
+/* See completer.h. */
+
+const char *
+completion_find_completion_word (completion_tracker &tracker, const char *text,
+ int *quote_char)
+{
+ size_t point = strlen (text);
+
+ complete_line_internal (tracker, NULL, text, point, handle_brkchars);
+
+ if (tracker.use_custom_word_point ())
+ {
+ gdb_assert (tracker.custom_word_point () > 0);
+ *quote_char = tracker.quote_char ();
+ return text + tracker.custom_word_point ();
+ }
+
+ gdb_rl_completion_word_info info;
+
+ info.word_break_characters = rl_completer_word_break_characters;
+ info.quote_characters = gdb_completer_quote_characters;
+ info.basic_quote_characters = rl_basic_quote_characters;
+
+ return gdb_rl_find_completion_word (&info, quote_char, NULL, text);
+}
+
+/* See completer.h. */
+
+void
+completion_tracker::recompute_lcd_visitor (completion_hash_entry *entry)
+{
+ if (!m_lowest_common_denominator_valid)
+ {
+ /* This is the first lowest common denominator that we are
+ considering, just copy it in. */
+ strcpy (m_lowest_common_denominator, entry->get_lcd ());
+ m_lowest_common_denominator_unique = true;
+ m_lowest_common_denominator_valid = true;
+ }
+ else
+ {
+ /* Find the common denominator between the currently-known lowest
+ common denominator and NEW_MATCH_UP. That becomes the new lowest
+ common denominator. */
+ size_t i;
+ const char *new_match = entry->get_lcd ();
+
+ for (i = 0;
+ (new_match[i] != '\0'
+ && new_match[i] == m_lowest_common_denominator[i]);
+ i++)
+ ;
+ if (m_lowest_common_denominator[i] != new_match[i])
+ {
+ m_lowest_common_denominator[i] = '\0';
+ m_lowest_common_denominator_unique = false;
+ }
+ }
+}
+
+/* See completer.h. */
+
+void
+completion_tracker::recompute_lowest_common_denominator ()
+{
+ /* We've already done this. */
+ if (m_lowest_common_denominator_valid)
+ return;
+
+ /* Resize the storage to ensure we have enough space, the plus one gives
+ us space for the trailing null terminator we will include. */
+ m_lowest_common_denominator
+ = (char *) xrealloc (m_lowest_common_denominator,
+ m_lowest_common_denominator_max_length + 1);
+
+ /* Callback used to visit each entry in the m_entries_hash. */
+ auto visitor_func
+ = [] (void **slot, void *info) -> int
+ {
+ completion_tracker *obj = (completion_tracker *) info;
+ completion_hash_entry *entry = (completion_hash_entry *) *slot;
+ obj->recompute_lcd_visitor (entry);
+ return 1;
+ };
+
+ htab_traverse (m_entries_hash, visitor_func, this);
+ m_lowest_common_denominator_valid = true;
+}
+
+/* See completer.h. */
+
+void
+completion_tracker::advance_custom_word_point_by (int len)
+{
+ m_custom_word_point += len;
+}
+
+/* Build a new C string that is a copy of LCD with the whitespace of
+ ORIG/ORIG_LEN preserved.
+
+ Say the user is completing a symbol name, with spaces, like:
+
+ "foo ( i"
+
+ and the resulting completion match is:
+
+ "foo(int)"
+
+ we want to end up with an input line like:
+
+ "foo ( int)"
+ ^^^^^^^ => text from LCD [1], whitespace from ORIG preserved.
+ ^^ => new text from LCD
+
+ [1] - We must take characters from the LCD instead of the original
+ text, since some completions want to change upper/lowercase. E.g.:
+
+ "handle sig<>"
+
+ completes to:
+
+ "handle SIG[QUIT|etc.]"
+*/
+
+static char *
+expand_preserving_ws (const char *orig, size_t orig_len,
+ const char *lcd)
+{
+ const char *p_orig = orig;
+ const char *orig_end = orig + orig_len;
+ const char *p_lcd = lcd;
+ std::string res;
+
+ while (p_orig < orig_end)
+ {
+ if (*p_orig == ' ')
+ {
+ while (p_orig < orig_end && *p_orig == ' ')
+ res += *p_orig++;
+ p_lcd = skip_spaces (p_lcd);
+ }
+ else
+ {
+ /* Take characters from the LCD instead of the original
+ text, since some completions change upper/lowercase.
+ E.g.:
+ "handle sig<>"
+ completes to:
+ "handle SIG[QUIT|etc.]"
+ */
+ res += *p_lcd;
+ p_orig++;
+ p_lcd++;
+ }
+ }
+
+ while (*p_lcd != '\0')
+ res += *p_lcd++;
+
+ return xstrdup (res.c_str ());
+}
+
+/* See completer.h. */
+
+completion_result
+completion_tracker::build_completion_result (const char *text,
+ int start, int end)
+{
+ size_t element_count = htab_elements (m_entries_hash);
+
+ if (element_count == 0)
+ return {};
+
+ /* +1 for the LCD, and +1 for NULL termination. */
+ char **match_list = XNEWVEC (char *, 1 + element_count + 1);
+
+ /* Build replacement word, based on the LCD. */
+
+ recompute_lowest_common_denominator ();
+ match_list[0]
+ = expand_preserving_ws (text, end - start,
+ m_lowest_common_denominator);
+
+ if (m_lowest_common_denominator_unique)
+ {
+ /* 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] = { (char) quote_char () };
+
+ match_list[0] = reconcat (match_list[0], match_list[0],
+ buf, (char *) NULL);
+ match_list[1] = NULL;
+
+ /* If the tracker wants to, or we already have a space at the
+ end of the match, tell readline to skip appending
+ another. */
+ bool completion_suppress_append
+ = (suppress_append_ws ()
+ || match_list[0][strlen (match_list[0]) - 1] == ' ');
+
+ return completion_result (match_list, 1, completion_suppress_append);
+ }
+ else
+ {
+ /* State object used while building the completion list. */
+ struct list_builder
+ {
+ list_builder (char **ml)
+ : match_list (ml),
+ index (1)
+ { /* Nothing. */ }
+
+ /* The list we are filling. */
+ char **match_list;
+
+ /* The next index in the list to write to. */
+ int index;
+ };
+ list_builder builder (match_list);
+
+ /* Visit each entry in m_entries_hash and add it to the completion
+ list, updating the builder state object. */
+ auto func
+ = [] (void **slot, void *info) -> int
+ {
+ completion_hash_entry *entry = (completion_hash_entry *) *slot;
+ list_builder *state = (list_builder *) info;
+
+ state->match_list[state->index] = entry->release_name ();
+ state->index++;
+ return 1;
+ };
+
+ /* Build the completion list and add a null at the end. */
+ htab_traverse_noresize (m_entries_hash, func, &builder);
+ match_list[builder.index] = NULL;
+
+ return completion_result (match_list, builder.index - 1, false);
+ }
+}
+
+/* See completer.h */
+
+completion_result::completion_result ()
+ : match_list (NULL), number_matches (0),
+ completion_suppress_append (false)
+{}
+
+/* See completer.h */
+
+completion_result::completion_result (char **match_list_,
+ size_t number_matches_,
+ bool completion_suppress_append_)
+ : match_list (match_list_),
+ number_matches (number_matches_),
+ completion_suppress_append (completion_suppress_append_)
+{}
+
+/* See completer.h */
+
+completion_result::~completion_result ()
+{
+ reset_match_list ();
+}
+
+/* See completer.h */
+
+completion_result::completion_result (completion_result &&rhs) noexcept
+ : match_list (rhs.match_list),
+ number_matches (rhs.number_matches)
+{
+ rhs.match_list = NULL;
+ rhs.number_matches = 0;
+}
+
+/* See completer.h */
+
+char **
+completion_result::release_match_list ()
+{
+ char **ret = match_list;
+ match_list = NULL;
+ return ret;
+}
+
+/* See completer.h */
+
+void
+completion_result::sort_match_list ()
+{
+ if (number_matches > 1)
+ {
+ /* Element 0 is special (it's the common prefix), leave it
+ be. */
+ std::sort (&match_list[1],
+ &match_list[number_matches + 1],
+ compare_cstrings);
+ }
+}
+
+/* See completer.h */
+
+void
+completion_result::reset_match_list ()
+{
+ if (match_list != NULL)
+ {
+ for (char **p = match_list; *p != NULL; p++)
+ xfree (*p);
+ xfree (match_list);
+ match_list = NULL;
+ }
+}
+
+/* Helper for gdb_rl_attempted_completion_function, which does most of
+ the work. This is called by readline to build the match list array
+ and to determine the lowest common denominator. The real matches
+ list starts at match[1], while match[0] is the slot holding
+ readline's idea of the lowest common denominator of all matches,
+ which is what readline replaces the completion "word" with.
+
+ TEXT is the caller's idea of the "word" we are looking at, as
+ computed in the handle_brkchars phase.
+
+ START is the offset from RL_LINE_BUFFER where TEXT starts. END is
+ the offset from RL_LINE_BUFFER where TEXT ends (i.e., where
+ rl_point is).
+
+ You should thus pretend that the line ends at END (relative to
+ RL_LINE_BUFFER).
+
+ RL_LINE_BUFFER contains the entire text of the line. RL_POINT is
+ the offset in that line of the cursor. You should pretend that the
+ line ends at POINT.
+
+ Returns NULL if there are no completions. */
+
+static char **
+gdb_rl_attempted_completion_function_throw (const char *text, int start, int end)
+{
+ /* 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 rl_point (i.e., END) is at column 0,
+ then readline skips the handle_brkchars phase, and so we create a
+ tracker now in that case too. */
+ if (end == 0 || !current_completion.tracker->use_custom_word_point ())
+ {
+ delete current_completion.tracker;
+ current_completion.tracker = new completion_tracker ();
+
+ complete_line (*current_completion.tracker, text,
+ rl_line_buffer, rl_point);
+ }
+
+ completion_tracker &tracker = *current_completion.tracker;
+
+ completion_result result
+ = tracker.build_completion_result (text, start, end);
+
+ rl_completion_suppress_append = result.completion_suppress_append;
+ return result.release_match_list ();
+}
+
+/* Function installed as "rl_attempted_completion_function" readline
+ hook. Wrapper around gdb_rl_attempted_completion_function_throw
+ that catches C++ exceptions, which can't cross readline. */
+
+char **
+gdb_rl_attempted_completion_function (const char *text, int start, int end)
+{
+ /* Restore globals that might have been tweaked in
+ gdb_completion_word_break_characters. */
+ rl_basic_quote_characters = gdb_org_rl_basic_quote_characters;
+
+ /* If we end up returning NULL, either on error, or simple because
+ there are no matches, inhibit readline's default filename
+ completer. */
+ rl_attempted_completion_over = 1;
+
+ /* If the handle_brkchars phase was aborted, don't try
+ completing. */
+ if (current_completion.aborted)
+ return NULL;
+
+ try
+ {
+ return gdb_rl_attempted_completion_function_throw (text, start, end);
+ }
+ catch (const gdb_exception &ex)
+ {
+ }
+
+ return NULL;
+}
+
+/* Skip over the possibly quoted word STR (as defined by the quote
+ characters QUOTECHARS and the word break characters BREAKCHARS).
+ Returns pointer to the location after the "word". If either
+ QUOTECHARS or BREAKCHARS is NULL, use the same values used by the
+ completer. */
+
+const char *
+skip_quoted_chars (const char *str, const char *quotechars,
+ const char *breakchars)
+{
+ char quote_char = '\0';
+ const char *scan;
+
+ if (quotechars == NULL)
+ quotechars = gdb_completer_quote_characters;
+
+ if (breakchars == NULL)
+ breakchars = current_language->word_break_characters ();
+
+ for (scan = str; *scan != '\0'; scan++)
+ {
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote char. */
+ if (*scan == quote_char)
+ {
+ /* Found matching close quote. */
+ scan++;
+ break;
+ }
+ }
+ else if (strchr (quotechars, *scan))
+ {
+ /* Found start of a quoted string. */
+ quote_char = *scan;
+ }
+ else if (strchr (breakchars, *scan))
+ {
+ break;
+ }
+ }
+
+ return (scan);