Fix build error in gdb/rocm-tdep.c
[deliverable/binutils-gdb.git] / gdb / completer.c
index 85e6d88b7423acecadff89d085fb3b54e5418495..3a17445004d92b102916474e0116f10945a4537d 100644 (file)
@@ -1,5 +1,5 @@
 /* Line completion stuff for GDB, the GNU debugger.
-   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   Copyright (C) 2000-2020 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 "gdbsupport/gdb_signals.h"
 #include "target.h"
 #include "reggroups.h"
 #include "user-regs.h"
 #include "arch-utils.h"
 #include "location.h"
 #include <algorithm>
+#include "linespec.h"
 #include "cli/cli-decode.h"
 
 /* FIXME: This is needed because of lookup_cmd_1 ().  We should be
@@ -63,8 +64,9 @@ struct gdb_completer_state
 /* The current completion state.  */
 static gdb_completer_state current_completion;
 
-/* An enumeration of the various things a user might
-   attempt to complete for a location.  */
+/* An enumeration of the various things a user might attempt to
+   complete for a location.  If you change this, remember to update
+   the explicit_options array below too.  */
 
 enum explicit_location_match_type
 {
@@ -74,6 +76,12 @@ enum explicit_location_match_type
     /* The name of a function or method.  */
     MATCH_FUNCTION,
 
+    /* The fully-qualified name of a function or method.  */
+    MATCH_QUALIFIED,
+
+    /* A line number.  */
+    MATCH_LINE,
+
     /* The name of a label.  */
     MATCH_LABEL
 };
@@ -94,13 +102,13 @@ enum explicit_location_match_type
 
 /* Variables which are necessary for fancy command line editing.  */
 
-/* When completing on command names, we remove '-' from the list of
+/* When completing on command names, we remove '-' and '.' from the list of
    word break characters, since we use it in command names.  If the
    readline library sees one in any of the current completion strings,
    it thinks that the string needs to be quoted and automatically
    supplies a leading quote.  */
 static const char gdb_completer_command_word_break_characters[] =
-" \t\n!@#$%^&*()+=|~`}{[]\"';:?/>.<,";
+" \t\n!@#$%^&*()+=|~`}{[]\"';:?/><,";
 
 /* When completing on file names, we remove from the list of word
    break characters any characters that are commonly used in file
@@ -146,15 +154,13 @@ filename_completer (struct cmd_list_element *ignore,
                    const char *text, const char *word)
 {
   int subsequent_name;
-  VEC (char_ptr) *return_val = NULL;
 
   subsequent_name = 0;
   while (1)
     {
-      char *p, *q;
-
-      p = rl_filename_completion_function (text, subsequent_name);
-      if (p == NULL)
+      gdb::unique_xmalloc_ptr<char> p_rl
+       (rl_filename_completion_function (text, subsequent_name));
+      if (p_rl == NULL)
        break;
       /* We need to set subsequent_name to a non-zero value before the
         continue line below, because otherwise, if the first file
@@ -163,32 +169,12 @@ filename_completer (struct cmd_list_element *ignore,
       subsequent_name = 1;
       /* Like emacs, don't complete on old versions.  Especially
          useful in the "source" command.  */
+      const char *p = p_rl.get ();
       if (p[strlen (p) - 1] == '~')
-       {
-         xfree (p);
-         continue;
-       }
+       continue;
 
-      if (word == text)
-       /* Return exactly p.  */
-       q = p;
-      else if (word > text)
-       {
-         /* Return some portion of p.  */
-         q = (char *) xmalloc (strlen (p) + 5);
-         strcpy (q, p + (word - text));
-         xfree (p);
-       }
-      else
-       {
-         /* Return some of TEXT plus p.  */
-         q = (char *) xmalloc (strlen (p) + (text - word) + 5);
-         strncpy (q, word, text - word);
-         q[text - word] = '\0';
-         strcat (q, p);
-         xfree (p);
-       }
-      tracker.add_completion (gdb::unique_xmalloc_ptr<char> (q));
+      tracker.add_completion
+       (make_completion_match_str (std::move (p_rl), text, word));
     }
 #if 0
   /* There is no way to do this just long enough to affect quote
@@ -212,6 +198,264 @@ filename_completer_handle_brkchars (struct cmd_list_element *ignore,
     (gdb_completer_file_name_break_characters);
 }
 
+/* Possible values for the found_quote flags word used by the completion
+   functions.  It says what kind of (shell-like) quoting we found anywhere
+   in the line. */
+#define RL_QF_SINGLE_QUOTE      0x01
+#define RL_QF_DOUBLE_QUOTE      0x02
+#define RL_QF_BACKSLASH         0x04
+#define RL_QF_OTHER_QUOTE       0x08
+
+/* Find the bounds of the current word for completion purposes, and
+   return a pointer to the end of the word.  This mimics (and is a
+   modified version of) readline's _rl_find_completion_word internal
+   function.
+
+   This function skips quoted substrings (characters between matched
+   pairs of characters in rl_completer_quote_characters).  We try to
+   find an unclosed quoted substring on which to do matching.  If one
+   is not found, we use the word break characters to find the
+   boundaries of the current word.  QC, if non-null, is set to the
+   opening quote character if we found an unclosed quoted substring,
+   '\0' otherwise.  DP, if non-null, is set to the value of the
+   delimiter character that caused a word break.  */
+
+struct gdb_rl_completion_word_info
+{
+  const char *word_break_characters;
+  const char *quote_characters;
+  const char *basic_quote_characters;
+};
+
+static const char *
+gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info,
+                            int *qc, int *dp,
+                            const char *line_buffer)
+{
+  int scan, end, found_quote, delimiter, pass_next, isbrk;
+  char quote_char;
+  const char *brkchars;
+  int point = strlen (line_buffer);
+
+  /* The algorithm below does '--point'.  Avoid buffer underflow with
+     the empty string.  */
+  if (point == 0)
+    {
+      if (qc != NULL)
+       *qc = '\0';
+      if (dp != NULL)
+       *dp = '\0';
+      return line_buffer;
+    }
+
+  end = point;
+  found_quote = delimiter = 0;
+  quote_char = '\0';
+
+  brkchars = info->word_break_characters;
+
+  if (info->quote_characters != NULL)
+    {
+      /* We have a list of characters which can be used in pairs to
+        quote substrings for the completer.  Try to find the start of
+        an unclosed quoted substring.  */
+      /* FOUND_QUOTE is set so we know what kind of quotes we
+        found.  */
+      for (scan = pass_next = 0;
+          scan < end;
+          scan++)
+       {
+         if (pass_next)
+           {
+             pass_next = 0;
+             continue;
+           }
+
+         /* Shell-like semantics for single quotes -- don't allow
+            backslash to quote anything in single quotes, especially
+            not the closing quote.  If you don't like this, take out
+            the check on the value of quote_char.  */
+         if (quote_char != '\'' && line_buffer[scan] == '\\')
+           {
+             pass_next = 1;
+             found_quote |= RL_QF_BACKSLASH;
+             continue;
+           }
+
+         if (quote_char != '\0')
+           {
+             /* Ignore everything until the matching close quote
+                char.  */
+             if (line_buffer[scan] == quote_char)
+               {
+                 /* Found matching close.  Abandon this
+                    substring.  */
+                 quote_char = '\0';
+                 point = end;
+               }
+           }
+         else if (strchr (info->quote_characters, line_buffer[scan]))
+           {
+             /* Found start of a quoted substring.  */
+             quote_char = line_buffer[scan];
+             point = scan + 1;
+             /* Shell-like quoting conventions.  */
+             if (quote_char == '\'')
+               found_quote |= RL_QF_SINGLE_QUOTE;
+             else if (quote_char == '"')
+               found_quote |= RL_QF_DOUBLE_QUOTE;
+             else
+               found_quote |= RL_QF_OTHER_QUOTE;
+           }
+       }
+    }
+
+  if (point == end && quote_char == '\0')
+    {
+      /* We didn't find an unclosed quoted substring upon which to do
+        completion, so use the word break characters to find the
+        substring on which to complete.  */
+      while (--point)
+       {
+         scan = line_buffer[point];
+
+         if (strchr (brkchars, scan) != 0)
+           break;
+       }
+    }
+
+  /* If we are at an unquoted word break, then advance past it.  */
+  scan = line_buffer[point];
+
+  if (scan)
+    {
+      isbrk = strchr (brkchars, scan) != 0;
+
+      if (isbrk)
+       {
+         /* If the character that caused the word break was a quoting
+            character, then remember it as the delimiter.  */
+         if (info->basic_quote_characters
+             && strchr (info->basic_quote_characters, scan)
+             && (end - point) > 1)
+           delimiter = scan;
+
+         point++;
+       }
+    }
+
+  if (qc != NULL)
+    *qc = quote_char;
+  if (dp != NULL)
+    *dp = delimiter;
+
+  return line_buffer + point;
+}
+
+/* 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.  */
+
+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 = 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, &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)
+{
+  if (m_lowest_common_denominator_unique)
+    {
+      const char *lcd = m_lowest_common_denominator;
+
+      if (strncmp_iw (word, lcd, strlen (lcd)) == 0)
+       {
+         /* Maybe skip the function and complete on keywords.  */
+         size_t wordlen = strlen (word);
+         if (word[wordlen - 1] == ' ')
+           return true;
+       }
+    }
+
+  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,
+                                                     &quote_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
@@ -225,7 +469,6 @@ static void
 complete_files_symbols (completion_tracker &tracker,
                        const char *text, const char *word)
 {
-  int ix;
   completion_list fn_list;
   const char *p;
   int quote_found = 0;
@@ -296,7 +539,10 @@ complete_files_symbols (completion_tracker &tracker,
      symbols as well as on files.  */
   if (colon)
     {
-      collect_file_symbol_completion_matches (tracker, symbol_start, word,
+      collect_file_symbol_completion_matches (tracker,
+                                             complete_symbol_mode::EXPRESSION,
+                                             symbol_name_match_type::EXPRESSION,
+                                             symbol_start, word,
                                              file_to_match);
       xfree (file_to_match);
     }
@@ -304,7 +550,10 @@ complete_files_symbols (completion_tracker &tracker,
     {
       size_t text_len = strlen (text);
 
-      collect_symbol_completion_matches (tracker, symbol_start, word);
+      collect_symbol_completion_matches (tracker,
+                                        complete_symbol_mode::EXPRESSION,
+                                        symbol_name_match_type::EXPRESSION,
+                                        symbol_start, word);
       /* If text includes characters which cannot appear in a file
         name, they cannot be asking for completion on files.  */
       if (strcspn (text,
@@ -314,8 +563,6 @@ complete_files_symbols (completion_tracker &tracker,
 
   if (!fn_list.empty () && !tracker.have_completions ())
     {
-      char *fn;
-
       /* If we only have file names as possible completion, we should
         bring them in sync with what rl_complete expects.  The
         problem is that if the user types "break /foo/b TAB", and the
@@ -345,10 +592,73 @@ complete_files_symbols (completion_tracker &tracker,
       /* No completions at all.  As the final resort, try completing
         on the entire text as a symbol.  */
       collect_symbol_completion_matches (tracker,
+                                        complete_symbol_mode::EXPRESSION,
+                                        symbol_name_match_type::EXPRESSION,
                                         orig_text, word);
     }
 }
 
+/* See completer.h.  */
+
+completion_list
+complete_source_filenames (const char *text)
+{
+  size_t text_len = strlen (text);
+
+  /* If text includes characters which cannot appear in a file name,
+     the user cannot be asking for completion on files.  */
+  if (strcspn (text,
+              gdb_completer_file_name_break_characters)
+      == text_len)
+    return make_source_files_completion_list (text, text);
+
+  return {};
+}
+
+/* Complete address and linespec locations.  */
+
+static void
+complete_address_and_linespec_locations (completion_tracker &tracker,
+                                        const char *text,
+                                        symbol_name_match_type match_type)
+{
+  if (*text == '*')
+    {
+      tracker.advance_custom_word_point_by (1);
+      text++;
+      const char *word
+       = advance_to_expression_complete_word_point (tracker, text);
+      complete_expression (tracker, text, word);
+    }
+  else
+    {
+      linespec_complete (tracker, text, match_type);
+    }
+}
+
+/* The explicit location options.  Note that indexes into this array
+   must match the explicit_location_match_type enumerators.  */
+
+static const char *const explicit_options[] =
+  {
+    "-source",
+    "-function",
+    "-qualified",
+    "-line",
+    "-label",
+    NULL
+  };
+
+/* The probe modifier options.  These can appear before a location in
+   breakpoint commands.  */
+static const char *const probe_options[] =
+  {
+    "-probe",
+    "-probe-stap",
+    "-probe-dtrace",
+    NULL
+  };
+
 /* Returns STRING if not NULL, the empty string otherwise.  */
 
 static const char *
@@ -364,18 +674,25 @@ static void
 collect_explicit_location_matches (completion_tracker &tracker,
                                   struct event_location *location,
                                   enum explicit_location_match_type what,
-                                  const char *word)
+                                  const char *word,
+                                  const struct language_defn *language)
 {
   const struct explicit_location *explicit_loc
     = get_explicit_location (location);
 
+  /* True if the option expects an argument.  */
+  bool needs_arg = true;
+
+  /* Note, in the various MATCH_* below, we complete on
+     explicit_loc->foo instead of WORD, because only the former will
+     have already skipped past any quote char.  */
   switch (what)
     {
     case MATCH_SOURCE:
       {
        const char *source = string_or_empty (explicit_loc->source_filename);
        completion_list matches
-         = make_source_files_completion_list (source, word);
+         = make_source_files_completion_list (source, source);
        tracker.add_completions (std::move (matches));
       }
       break;
@@ -383,120 +700,185 @@ collect_explicit_location_matches (completion_tracker &tracker,
     case MATCH_FUNCTION:
       {
        const char *function = string_or_empty (explicit_loc->function_name);
-       if (explicit_loc->source_filename != NULL)
-         {
-           const char *filename = explicit_loc->source_filename;
-
-           collect_file_symbol_completion_matches (tracker,
-                                                   function, word, filename);
-         }
-       else
-        collect_symbol_completion_matches (tracker, function, word);
+       linespec_complete_function (tracker, function,
+                                   explicit_loc->func_name_match_type,
+                                   explicit_loc->source_filename);
       }
       break;
 
+    case MATCH_QUALIFIED:
+      needs_arg = false;
+      break;
+    case MATCH_LINE:
+      /* Nothing to offer.  */
+      break;
+
     case MATCH_LABEL:
-      /* Not supported.  */
+      {
+       const char *label = string_or_empty (explicit_loc->label_name);
+       linespec_complete_label (tracker, language,
+                                explicit_loc->source_filename,
+                                explicit_loc->function_name,
+                                explicit_loc->func_name_match_type,
+                                label);
+      }
       break;
 
     default:
       gdb_assert_not_reached ("unhandled explicit_location_match_type");
     }
+
+  if (!needs_arg || tracker.completes_to_completion_word (word))
+    {
+      tracker.discard_completions ();
+      tracker.advance_custom_word_point_by (strlen (word));
+      complete_on_enum (tracker, explicit_options, "", "");
+      complete_on_enum (tracker, linespec_keywords, "", "");
+    }
+  else if (!tracker.have_completions ())
+    {
+      /* Maybe we have an unterminated linespec keyword at the tail of
+        the string.  Try completing on that.  */
+      size_t wordlen = strlen (word);
+      const char *keyword = word + wordlen;
+
+      if (wordlen > 0 && keyword[-1] != ' ')
+       {
+         while (keyword > word && *keyword != ' ')
+           keyword--;
+         /* Don't complete on keywords if we'd be completing on the
+            whole explicit linespec option.  E.g., "b -function
+            thr<tab>" should not complete to the "thread"
+            keyword.  */
+         if (keyword != word)
+           {
+             keyword = skip_spaces (keyword);
+
+             tracker.advance_custom_word_point_by (keyword - word);
+             complete_on_enum (tracker, linespec_keywords, keyword, keyword);
+           }
+       }
+      else if (wordlen > 0 && keyword[-1] == ' ')
+       {
+         /* Assume that we're maybe past the explicit location
+            argument, and we didn't manage to find any match because
+            the user wants to create a pending breakpoint.  Offer the
+            keyword and explicit location options as possible
+            completions.  */
+         tracker.advance_custom_word_point_by (keyword - word);
+         complete_on_enum (tracker, linespec_keywords, keyword, keyword);
+         complete_on_enum (tracker, explicit_options, keyword, keyword);
+       }
+    }
 }
 
-/* A convenience macro to (safely) back up P to the previous word.  */
+/* If the next word in *TEXT_P is any of the keywords in KEYWORDS,
+   then advance both TEXT_P and the word point in the tracker past the
+   keyword and return the (0-based) index in the KEYWORDS array that
+   matched.  Otherwise, return -1.  */
 
-static const char *
-backup_text_ptr (const char *p, const char *text)
+static int
+skip_keyword (completion_tracker &tracker,
+             const char * const *keywords, const char **text_p)
 {
-  while (p > text && isspace (*p))
-    --p;
-  for (; p > text && !isspace (p[-1]); --p)
-    ;
+  const char *text = *text_p;
+  const char *after = skip_to_space (text);
+  size_t len = after - text;
+
+  if (text[len] != ' ')
+    return -1;
+
+  int found = -1;
+  for (int i = 0; keywords[i] != NULL; i++)
+    {
+      if (strncmp (keywords[i], text, len) == 0)
+       {
+         if (found == -1)
+           found = i;
+         else
+           return -1;
+       }
+    }
+
+  if (found != -1)
+    {
+      tracker.advance_custom_word_point_by (len + 1);
+      text += len + 1;
+      *text_p = text;
+      return found;
+    }
 
-  return p;
+  return -1;
 }
 
 /* A completer function for explicit locations.  This function
-   completes both options ("-source", "-line", etc) and values.  */
+   completes both options ("-source", "-line", etc) and values.  If
+   completing a quoted string, then QUOTED_ARG_START and
+   QUOTED_ARG_END point to the quote characters.  LANGUAGE is the
+   current language.  */
 
 static void
 complete_explicit_location (completion_tracker &tracker,
                            struct event_location *location,
-                           const char *text, const char *word)
+                           const char *text,
+                           const language_defn *language,
+                           const char *quoted_arg_start,
+                           const char *quoted_arg_end)
 {
-  const char *p;
+  if (*text != '-')
+    return;
 
-  /* Find the beginning of the word.  This is necessary because
-     we need to know if we are completing an option name or value.  We
-     don't get the leading '-' from the completer.  */
-  p = backup_text_ptr (word, text);
+  int keyword = skip_keyword (tracker, explicit_options, &text);
 
-  if (*p == '-')
+  if (keyword == -1)
+    complete_on_enum (tracker, explicit_options, text, text);
+  else
     {
-      /* Completing on option name.  */
-      static const char *const keywords[] =
+      /* Completing on value.  */
+      enum explicit_location_match_type what
+       = (explicit_location_match_type) keyword;
+
+      if (quoted_arg_start != NULL && quoted_arg_end != NULL)
        {
-         "source",
-         "function",
-         "line",
-         "label",
-         NULL
-       };
+         if (quoted_arg_end[1] == '\0')
+           {
+             /* If completing a quoted string with the cursor right
+                at the terminating quote char, complete the
+                completion word without interpretation, so that
+                readline advances the cursor one whitespace past the
+                quote, even if there's no match.  This makes these
+                cases behave the same:
 
-      /* Skip over the '-'.  */
-      ++p;
+                  before: "b -function function()"
+                  after:  "b -function function() "
 
-      complete_on_enum (tracker, keywords, p, p);
-      return;
-    }
-  else
-    {
-      /* Completing on value (or unknown).  Get the previous word to see what
-        the user is completing on.  */
-      size_t len, offset;
-      const char *new_word, *end;
-      enum explicit_location_match_type what;
-      struct explicit_location *explicit_loc
-       = get_explicit_location (location);
-
-      /* Backup P to the previous word, which should be the option
-        the user is attempting to complete.  */
-      offset = word - p;
-      end = --p;
-      p = backup_text_ptr (p, text);
-      len = end - p;
-
-      if (strncmp (p, "-source", len) == 0)
-       {
-         what = MATCH_SOURCE;
-         new_word = explicit_loc->source_filename + offset;
-       }
-      else if (strncmp (p, "-function", len) == 0)
-       {
-         what = MATCH_FUNCTION;
-         new_word = explicit_loc->function_name + offset;
-       }
-      else if (strncmp (p, "-label", len) == 0)
-       {
-         what = MATCH_LABEL;
-         new_word = explicit_loc->label_name + offset;
-       }
-      else
-       {
-         /* The user isn't completing on any valid option name,
-            e.g., "break -source foo.c [tab]".  */
+                  before: "b -function 'function()'"
+                  after:  "b -function 'function()' "
+
+                and trusts the user in this case:
+
+                  before: "b -function 'not_loaded_function_yet()'"
+                  after:  "b -function 'not_loaded_function_yet()' "
+             */
+             tracker.add_completion (make_unique_xstrdup (text));
+           }
+         else if (quoted_arg_end[1] == ' ')
+           {
+             /* We're maybe past the explicit location argument.
+                Skip the argument without interpretation, assuming the
+                user may want to create pending breakpoint.  Offer
+                the keyword and explicit location options as possible
+                completions.  */
+             tracker.advance_custom_word_point_by (strlen (text));
+             complete_on_enum (tracker, linespec_keywords, "", "");
+             complete_on_enum (tracker, explicit_options, "", "");
+           }
          return;
        }
 
-      /* If the user hasn't entered a search expression, e.g.,
-        "break -function <TAB><TAB>", new_word will be NULL, but
-        search routines require non-NULL search words.  */
-      if (new_word == NULL)
-       new_word = "";
-
       /* Now gather matches  */
-      collect_explicit_location_matches (tracker, location, what, new_word);
+      collect_explicit_location_matches (tracker, location, what, text,
+                                        language);
     }
 }
 
@@ -505,23 +887,133 @@ complete_explicit_location (completion_tracker &tracker,
 void
 location_completer (struct cmd_list_element *ignore,
                    completion_tracker &tracker,
-                   const char *text, const char *word)
+                   const char *text, const char * /* word */)
 {
+  int found_probe_option = -1;
+
+  /* If we have a probe modifier, skip it.  This can only appear as
+     first argument.  Until we have a specific completer for probes,
+     falling back to the linespec completer for the remainder of the
+     line is better than nothing.  */
+  if (text[0] == '-' && text[1] == 'p')
+    found_probe_option = skip_keyword (tracker, probe_options, &text);
+
+  const char *option_text = text;
+  int saved_word_point = tracker.custom_word_point ();
+
   const char *copy = text;
 
-  event_location_up location = string_to_explicit_location (&copy,
-                                                           current_language,
-                                                           1);
-  if (location != NULL)
-    complete_explicit_location (tracker, location.get (),
-                               text, word);
+  explicit_completion_info completion_info;
+  event_location_up location
+    = string_to_explicit_location (&copy, current_language,
+                                  &completion_info);
+  if (completion_info.quoted_arg_start != NULL
+      && completion_info.quoted_arg_end == NULL)
+    {
+      /* Found an unbalanced quote.  */
+      tracker.set_quote_char (*completion_info.quoted_arg_start);
+      tracker.advance_custom_word_point_by (1);
+    }
+
+  if (completion_info.saw_explicit_location_option)
+    {
+      if (*copy != '\0')
+       {
+         tracker.advance_custom_word_point_by (copy - text);
+         text = copy;
+
+         /* We found a terminator at the tail end of the string,
+            which means we're past the explicit location options.  We
+            may have a keyword to complete on.  If we have a whole
+            keyword, then complete whatever comes after as an
+            expression.  This is mainly for the "if" keyword.  If the
+            "thread" and "task" keywords gain their own completers,
+            they should be used here.  */
+         int keyword = skip_keyword (tracker, linespec_keywords, &text);
+
+         if (keyword == -1)
+           {
+             complete_on_enum (tracker, linespec_keywords, text, text);
+           }
+         else
+           {
+             const char *word
+               = advance_to_expression_complete_word_point (tracker, text);
+             complete_expression (tracker, text, word);
+           }
+       }
+      else
+       {
+         tracker.advance_custom_word_point_by (completion_info.last_option
+                                               - text);
+         text = completion_info.last_option;
+
+         complete_explicit_location (tracker, location.get (), text,
+                                     current_language,
+                                     completion_info.quoted_arg_start,
+                                     completion_info.quoted_arg_end);
+
+       }
+    }
+  /* This is an address or linespec location.  */
+  else if (location != NULL)
+    {
+      /* Handle non-explicit location options.  */
+
+      int keyword = skip_keyword (tracker, explicit_options, &text);
+      if (keyword == -1)
+       complete_on_enum (tracker, explicit_options, text, text);
+      else
+       {
+         tracker.advance_custom_word_point_by (copy - text);
+         text = copy;
+
+         symbol_name_match_type match_type
+           = get_explicit_location (location.get ())->func_name_match_type;
+         complete_address_and_linespec_locations (tracker, text, match_type);
+       }
+    }
   else
     {
-      /* This is an address or linespec location.
-        Right now both of these are handled by the (old) linespec
-        completer.  */
-      complete_files_symbols (tracker, text, word);
+      /* No options.  */
+      complete_address_and_linespec_locations (tracker, text,
+                                              symbol_name_match_type::WILD);
     }
+
+  /* Add matches for option names, if either:
+
+     - Some completer above found some matches, but the word point did
+       not advance (e.g., "b <tab>" finds all functions, or "b -<tab>"
+       matches all objc selectors), or;
+
+     - Some completer above advanced the word point, but found no
+       matches.
+  */
+  if ((text[0] == '-' || text[0] == '\0')
+      && (!tracker.have_completions ()
+         || tracker.custom_word_point () == saved_word_point))
+    {
+      tracker.set_custom_word_point (saved_word_point);
+      text = option_text;
+
+      if (found_probe_option == -1)
+       complete_on_enum (tracker, probe_options, text, text);
+      complete_on_enum (tracker, explicit_options, text, text);
+    }
+}
+
+/* The corresponding completer_handle_brkchars
+   implementation.  */
+
+static void
+location_completer_handle_brkchars (struct cmd_list_element *ignore,
+                                   completion_tracker &tracker,
+                                   const char *text,
+                                   const char *word_ignored)
+{
+  tracker.set_use_custom_word_point (true);
+
+  location_completer (ignore, tracker, text, NULL);
 }
 
 /* Helper for expression_completer which recursively adds field and
@@ -530,7 +1022,7 @@ location_completer (struct cmd_list_element *ignore,
 
 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;
@@ -567,7 +1059,7 @@ add_struct_fields (struct type *type, completion_list &output,
        {
          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.  */
@@ -577,32 +1069,28 @@ add_struct_fields (struct type *type, completion_list &output,
     }
 }
 
-/* Complete on expressions.  Often this means completing on symbol
-   names, but some language parsers also have support for completing
-   field names.  */
+/* See completer.h.  */
 
-static void
+void
 complete_expression (completion_tracker &tracker,
                     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 (;;)
        {
@@ -615,26 +1103,20 @@ complete_expression (completion_tracker &tracker,
       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)
     {
-      VEC (char_ptr) *result;
-      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);
 }
@@ -659,23 +1141,6 @@ set_rl_completer_word_break_characters (const char *break_chars)
   rl_completer_word_break_characters = (char *) break_chars;
 }
 
-/* See definition in completer.h.  */
-
-void
-set_gdb_completion_word_break_characters (completer_ftype *fn)
-{
-  const char *break_chars;
-
-  /* So far we are only interested in differentiating filename
-     completers from everything else.  */
-  if (fn == filename_completer)
-    break_chars = gdb_completer_file_name_break_characters;
-  else
-    break_chars = gdb_completer_command_word_break_characters;
-
-  set_rl_completer_word_break_characters (break_chars);
-}
-
 /* Complete on symbols.  */
 
 void
@@ -683,7 +1148,9 @@ symbol_completer (struct cmd_list_element *ignore,
                  completion_tracker &tracker,
                  const char *text, const char *word)
 {
-  collect_symbol_completion_matches (tracker, text, word);
+  collect_symbol_completion_matches (tracker, complete_symbol_mode::EXPRESSION,
+                                    symbol_name_match_type::EXPRESSION,
+                                    text, word);
 }
 
 /* Here are some useful test cases for completion.  FIXME: These
@@ -712,10 +1179,24 @@ symbol_completer (struct cmd_list_element *ignore,
 enum complete_line_internal_reason
 {
   /* Preliminary phase, called by gdb_completion_word_break_characters
-     function, is used to determine the correct set of chars that are
-     word delimiters depending on the current command in line_buffer.
-     No completion list should be generated; the return value should
-     be NULL.  This is checked by an assertion.  */
+     function, is used to either:
+
+     #1 - Determine the set of chars that are word delimiters
+         depending on the current command in line_buffer.
+
+     #2 - Manually advance RL_POINT to the "word break" point instead
+         of letting readline do it (based on too-simple character
+         matching).
+
+     Simpler completers that just pass a brkchars array to readline
+     (#1 above) must defer generating the completions to the main
+     phase (below).  No completion list should be generated in this
+     phase.
+
+     OTOH, completers that manually advance the word point(#2 above)
+     must set "use_custom_word_point" in the tracker and generate
+     their completion in this phase.  Note that this is the convenient
+     thing to do since they'll be parsing the input line anyway.  */
   handle_brkchars,
 
   /* Main phase, called by complete_line function, is used to get the
@@ -803,7 +1284,7 @@ complete_line_internal_1 (completion_tracker &tracker,
      on command strings (as opposed to strings supplied by the
      individual command completer functions, which can be any string)
      then we will switch to the special word break set for command
-     strings, which leaves out the '-' character used in some
+     strings, which leaves out the '-' and '.' character used in some
      commands.  */
   set_rl_completer_word_break_characters
     (current_language->la_word_break_characters());
@@ -831,10 +1312,13 @@ complete_line_internal_1 (completion_tracker &tracker,
       word = tmp_command + point - strlen (text);
     }
 
-  if (point == 0)
+  /* Move P up to the start of the command.  */
+  p = skip_spaces (p);
+
+  if (*p == '\0')
     {
-      /* An empty line we want to consider ambiguous; that is, it
-        could be any command.  */
+      /* An empty line is ambiguous; that is, it could be any
+        command.  */
       c = CMD_LIST_AMBIGUOUS;
       result_list = 0;
     }
@@ -849,6 +1333,8 @@ complete_line_internal_1 (completion_tracker &tracker,
       p++;
     }
 
+  tracker.advance_custom_word_point_by (p - tmp_command);
+
   if (!c)
     {
       /* It is an unrecognized command.  So there are no
@@ -861,7 +1347,7 @@ complete_line_internal_1 (completion_tracker &tracker,
       /* lookup_cmd_1 advances p up to the first ambiguous thing, but
         doesn't advance over that thing itself.  Do so now.  */
       q = p;
-      while (*q && (isalnum (*q) || *q == '-' || *q == '_'))
+      while (valid_cmd_char_p (*q))
        ++q;
       if (q != tmp_command + point)
        {
@@ -949,12 +1435,15 @@ complete_line_internal_1 (completion_tracker &tracker,
              q = p;
              while (q > tmp_command)
                {
-                 if (isalnum (q[-1]) || q[-1] == '-' || q[-1] == '_')
+                 if (valid_cmd_char_p (q[-1]))
                    --q;
                  else
                    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);
@@ -1001,14 +1490,14 @@ complete_line_internal (completion_tracker &tracker,
                        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;
     }
 }
 
@@ -1024,7 +1513,25 @@ int max_completions = 200;
 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);
+}
+
+/* See completer.h.  */
+
+void
+completion_tracker::discard_completions ()
+{
+  xfree (m_lowest_common_denominator);
+  m_lowest_common_denominator = NULL;
+
+  m_lowest_common_denominator_unique = false;
+
+  m_entries_vec.clear ();
+
+  htab_delete (m_entries_hash);
+  m_entries_hash = htab_create_alloc (INITIAL_COMPLETION_HTAB_SIZE,
+                                     htab_hash_string, streq_hash,
                                      NULL, xcalloc, xfree);
 }
 
@@ -1039,7 +1546,10 @@ completion_tracker::~completion_tracker ()
 /* See completer.h.  */
 
 bool
-completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::maybe_add_completion
+  (gdb::unique_xmalloc_ptr<char> name,
+   completion_match_for_lcd *match_for_lcd,
+   const char *text, const char *word)
 {
   void **slot;
 
@@ -1052,9 +1562,18 @@ completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
   slot = htab_find_slot (m_entries_hash, name.get (), INSERT);
   if (*slot == HTAB_EMPTY_ENTRY)
     {
-      const char *match_for_lcd_str = name.get ();
+      const char *match_for_lcd_str = NULL;
+
+      if (match_for_lcd != NULL)
+       match_for_lcd_str = match_for_lcd->finish ();
 
-      recompute_lowest_common_denominator (match_for_lcd_str);
+      if (match_for_lcd_str == NULL)
+       match_for_lcd_str = name.get ();
+
+      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));
@@ -1066,9 +1585,11 @@ completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
 /* See completer.h.  */
 
 void
-completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name,
+                                   completion_match_for_lcd *match_for_lcd,
+                                   const char *text, const char *word)
 {
-  if (!maybe_add_completion (std::move (name)))
+  if (!maybe_add_completion (std::move (name), match_for_lcd, text, word))
     throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
 }
 
@@ -1081,6 +1602,105 @@ completion_tracker::add_completions (completion_list &&list)
     add_completion (std::move (candidate));
 }
 
+/* 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.
@@ -1149,10 +1769,7 @@ signal_completer (struct cmd_list_element *ignore,
        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));
     }
 }
 
@@ -1191,10 +1808,7 @@ reg_or_group_completer_1 (completion_tracker &tracker,
           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));
        }
     }
 
@@ -1208,10 +1822,7 @@ reg_or_group_completer_1 (completion_tracker &tracker,
        {
          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));
        }
     }
 }
@@ -1258,12 +1869,27 @@ 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.  */
 
@@ -1280,6 +1906,30 @@ gdb_completion_word_break_characters_throw ()
   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;
 }
 
@@ -1289,39 +1939,66 @@ gdb_completion_word_break_characters ()
   /* 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.  */
 
+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_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'
@@ -1336,6 +2013,14 @@ completion_tracker::recompute_lowest_common_denominator (const char *new_match)
     }
 }
 
+/* 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.
 
@@ -1378,7 +2063,7 @@ expand_preserving_ws (const char *orig, size_t orig_len,
        {
          while (p_orig < orig_end && *p_orig == ' ')
            res += *p_orig++;
-         p_lcd = skip_spaces_const (p_lcd);
+         p_lcd = skip_spaces (p_lcd);
        }
       else
        {
@@ -1423,12 +2108,21 @@ completion_tracker::build_completion_result (const char *text,
 
   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 we already have a space at the end of the match, tell
-        readline to skip appending another.  */
+      /* 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
-       = (match_list[0][strlen (match_list[0]) - 1] == ' ');
+       = (suppress_append_ws ()
+          || match_list[0][strlen (match_list[0]) - 1] == ' ');
 
       return completion_result (match_list, 1, completion_suppress_append);
     }
@@ -1492,14 +2186,6 @@ completion_result::release_match_list ()
   return ret;
 }
 
-/* Compare C strings for std::sort.  */
-
-static bool
-compare_cstrings (const char *str1, const char *str2)
-{
-  return strcmp (str1, str2) < 0;
-}
-
 /* See completer.h  */
 
 void
@@ -1555,14 +2241,20 @@ completion_result::reset_match_list ()
 static char **
 gdb_rl_attempted_completion_function_throw (const char *text, int start, int end)
 {
-  /* Completers must be called twice.  If rl_point (i.e., END) is at
-     column 0, then readline skips the the handle_brkchars phase, and
-     so we create a tracker now in that case too.  */
-  delete current_completion.tracker;
-  current_completion.tracker = new completion_tracker ();
+  /* 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);
+      complete_line (*current_completion.tracker, text,
+                    rl_line_buffer, rl_point);
+    }
 
   completion_tracker &tracker = *current_completion.tracker;
 
@@ -1580,6 +2272,10 @@ gdb_rl_attempted_completion_function_throw (const char *text, int start, int end
 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.  */
@@ -1590,14 +2286,13 @@ gdb_rl_attempted_completion_function (const char *text, int start, int end)
   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;
 }
@@ -2239,8 +2934,6 @@ gdb_display_match_list (char **matches, int len, int max,
        }
     }
 }
-\f
-extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
 
 void
 _initialize_completer (void)
This page took 0.039929 seconds and 4 git commands to generate.