Fix crash with "maint print arc"
[binutils-gdb.git] / gdb / utils.c
index e27a8818b94cb8392f77a59ad1e5dd7732d9ea11..f9dc4f234310c6bda1807a27507ee56f05472e13 100644 (file)
@@ -1,6 +1,6 @@
 /* General utility routines for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2021 Free Software Foundation, Inc.
+   Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -48,7 +48,7 @@
 #include "annotate.h"
 #include "filenames.h"
 #include "symfile.h"
-#include "gdb_obstack.h"
+#include "gdbsupport/gdb_obstack.h"
 #include "gdbcore.h"
 #include "top.h"
 #include "main.h"
@@ -63,7 +63,7 @@
 #include <chrono>
 
 #include "interps.h"
-#include "gdb_regex.h"
+#include "gdbsupport/gdb_regex.h"
 #include "gdbsupport/job-control.h"
 #include "gdbsupport/selftest.h"
 #include "gdbsupport/gdb_optional.h"
 #include "cli-out.h"
 #include "gdbsupport/gdb-safe-ctype.h"
 #include "bt-utils.h"
+#include "gdbsupport/buildargv.h"
+#include "pager.h"
+#include "run-on-main-thread.h"
 
 void (*deprecated_error_begin_hook) (void);
 
 /* Prototypes for local functions */
 
-static void vfprintf_maybe_filtered (struct ui_file *, const char *,
-                                    va_list, bool)
-  ATTRIBUTE_PRINTF (2, 0);
-
-static void fputs_maybe_filtered (const char *, struct ui_file *, int);
-
-static void prompt_for_continue (void);
-
 static void set_screen_size (void);
 static void set_width (void);
 
@@ -102,7 +97,7 @@ static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
 
 /* A flag indicating whether to timestamp debugging messages.  */
 
-static bool debug_timestamp = false;
+bool debug_timestamp = false;
 
 /* True means that strings with character values >0x7F should be printed
    as octal escapes.  False means just print the value (e.g. it's an
@@ -113,9 +108,9 @@ static void
 show_sevenbit_strings (struct ui_file *file, int from_tty,
                       struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("Printing of 8-bit characters "
-                           "in strings as \\nnn is %s.\n"),
-                   value);
+  gdb_printf (file, _("Printing of 8-bit characters "
+                     "in strings as \\nnn is %s.\n"),
+             value);
 }
 
 /* String to be printed before warning messages, if any.  */
@@ -127,7 +122,7 @@ static void
 show_pagination_enabled (struct ui_file *file, int from_tty,
                         struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("State of pagination is %s.\n"), value);
+  gdb_printf (file, _("State of pagination is %s.\n"), value);
 }
 
 \f
@@ -152,13 +147,10 @@ vwarning (const char *string, va_list args)
          term_state.emplace ();
          target_terminal::ours_for_output ();
        }
-      if (filtered_printing_initialized ())
-       wrap_here ("");         /* Force out any buffered output.  */
-      gdb_flush (gdb_stdout);
       if (warning_pre_print)
-       fputs_unfiltered (warning_pre_print, gdb_stderr);
-      vfprintf_unfiltered (gdb_stderr, string, args);
-      fprintf_unfiltered (gdb_stderr, "\n");
+       gdb_puts (warning_pre_print, gdb_stderr);
+      gdb_vprintf (gdb_stderr, string, args);
+      gdb_printf (gdb_stderr, "\n");
     }
 }
 
@@ -186,7 +178,7 @@ abort_with_message (const char *msg)
   if (current_ui == NULL)
     fputs (msg, stderr);
   else
-    fputs_unfiltered (msg, gdb_stderr);
+    gdb_puts (msg, gdb_stderr);
 
   abort ();            /* ARI: abort */
 }
@@ -246,10 +238,10 @@ can_dump_core (enum resource_limit_kind limit_kind)
 void
 warn_cant_dump_core (const char *reason)
 {
-  fprintf_unfiltered (gdb_stderr,
-                     _("%s\nUnable to dump core, use `ulimit -c"
-                       " unlimited' before executing GDB next time.\n"),
-                     reason);
+  gdb_printf (gdb_stderr,
+             _("%s\nUnable to dump core, use `ulimit -c"
+               " unlimited' before executing GDB next time.\n"),
+             reason);
 }
 
 /* Check whether GDB will be able to dump core using the dump_core
@@ -314,6 +306,16 @@ struct internal_problem
   bool should_print_backtrace;
 };
 
+/* Return true if the readline callbacks have been initialized for UI.
+   This is always true once GDB is fully initialized, but during the early
+   startup phase this is initially false.  */
+
+static bool
+readline_initialized (struct ui *ui)
+{
+  return ui->call_readline != nullptr;
+}
+
 /* Report a problem, internal to GDB, to the user.  Once the problem
    has been reported, and assuming GDB didn't quit, the caller can
    either allow execution to resume or throw an error.  */
@@ -386,8 +388,9 @@ internal_vproblem (struct internal_problem *problem,
   if (problem->should_quit != internal_problem_ask
       || !confirm
       || !filtered_printing_initialized ()
+      || !readline_initialized (current_ui)
       || problem->should_print_backtrace)
-    fprintf_unfiltered (gdb_stderr, "%s\n", reason.c_str ());
+    gdb_printf (gdb_stderr, "%s\n", reason.c_str ());
 
   if (problem->should_print_backtrace)
     gdb_internal_backtrace ();
@@ -397,7 +400,8 @@ internal_vproblem (struct internal_problem *problem,
       /* Default (yes/batch case) is to quit GDB.  When in batch mode
         this lessens the likelihood of GDB going into an infinite
         loop.  */
-      if (!confirm || !filtered_printing_initialized ())
+      if (!confirm || !filtered_printing_initialized ()
+         || !readline_initialized (current_ui))
        quit_p = 1;
       else
        quit_p = query (_("%s\nQuit this debugging session? "),
@@ -410,17 +414,19 @@ internal_vproblem (struct internal_problem *problem,
   else
     internal_error (__FILE__, __LINE__, _("bad switch"));
 
-  fputs_unfiltered (_("\nThis is a bug, please report it."), gdb_stderr);
+  gdb_puts (_("\nThis is a bug, please report it."), gdb_stderr);
   if (REPORT_BUGS_TO[0])
-    fprintf_unfiltered (gdb_stderr, _("  For instructions, see:\n%s."),
-                       REPORT_BUGS_TO);
-  fputs_unfiltered ("\n\n", gdb_stderr);
+    gdb_printf (gdb_stderr, _("  For instructions, see:\n%ps."),
+               styled_string (file_name_style.style (),
+                              REPORT_BUGS_TO));
+  gdb_puts ("\n\n", gdb_stderr);
 
   if (problem->should_dump_core == internal_problem_ask)
     {
       if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ()))
        dump_core_p = 0;
-      else if (!filtered_printing_initialized ())
+      else if (!filtered_printing_initialized ()
+              || !readline_initialized (current_ui))
        dump_core_p = 1;
       else
        {
@@ -656,10 +662,7 @@ void
 print_sys_errmsg (const char *string, int errcode)
 {
   const char *err = safe_strerror (errcode);
-  /* We want anything which was printed on stdout to come out first, before
-     this message.  */
-  gdb_flush (gdb_stdout);
-  fprintf_unfiltered (gdb_stderr, "%s: %s.\n", string, err);
+  gdb_printf (gdb_stderr, "%s: %s.\n", string, err);
 }
 
 /* Control C eventually causes this to be called, at a convenient time.  */
@@ -693,6 +696,9 @@ quit (void)
 void
 maybe_quit (void)
 {
+  if (!is_main_thread ())
+    return;
+
   if (sync_quit_force_run)
     quit ();
 
@@ -779,20 +785,6 @@ uinteger_pow (ULONGEST v1, LONGEST v2)
     }
 }
 
-void
-print_spaces (int n, struct ui_file *file)
-{
-  fputs_unfiltered (n_spaces (n), file);
-}
-
-/* Print a host address.  */
-
-void
-gdb_print_host_address_1 (const void *addr, struct ui_file *stream)
-{
-  fprintf_filtered (stream, "%s", host_address_to_string (addr));
-}
-
 \f
 
 /* An RAII class that sets up to handle input and then tears down
@@ -894,12 +886,12 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
     {
       target_terminal::scoped_restore_terminal_state term_state;
       target_terminal::ours_for_output ();
-      wrap_here ("");
-      vfprintf_filtered (gdb_stdout, ctlstr, args);
+      gdb_stdout->wrap_here (0);
+      gdb_vprintf (gdb_stdout, ctlstr, args);
 
-      printf_filtered (_("(%s or %s) [answered %c; "
-                        "input not from terminal]\n"),
-                      y_string, n_string, def_answer);
+      gdb_printf (_("(%s or %s) [answered %c; "
+                   "input not from terminal]\n"),
+                 y_string, n_string, def_answer);
 
       return def_value;
     }
@@ -934,7 +926,7 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
 
       if (response == NULL)    /* C-d  */
        {
-         printf_filtered ("EOF [assumed %c]\n", def_answer);
+         gdb_printf ("EOF [assumed %c]\n", def_answer);
          retval = def_value;
          break;
        }
@@ -961,15 +953,15 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
          break;
        }
       /* Invalid entries are not defaulted and require another selection.  */
-      printf_filtered (_("Please answer %s or %s.\n"),
-                      y_string, n_string);
+      gdb_printf (_("Please answer %s or %s.\n"),
+                 y_string, n_string);
     }
 
   /* Add time spend in this routine to prompt_for_continue_wait_time.  */
   prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
-    printf_filtered (("\n\032\032post-query\n"));
+    gdb_printf (("\n\032\032post-query\n"));
   return retval;
 }
 \f
@@ -1091,7 +1083,7 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
       case '6':
       case '7':
        {
-         int i = host_hex_value (c);
+         int i = fromhex (c);
          int count = 0;
          while (++count < 3)
            {
@@ -1100,7 +1092,7 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
                {
                  (*string_ptr)++;
                  i *= 8;
-                 i += host_hex_value (c);
+                 i += fromhex (c);
                }
              else
                {
@@ -1143,103 +1135,6 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
   return target_char;
 }
 \f
-/* Print the character C on STREAM as part of the contents of a literal
-   string whose delimiter is QUOTER.  Note that this routine should only
-   be called for printing things which are independent of the language
-   of the program being debugged.
-
-   printchar will normally escape backslashes and instances of QUOTER. If
-   QUOTER is 0, printchar won't escape backslashes or any quoting character.
-   As a side effect, if you pass the backslash character as the QUOTER,
-   printchar will escape backslashes as usual, but not any other quoting
-   character. */
-
-static void
-printchar (int c, do_fputc_ftype do_fputc, ui_file *stream, int quoter)
-{
-  c &= 0xFF;                   /* Avoid sign bit follies */
-
-  if (c < 0x20 ||              /* Low control chars */
-      (c >= 0x7F && c < 0xA0) ||       /* DEL, High controls */
-      (sevenbit_strings && c >= 0x80))
-    {                          /* high order bit set */
-      do_fputc ('\\', stream);
-
-      switch (c)
-       {
-       case '\n':
-         do_fputc ('n', stream);
-         break;
-       case '\b':
-         do_fputc ('b', stream);
-         break;
-       case '\t':
-         do_fputc ('t', stream);
-         break;
-       case '\f':
-         do_fputc ('f', stream);
-         break;
-       case '\r':
-         do_fputc ('r', stream);
-         break;
-       case '\033':
-         do_fputc ('e', stream);
-         break;
-       case '\007':
-         do_fputc ('a', stream);
-         break;
-       default:
-         {
-           do_fputc ('0' + ((c >> 6) & 0x7), stream);
-           do_fputc ('0' + ((c >> 3) & 0x7), stream);
-           do_fputc ('0' + ((c >> 0) & 0x7), stream);
-           break;
-         }
-       }
-    }
-  else
-    {
-      if (quoter != 0 && (c == '\\' || c == quoter))
-       do_fputc ('\\', stream);
-      do_fputc (c, stream);
-    }
-}
-
-/* Print the character C on STREAM as part of the contents of a
-   literal string whose delimiter is QUOTER.  Note that these routines
-   should only be call for printing things which are independent of
-   the language of the program being debugged.  */
-
-void
-fputstr_filtered (const char *str, int quoter, struct ui_file *stream)
-{
-  while (*str)
-    printchar (*str++, fputc_filtered, stream, quoter);
-}
-
-void
-fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream)
-{
-  while (*str)
-    printchar (*str++, fputc_unfiltered, stream, quoter);
-}
-
-void
-fputstrn_filtered (const char *str, int n, int quoter,
-                  struct ui_file *stream)
-{
-  for (int i = 0; i < n; i++)
-    printchar (str[i], fputc_filtered, stream, quoter);
-}
-
-void
-fputstrn_unfiltered (const char *str, int n, int quoter,
-                    do_fputc_ftype do_fputc, struct ui_file *stream)
-{
-  for (int i = 0; i < n; i++)
-    printchar (str[i], do_fputc, stream, quoter);
-}
-\f
 
 /* Number of lines per page or UINT_MAX if paging is disabled.  */
 static unsigned int lines_per_page;
@@ -1247,9 +1142,9 @@ static void
 show_lines_per_page (struct ui_file *file, int from_tty,
                     struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file,
-                   _("Number of lines gdb thinks are in a page is %s.\n"),
-                   value);
+  gdb_printf (file,
+             _("Number of lines gdb thinks are in a page is %s.\n"),
+             value);
 }
 
 /* Number of chars per line or UINT_MAX if line folding is disabled.  */
@@ -1258,10 +1153,10 @@ static void
 show_chars_per_line (struct ui_file *file, int from_tty,
                     struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file,
-                   _("Number of characters gdb thinks "
-                     "are in a line is %s.\n"),
-                   value);
+  gdb_printf (file,
+             _("Number of characters gdb thinks "
+               "are in a line is %s.\n"),
+             value);
 }
 
 /* Current count of lines printed on this page, chars on this line.  */
@@ -1273,7 +1168,7 @@ static bool pagination_disabled_for_command;
 
 /* Buffer and start column of buffered text, for doing smarter word-
    wrapping.  When someone calls wrap_here(), we start buffering output
-   that comes through fputs_filtered().  If we see a newline, we just
+   that comes through gdb_puts().  If we see a newline, we just
    spit it out and forget about the wrap_here().  If we see another
    wrap_here(), we spit it out and remember the newer one.  If we see
    the end of the line, we spit out a newline, the indent, and then
@@ -1281,20 +1176,6 @@ static bool pagination_disabled_for_command;
 
 static bool filter_initialized = false;
 
-/* Contains characters which are waiting to be output (they have
-   already been counted in chars_printed).  */
-static std::string wrap_buffer;
-
-/* String to indent by if the wrap occurs.  Must not be NULL if wrap_column
-   is non-zero.  */
-static const char *wrap_indent;
-
-/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
-   is not in effect.  */
-static int wrap_column;
-
-/* The style applied at the time that wrap_here was called.  */
-static ui_file_style wrap_style;
 \f
 
 /* Initialize the number of lines per page and chars per line.  */
@@ -1426,7 +1307,6 @@ set_width (void)
   if (chars_per_line == 0)
     init_page_info ();
 
-  wrap_buffer.clear ();
   filter_initialized = true;
 }
 
@@ -1455,55 +1335,28 @@ set_screen_width_and_height (int width, int height)
   set_width ();
 }
 
-/* The currently applied style.  */
-
-static ui_file_style applied_style;
-
-/* Emit an ANSI style escape for STYLE.  If STREAM is nullptr, emit to
-   the wrap buffer; otherwise emit to STREAM.  */
-
-static void
-emit_style_escape (const ui_file_style &style,
-                  struct ui_file *stream = nullptr)
+void
+pager_file::emit_style_escape (const ui_file_style &style)
 {
-  if (applied_style != style)
+  if (can_emit_style_escape () && style != m_applied_style)
     {
-      applied_style = style;
-
-      if (stream == nullptr)
-       wrap_buffer.append (style.to_ansi ());
+      m_applied_style = style;
+      if (m_paging)
+       m_stream->emit_style_escape (style);
       else
-       stream->puts (style.to_ansi ().c_str ());
+       m_wrap_buffer.append (style.to_ansi ());
     }
 }
 
-/* Set the current output style.  This will affect future uses of the
-   _filtered output functions.  */
-
-static void
-set_output_style (struct ui_file *stream, const ui_file_style &style)
-{
-  if (!stream->can_emit_style_escape ())
-    return;
-
-  /* Note that we may not pass STREAM here, when we want to emit to
-     the wrap buffer, not directly to STREAM.  */
-  if (stream == gdb_stdout)
-    stream = nullptr;
-  emit_style_escape (style, stream);
-}
-
-/* See utils.h.  */
+/* See pager.h.  */
 
 void
-reset_terminal_style (struct ui_file *stream)
+pager_file::reset_style ()
 {
-  if (stream->can_emit_style_escape ())
+  if (can_emit_style_escape ())
     {
-      /* Force the setting, regardless of what we think the setting
-        might already be.  */
-      applied_style = ui_file_style ();
-      wrap_buffer.append (applied_style.to_ansi ());
+      m_applied_style = ui_file_style ();
+      m_wrap_buffer.append (m_applied_style.to_ansi ());
     }
 }
 
@@ -1512,8 +1365,8 @@ reset_terminal_style (struct ui_file *stream)
    telling users what to do in the prompt is more user-friendly than
    expecting them to think of Ctrl-C/SIGINT.  */
 
-static void
-prompt_for_continue (void)
+void
+pager_file::prompt_for_continue ()
 {
   char cont_prompt[120];
   /* Used to add duration we waited for user to respond to
@@ -1522,12 +1375,13 @@ prompt_for_continue (void)
   steady_clock::time_point prompt_started = steady_clock::now ();
   bool disable_pagination = pagination_disabled_for_command;
 
+  scoped_restore save_paging = make_scoped_restore (&m_paging, true);
+
   /* Clear the current styling.  */
-  if (gdb_stdout->can_emit_style_escape ())
-    emit_style_escape (ui_file_style (), gdb_stdout);
+  m_stream->emit_style_escape (ui_file_style ());
 
   if (annotation_level > 1)
-    printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));
+    m_stream->puts (("\n\032\032pre-prompt-for-continue\n"));
 
   strcpy (cont_prompt,
          "--Type <RET> for more, q to quit, "
@@ -1550,7 +1404,7 @@ prompt_for_continue (void)
   prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
 
   if (annotation_level > 1)
-    printf_unfiltered (("\n\032\032post-prompt-for-continue\n"));
+    m_stream->puts (("\n\032\032post-prompt-for-continue\n"));
 
   if (ignore != NULL)
     {
@@ -1601,24 +1455,28 @@ reinitialize_more_filter (void)
   pagination_disabled_for_command = false;
 }
 
-/* Flush the wrap buffer to STREAM, if necessary.  */
-
-static void
-flush_wrap_buffer (struct ui_file *stream)
+void
+pager_file::flush_wrap_buffer ()
 {
-  if (stream == gdb_stdout && !wrap_buffer.empty ())
+  if (!m_paging && !m_wrap_buffer.empty ())
     {
-      stream->puts (wrap_buffer.c_str ());
-      wrap_buffer.clear ();
+      m_stream->puts (m_wrap_buffer.c_str ());
+      m_wrap_buffer.clear ();
     }
 }
 
+void
+pager_file::flush ()
+{
+  flush_wrap_buffer ();
+  m_stream->flush ();
+}
+
 /* See utils.h.  */
 
 void
 gdb_flush (struct ui_file *stream)
 {
-  flush_wrap_buffer (stream);
   stream->flush ();
 }
 
@@ -1630,65 +1488,42 @@ get_chars_per_line ()
   return chars_per_line;
 }
 
-/* Indicate that if the next sequence of characters overflows the line,
-   a newline should be inserted here rather than when it hits the end.
-   If INDENT is non-null, it is a string to be printed to indent the
-   wrapped part on the next line.  INDENT must remain accessible until
-   the next call to wrap_here() or until a newline is printed through
-   fputs_filtered().
-
-   If the line is already overfull, we immediately print a newline and
-   the indentation, and disable further wrapping.
-
-   If we don't know the width of lines, but we know the page height,
-   we must not wrap words, but should still keep track of newlines
-   that were explicitly printed.
-
-   INDENT should not contain tabs, as that will mess up the char count
-   on the next line.  FIXME.
-
-   This routine is guaranteed to force out any output which has been
-   squirreled away in the wrap_buffer, so wrap_here ((char *)0) can be
-   used to force out output from the wrap_buffer.  */
+/* See ui-file.h.  */
 
 void
-wrap_here (const char *indent)
+pager_file::wrap_here (int indent)
 {
   /* This should have been allocated, but be paranoid anyway.  */
   gdb_assert (filter_initialized);
 
-  flush_wrap_buffer (gdb_stdout);
+  flush_wrap_buffer ();
   if (chars_per_line == UINT_MAX)      /* No line overflow checking.  */
     {
-      wrap_column = 0;
+      m_wrap_column = 0;
     }
   else if (chars_printed >= chars_per_line)
     {
-      puts_filtered ("\n");
-      if (indent != NULL)
-       puts_filtered (indent);
-      wrap_column = 0;
+      this->puts ("\n");
+      if (indent != 0)
+       this->puts (n_spaces (indent));
+      m_wrap_column = 0;
     }
   else
     {
-      wrap_column = chars_printed;
-      if (indent == NULL)
-       wrap_indent = "";
-      else
-       wrap_indent = indent;
-      wrap_style = applied_style;
+      m_wrap_column = chars_printed;
+      m_wrap_indent = indent;
+      m_wrap_style = m_applied_style;
     }
 }
 
-/* Print input string to gdb_stdout, filtered, with wrap, 
-   arranging strings in columns of n chars.  String can be
-   right or left justified in the column.  Never prints 
-   trailing spaces.  String should never be longer than
-   width.  FIXME: this could be useful for the EXAMINE 
-   command, which currently doesn't tabulate very well.  */
+/* Print input string to gdb_stdout arranging strings in columns of n
+   chars.  String can be right or left justified in the column.  Never
+   prints trailing spaces.  String should never be longer than width.
+   FIXME: this could be useful for the EXAMINE command, which
+   currently doesn't tabulate very well.  */
 
 void
-puts_filtered_tabular (char *string, int width, int right)
+puts_tabular (char *string, int width, int right)
 {
   int spaces = 0;
   int stringlen;
@@ -1697,13 +1532,13 @@ puts_filtered_tabular (char *string, int width, int right)
   gdb_assert (chars_per_line > 0);
   if (chars_per_line == UINT_MAX)
     {
-      fputs_filtered (string, gdb_stdout);
-      fputs_filtered ("\n", gdb_stdout);
+      gdb_puts (string);
+      gdb_puts ("\n");
       return;
     }
 
   if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
-    fputs_filtered ("\n", gdb_stdout);
+    gdb_puts ("\n");
 
   if (width >= chars_per_line)
     width = chars_per_line - 1;
@@ -1720,8 +1555,8 @@ puts_filtered_tabular (char *string, int width, int right)
   while (spaces--)
     spacebuf[spaces] = ' ';
 
-  fputs_filtered (spacebuf, gdb_stdout);
-  fputs_filtered (string, gdb_stdout);
+  gdb_puts (spacebuf);
+  gdb_puts (string);
 }
 
 
@@ -1735,55 +1570,43 @@ begin_line (void)
 {
   if (chars_printed > 0)
     {
-      puts_filtered ("\n");
+      gdb_puts ("\n");
     }
 }
 
-
-/* Like fputs but if FILTER is true, pause after every screenful.
-
-   Regardless of FILTER can wrap at points other than the final
-   character of a line.
-
-   Unlike fputs, fputs_maybe_filtered does not return a value.
-   It is OK for LINEBUFFER to be NULL, in which case just don't print
-   anything.
-
-   Note that a longjmp to top level may occur in this routine (only if
-   FILTER is true) (since prompt_for_continue may do so) so this
-   routine should not be called when cleanups are not in place.  */
-
-static void
-fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
-                     int filter)
+void
+pager_file::puts (const char *linebuffer)
 {
   const char *lineptr;
 
   if (linebuffer == 0)
     return;
 
-  /* Don't do any filtering if it is disabled.  */
-  if (stream != gdb_stdout
-      || !pagination_enabled
-      || pagination_disabled_for_command
-      || batch_flag
+  /* Don't do any filtering or wrapping if both are disabled.  */
+  if (batch_flag
       || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)
       || top_level_interpreter () == NULL
       || top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ())
     {
-      flush_wrap_buffer (stream);
-      stream->puts (linebuffer);
+      flush_wrap_buffer ();
+      m_stream->puts (linebuffer);
       return;
     }
 
   auto buffer_clearer
     = make_scope_exit ([&] ()
                       {
-                        wrap_buffer.clear ();
-                        wrap_column = 0;
-                        wrap_indent = "";
+                        m_wrap_buffer.clear ();
+                        m_wrap_column = 0;
+                        m_wrap_indent = 0;
                       });
 
+  /* If the user does "set height 1" then the pager will exhibit weird
+     behavior.  This is pathological, though, so don't allow it.  */
+  const unsigned int lines_allowed = (lines_per_page > 1
+                                     ? lines_per_page - 1
+                                     : 1);
+
   /* Go through and output each character.  Show line extension
      when this is necessary; prompt user for new page when this is
      necessary.  */
@@ -1794,8 +1617,9 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
       /* Possible new page.  Note that PAGINATION_DISABLED_FOR_COMMAND
         might be set during this loop, so we must continue to check
         it here.  */
-      if (filter && (lines_printed >= lines_per_page - 1)
-         && !pagination_disabled_for_command)
+      if (pagination_enabled
+         && !pagination_disabled_for_command
+         && lines_printed >= lines_allowed)
        prompt_for_continue ();
 
       while (*lineptr && *lineptr != '\n')
@@ -1805,7 +1629,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
          /* Print a single line.  */
          if (*lineptr == '\t')
            {
-             wrap_buffer.push_back ('\t');
+             m_wrap_buffer.push_back ('\t');
              /* Shifting right by 3 produces the number of tab stops
                 we have already passed, and then adding one and
                 shifting left 3 advances to the next tab stop.  */
@@ -1815,20 +1639,20 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
          else if (*lineptr == '\033'
                   && skip_ansi_escape (lineptr, &skip_bytes))
            {
-             wrap_buffer.append (lineptr, skip_bytes);
+             m_wrap_buffer.append (lineptr, skip_bytes);
              /* Note that we don't consider this a character, so we
                 don't increment chars_printed here.  */
              lineptr += skip_bytes;
            }
          else if (*lineptr == '\r')
            {
-             wrap_buffer.push_back (*lineptr);
+             m_wrap_buffer.push_back (*lineptr);
              chars_printed = 0;
              lineptr++;
            }
          else
            {
-             wrap_buffer.push_back (*lineptr);
+             m_wrap_buffer.push_back (*lineptr);
              chars_printed++;
              lineptr++;
            }
@@ -1843,12 +1667,12 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
                 prompt is given; and to avoid emitting style
                 sequences in the middle of a run of text, we track
                 this as well.  */
-             ui_file_style save_style = applied_style;
+             ui_file_style save_style = m_applied_style;
              bool did_paginate = false;
 
              chars_printed = 0;
              lines_printed++;
-             if (wrap_column)
+             if (m_wrap_column)
                {
                  /* We are about to insert a newline at an historic
                     location in the WRAP_BUFFER.  Before we do we want to
@@ -1856,77 +1680,60 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
                     need to insert an escape sequence we must restore the
                     current applied style to how it was at the WRAP_COLUMN
                     location.  */
-                 applied_style = wrap_style;
-                 if (stream->can_emit_style_escape ())
-                   emit_style_escape (ui_file_style (), stream);
+                 m_applied_style = m_wrap_style;
+                 m_stream->emit_style_escape (ui_file_style ());
                  /* If we aren't actually wrapping, don't output
                     newline -- if chars_per_line is right, we
                     probably just overflowed anyway; if it's wrong,
                     let us keep going.  */
-                 /* XXX: The ideal thing would be to call
-                    'stream->putc' here, but we can't because it
-                    currently calls 'fputc_unfiltered', which ends up
-                    calling us, which generates an infinite
-                    recursion.  */
-                 stream->puts ("\n");
+                 m_stream->puts ("\n");
                }
              else
-               flush_wrap_buffer (stream);
+               this->flush_wrap_buffer ();
 
              /* Possible new page.  Note that
                 PAGINATION_DISABLED_FOR_COMMAND might be set during
                 this loop, so we must continue to check it here.  */
-             if (lines_printed >= lines_per_page - 1
-                 && !pagination_disabled_for_command)
+             if (pagination_enabled
+                 && !pagination_disabled_for_command
+                 && lines_printed >= lines_allowed)
                {
                  prompt_for_continue ();
                  did_paginate = true;
                }
 
              /* Now output indentation and wrapped string.  */
-             if (wrap_column)
+             if (m_wrap_column)
                {
-                 stream->puts (wrap_indent);
+                 m_stream->puts (n_spaces (m_wrap_indent));
 
                  /* Having finished inserting the wrapping we should
                     restore the style as it was at the WRAP_COLUMN.  */
-                 if (stream->can_emit_style_escape ())
-                   emit_style_escape (wrap_style, stream);
+                 m_stream->emit_style_escape (m_wrap_style);
 
                  /* The WRAP_BUFFER will still contain content, and that
                     content might set some alternative style.  Restore
                     APPLIED_STYLE as it was before we started wrapping,
                     this reflects the current style for the last character
                     in WRAP_BUFFER.  */
-                 applied_style = save_style;
+                 m_applied_style = save_style;
 
-                 /* FIXME, this strlen is what prevents wrap_indent from
-                    containing tabs.  However, if we recurse to print it
-                    and count its chars, we risk trouble if wrap_indent is
-                    longer than (the user settable) chars_per_line.
-                    Note also that this can set chars_printed > chars_per_line
+                 /* Note that this can set chars_printed > chars_per_line
                     if we are printing a long string.  */
-                 chars_printed = strlen (wrap_indent)
-                   + (save_chars - wrap_column);
-                 wrap_column = 0;      /* And disable fancy wrap */
+                 chars_printed = m_wrap_indent + (save_chars - m_wrap_column);
+                 m_wrap_column = 0;    /* And disable fancy wrap */
                }
-             else if (did_paginate && stream->can_emit_style_escape ())
-               emit_style_escape (save_style, stream);
+             else if (did_paginate)
+               m_stream->emit_style_escape (save_style);
            }
        }
 
       if (*lineptr == '\n')
        {
          chars_printed = 0;
-         wrap_here ((char *) 0);       /* Spit out chars, cancel
-                                          further wraps.  */
+         wrap_here (0); /* Spit out chars, cancel further wraps.  */
          lines_printed++;
-         /* XXX: The ideal thing would be to call
-            'stream->putc' here, but we can't because it
-            currently calls 'fputc_unfiltered', which ends up
-            calling us, which generates an infinite
-            recursion.  */
-         stream->puts ("\n");
+         m_stream->puts ("\n");
          lineptr++;
        }
     }
@@ -1935,37 +1742,64 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
 }
 
 void
-fputs_filtered (const char *linebuffer, struct ui_file *stream)
+pager_file::write (const char *buf, long length_buf)
 {
-  fputs_maybe_filtered (linebuffer, stream, 1);
+  /* We have to make a string here because the pager uses
+     skip_ansi_escape, which requires NUL-termination.  */
+  std::string str (buf, length_buf);
+  this->puts (str.c_str ());
 }
 
-void
-fputs_unfiltered (const char *linebuffer, struct ui_file *stream)
+#if GDB_SELF_TEST
+
+/* Test that disabling the pager does not also disable word
+   wrapping.  */
+
+static void
+test_pager ()
 {
-  fputs_maybe_filtered (linebuffer, stream, 0);
+  string_file *strfile = new string_file ();
+  pager_file pager (strfile);
+
+  /* Make sure the pager is disabled.  */
+  scoped_restore save_enabled
+    = make_scoped_restore (&pagination_enabled, false);
+  scoped_restore save_disabled
+    = make_scoped_restore (&pagination_disabled_for_command, false);
+  scoped_restore save_batch
+    = make_scoped_restore (&batch_flag, false);
+  scoped_restore save_lines
+    = make_scoped_restore (&lines_per_page, 50);
+  /* Make it easy to word wrap.  */
+  scoped_restore save_chars
+    = make_scoped_restore (&chars_per_line, 15);
+  scoped_restore save_printed
+    = make_scoped_restore (&chars_printed, 0);
+
+  pager.puts ("aaaaaaaaaaaa");
+  pager.wrap_here (2);
+  pager.puts ("bbbbbbbbbbbb\n");
+
+  SELF_CHECK (strfile->string () == "aaaaaaaaaaaa\n  bbbbbbbbbbbb\n");
 }
 
-/* See utils.h.  */
+#endif /* GDB_SELF_TEST */
 
 void
-fputs_styled (const char *linebuffer, const ui_file_style &style,
-             struct ui_file *stream)
+gdb_puts (const char *linebuffer, struct ui_file *stream)
 {
-  set_output_style (stream, style);
-  fputs_maybe_filtered (linebuffer, stream, 1);
-  set_output_style (stream, ui_file_style ());
+  stream->puts (linebuffer);
 }
 
 /* See utils.h.  */
 
 void
-fputs_styled_unfiltered (const char *linebuffer, const ui_file_style &style,
-                        struct ui_file *stream)
+fputs_styled (const char *linebuffer, const ui_file_style &style,
+             struct ui_file *stream)
 {
-  set_output_style (stream, style);
-  fputs_maybe_filtered (linebuffer, stream, 0);
-  set_output_style (stream, ui_file_style ());
+  stream->emit_style_escape (style);
+  gdb_puts (linebuffer, stream);
+  stream->emit_style_escape (ui_file_style ());
 }
 
 /* See utils.h.  */
@@ -1983,242 +1817,58 @@ fputs_highlighted (const char *str, const compiled_regex &highlight,
       /* Output the part before pmatch with current style.  */
       while (pmatch.rm_so > 0)
        {
-         fputc_filtered (*str, stream);
+         gdb_putc (*str, stream);
          pmatch.rm_so--;
          str++;
        }
 
       /* Output pmatch with the highlight style.  */
-      set_output_style (stream, highlight_style.style ());
+      stream->emit_style_escape (highlight_style.style ());
       while (n_highlight > 0)
        {
-         fputc_filtered (*str, stream);
+         gdb_putc (*str, stream);
          n_highlight--;
          str++;
        }
-      set_output_style (stream, ui_file_style ());
+      stream->emit_style_escape (ui_file_style ());
     }
 
   /* Output the trailing part of STR not matching HIGHLIGHT.  */
   if (*str)
-    fputs_filtered (str, stream);
-}
-
-int
-putchar_unfiltered (int c)
-{
-  return fputc_unfiltered (c, gdb_stdout);
-}
-
-/* Write character C to gdb_stdout using GDB's paging mechanism and return C.
-   May return nonlocally.  */
-
-int
-putchar_filtered (int c)
-{
-  return fputc_filtered (c, gdb_stdout);
-}
-
-int
-fputc_unfiltered (int c, struct ui_file *stream)
-{
-  char buf[2];
-
-  buf[0] = c;
-  buf[1] = 0;
-  fputs_unfiltered (buf, stream);
-  return c;
-}
-
-int
-fputc_filtered (int c, struct ui_file *stream)
-{
-  char buf[2];
-
-  buf[0] = c;
-  buf[1] = 0;
-  fputs_filtered (buf, stream);
-  return c;
-}
-
-/* puts_debug is like fputs_unfiltered, except it prints special
-   characters in printable fashion.  */
-
-void
-puts_debug (char *prefix, char *string, char *suffix)
-{
-  int ch;
-
-  /* Print prefix and suffix after each line.  */
-  static int new_line = 1;
-  static int return_p = 0;
-  static const char *prev_prefix = "";
-  static const char *prev_suffix = "";
-
-  if (*string == '\n')
-    return_p = 0;
-
-  /* If the prefix is changing, print the previous suffix, a new line,
-     and the new prefix.  */
-  if ((return_p || (strcmp (prev_prefix, prefix) != 0)) && !new_line)
-    {
-      fputs_unfiltered (prev_suffix, gdb_stdlog);
-      fputs_unfiltered ("\n", gdb_stdlog);
-      fputs_unfiltered (prefix, gdb_stdlog);
-    }
-
-  /* Print prefix if we printed a newline during the previous call.  */
-  if (new_line)
-    {
-      new_line = 0;
-      fputs_unfiltered (prefix, gdb_stdlog);
-    }
-
-  prev_prefix = prefix;
-  prev_suffix = suffix;
-
-  /* Output characters in a printable format.  */
-  while ((ch = *string++) != '\0')
-    {
-      switch (ch)
-       {
-       default:
-         if (gdb_isprint (ch))
-           fputc_unfiltered (ch, gdb_stdlog);
-
-         else
-           fprintf_unfiltered (gdb_stdlog, "\\x%02x", ch & 0xff);
-         break;
-
-       case '\\':
-         fputs_unfiltered ("\\\\", gdb_stdlog);
-         break;
-       case '\b':
-         fputs_unfiltered ("\\b", gdb_stdlog);
-         break;
-       case '\f':
-         fputs_unfiltered ("\\f", gdb_stdlog);
-         break;
-       case '\n':
-         new_line = 1;
-         fputs_unfiltered ("\\n", gdb_stdlog);
-         break;
-       case '\r':
-         fputs_unfiltered ("\\r", gdb_stdlog);
-         break;
-       case '\t':
-         fputs_unfiltered ("\\t", gdb_stdlog);
-         break;
-       case '\v':
-         fputs_unfiltered ("\\v", gdb_stdlog);
-         break;
-       }
-
-      return_p = ch == '\r';
-    }
-
-  /* Print suffix if we printed a newline.  */
-  if (new_line)
-    {
-      fputs_unfiltered (suffix, gdb_stdlog);
-      fputs_unfiltered ("\n", gdb_stdlog);
-    }
+    gdb_puts (str, stream);
 }
 
-
-/* Print a variable number of ARGS using format FORMAT.  If this
-   information is going to put the amount written (since the last call
-   to REINITIALIZE_MORE_FILTER or the last page break) over the page size,
-   call prompt_for_continue to get the users permission to continue.
-
-   Unlike fprintf, this function does not return a value.
-
-   We implement three variants, vfprintf (takes a vararg list and stream),
-   fprintf (takes a stream to write on), and printf (the usual).
-
-   Note also that this may throw a quit (since prompt_for_continue may
-   do so).  */
-
-static void
-vfprintf_maybe_filtered (struct ui_file *stream, const char *format,
-                        va_list args, bool filter)
-{
-  ui_out_flags flags = disallow_ui_out_field;
-  if (!filter)
-    flags |= unfiltered_output;
-  cli_ui_out (stream, flags).vmessage (applied_style, format, args);
-}
-
-
 void
-vfprintf_filtered (struct ui_file *stream, const char *format, va_list args)
+gdb_putc (int c)
 {
-  vfprintf_maybe_filtered (stream, format, args, true);
-}
-
-void
-vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
-{
-  if (debug_timestamp && stream == gdb_stdlog)
-    {
-      static bool needs_timestamp = true;
-
-      /* Print timestamp if previous print ended with a \n.  */
-      if (needs_timestamp)
-       {
-         using namespace std::chrono;
-
-         steady_clock::time_point now = steady_clock::now ();
-         seconds s = duration_cast<seconds> (now.time_since_epoch ());
-         microseconds us = duration_cast<microseconds> (now.time_since_epoch () - s);
-         std::string timestamp = string_printf ("%ld.%06ld ",
-                                                (long) s.count (),
-                                                (long) us.count ());
-         fputs_unfiltered (timestamp.c_str (), stream);
-       }
-
-      /* Print the message.  */
-      string_file sfile;
-      cli_ui_out (&sfile, 0).vmessage (ui_file_style (), format, args);
-      std::string linebuffer = std::move (sfile.string ());
-      fputs_unfiltered (linebuffer.c_str (), stream);
-
-      size_t len = linebuffer.length ();
-      needs_timestamp = (len > 0 && linebuffer[len - 1] == '\n');
-    }
-  else
-    vfprintf_maybe_filtered (stream, format, args, false);
+  return gdb_stdout->putc (c);
 }
 
 void
-vprintf_filtered (const char *format, va_list args)
+gdb_putc (int c, struct ui_file *stream)
 {
-  vfprintf_filtered (gdb_stdout, format, args);
+  return stream->putc (c);
 }
 
 void
-vprintf_unfiltered (const char *format, va_list args)
+gdb_vprintf (struct ui_file *stream, const char *format, va_list args)
 {
-  vfprintf_unfiltered (gdb_stdout, format, args);
+  stream->vprintf (format, args);
 }
 
 void
-fprintf_filtered (struct ui_file *stream, const char *format, ...)
+gdb_vprintf (const char *format, va_list args)
 {
-  va_list args;
-
-  va_start (args, format);
-  vfprintf_filtered (stream, format, args);
-  va_end (args);
+  gdb_stdout->vprintf (format, args);
 }
 
 void
-fprintf_unfiltered (struct ui_file *stream, const char *format, ...)
+gdb_printf (struct ui_file *stream, const char *format, ...)
 {
   va_list args;
 
   va_start (args, format);
-  vfprintf_unfiltered (stream, format, args);
+  gdb_vprintf (stream, format, args);
   va_end (args);
 }
 
@@ -2230,46 +1880,20 @@ fprintf_styled (struct ui_file *stream, const ui_file_style &style,
 {
   va_list args;
 
-  set_output_style (stream, style);
+  stream->emit_style_escape (style);
   va_start (args, format);
-  vfprintf_filtered (stream, format, args);
+  gdb_vprintf (stream, format, args);
   va_end (args);
-  set_output_style (stream, ui_file_style ());
-}
-
-/* See utils.h.  */
-
-void
-vfprintf_styled (struct ui_file *stream, const ui_file_style &style,
-                const char *format, va_list args)
-{
-  set_output_style (stream, style);
-  vfprintf_filtered (stream, format, args);
-  set_output_style (stream, ui_file_style ());
-}
-
-/* See utils.h.  */
-
-void
-vfprintf_styled_no_gdbfmt (struct ui_file *stream, const ui_file_style &style,
-                          bool filter, const char *format, va_list args)
-{
-  std::string str = string_vprintf (format, args);
-  if (!str.empty ())
-    {
-      set_output_style (stream, style);
-      fputs_maybe_filtered (str.c_str (), stream, filter);
-      set_output_style (stream, ui_file_style ());
-    }
+  stream->emit_style_escape (ui_file_style ());
 }
 
 void
-printf_filtered (const char *format, ...)
+gdb_printf (const char *format, ...)
 {
   va_list args;
 
   va_start (args, format);
-  vfprintf_filtered (gdb_stdout, format, args);
+  gdb_vprintf (gdb_stdout, format, args);
   va_end (args);
 }
 
@@ -2280,7 +1904,9 @@ printf_unfiltered (const char *format, ...)
   va_list args;
 
   va_start (args, format);
-  vfprintf_unfiltered (gdb_stdout, format, args);
+  string_file file (gdb_stdout->can_emit_style_escape ());
+  file.vprintf (format, args);
+  gdb_stdout->puts_unfiltered (file.string ().c_str ());
   va_end (args);
 }
 
@@ -2290,20 +1916,14 @@ printf_unfiltered (const char *format, ...)
    This one doesn't, and had better not!  */
 
 void
-puts_filtered (const char *string)
-{
-  fputs_filtered (string, gdb_stdout);
-}
-
-void
-puts_unfiltered (const char *string)
+gdb_puts (const char *string)
 {
-  fputs_unfiltered (string, gdb_stdout);
+  gdb_stdout->puts (string);
 }
 
 /* Return a pointer to N spaces and a null.  The pointer is good
    until the next call to here.  */
-char *
+const char *
 n_spaces (int n)
 {
   char *t;
@@ -2325,34 +1945,34 @@ n_spaces (int n)
 
 /* Print N spaces.  */
 void
-print_spaces_filtered (int n, struct ui_file *stream)
+print_spaces (int n, struct ui_file *stream)
 {
-  fputs_filtered (n_spaces (n), stream);
+  gdb_puts (n_spaces (n), stream);
 }
 \f
 /* C++/ObjC demangler stuff.  */
 
-/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language
+/* fprintf_symbol attempts to demangle NAME, a symbol in language
    LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
    If the name is not mangled, or the language for the name is unknown, or
    demangling is off, the name is printed in its "raw" form.  */
 
 void
-fprintf_symbol_filtered (struct ui_file *stream, const char *name,
-                        enum language lang, int arg_mode)
+fprintf_symbol (struct ui_file *stream, const char *name,
+               enum language lang, int arg_mode)
 {
   if (name != NULL)
     {
       /* If user wants to see raw output, no problem.  */
       if (!demangle)
        {
-         fputs_filtered (name, stream);
+         gdb_puts (name, stream);
        }
       else
        {
          gdb::unique_xmalloc_ptr<char> demangled
            = language_demangle (language_def (lang), name, arg_mode);
-         fputs_filtered (demangled ? demangled.get () : name, stream);
+         gdb_puts (demangled ? demangled.get () : name, stream);
        }
     }
 }
@@ -2473,13 +2093,45 @@ skip_abi_tag (const char **name)
   return false;
 }
 
+/* If *NAME points at a template parameter list, skip it and return true.
+   Otherwise do nothing and return false.  */
+
+static bool
+skip_template_parameter_list (const char **name)
+{
+  const char *p = *name;
+
+  if (*p == '<')
+    {
+      const char *template_param_list_end = find_toplevel_char (p + 1, '>');
+
+      if (template_param_list_end == NULL)
+       return false;
+
+      p = template_param_list_end + 1;
+
+      /* Skip any whitespace that might occur after the closing of the
+        parameter list, but only if it is the end of parameter list.  */
+      const char *q = p;
+      while (ISSPACE (*q))
+       ++q;
+      if (*q == '>')
+       p = q;
+      *name = p;
+      return true;
+    }
+
+  return false;
+}
+
 /* See utils.h.  */
 
 int
 strncmp_iw_with_mode (const char *string1, const char *string2,
                      size_t string2_len, strncmp_iw_mode mode,
                      enum language language,
-                     completion_match_for_lcd *match_for_lcd)
+                     completion_match_for_lcd *match_for_lcd,
+                     bool ignore_template_params)
 {
   const char *string1_start = string1;
   const char *end_str2 = string2 + string2_len;
@@ -2529,6 +2181,48 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
            string1++;
        }
 
+      /* Skip template parameters in STRING1 if STRING2 does not contain
+        any.  E.g.:
+
+        Case 1: User is looking for all functions named "foo".
+        string1: foo <...> (...)
+        string2: foo
+
+        Case 2: User is looking for all methods named "foo" in all template
+        class instantiations.
+        string1: Foo<...>::foo <...> (...)
+        string2: Foo::foo (...)
+
+        Case 3: User is looking for a specific overload of a template
+        function or method.
+        string1: foo<...>
+        string2: foo(...)
+
+        Case 4: User is looking for a specific overload of a specific
+        template instantiation.
+        string1: foo<A> (...)
+        string2: foo<B> (...)
+
+        Case 5: User is looking wild parameter match.
+        string1: foo<A<a<b<...> > > > (...)
+        string2: foo<A
+      */
+      if (language == language_cplus && ignore_template_params
+         && *string1 == '<' && *string2 != '<')
+       {
+         /* Skip any parameter list in STRING1.  */
+         const char *template_start = string1;
+
+         if (skip_template_parameter_list (&string1))
+           {
+             /* Don't mark the parameter list ignored if the user didn't
+                try to ignore it.  [Case #5 above]  */
+             if (*string2 != '\0'
+                 && match_for_lcd != NULL && template_start != string1)
+               match_for_lcd->mark_ignored_range (template_start, string1);
+           }
+       }
+
       if (*string1 == '\0' || string2 == end_str2)
        break;
 
@@ -2637,6 +2331,12 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
                    break;
                  if (*string1 == '(' || *string2 == '(')
                    break;
+
+                 /* If STRING1 or STRING2 starts with a template
+                    parameter list, break out of operator processing.  */
+                 skip_ws (string1, string2, end_str2);
+                 if (*string1 == '<' || *string2 == '<')
+                   break;
                }
 
              continue;
@@ -2704,6 +2404,569 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
     return 1;
 }
 
+#if GDB_SELF_TEST
+
+/* Unit tests for strncmp_iw_with_mode.  */
+
+#define CHECK_MATCH_LM(S1, S2, MODE, LANG, LCD)                        \
+  SELF_CHECK (strncmp_iw_with_mode ((S1), (S2), strlen ((S2)), \
+                                   strncmp_iw_mode::MODE,                              \
+                                   (LANG), (LCD)) == 0)
+
+#define CHECK_MATCH_LANG(S1, S2, MODE, LANG)                   \
+  CHECK_MATCH_LM ((S1), (S2), MODE, (LANG), nullptr)
+
+#define CHECK_MATCH(S1, S2, MODE)                                              \
+  CHECK_MATCH_LANG ((S1), (S2), MODE, language_minimal)
+
+#define CHECK_NO_MATCH_LM(S1, S2, MODE, LANG, LCD)             \
+  SELF_CHECK (strncmp_iw_with_mode ((S1), (S2), strlen ((S2)), \
+                                   strncmp_iw_mode::MODE,                              \
+                                   (LANG)) != 0)
+
+#define CHECK_NO_MATCH_LANG(S1, S2, MODE, LANG)                \
+  CHECK_NO_MATCH_LM ((S1), (S2), MODE, (LANG), nullptr)
+
+#define CHECK_NO_MATCH(S1, S2, MODE)                                  \
+  CHECK_NO_MATCH_LANG ((S1), (S2), MODE, language_minimal)
+
+static void
+check_scope_operator (enum language lang)
+{
+  CHECK_MATCH_LANG ("::", "::", NORMAL, lang);
+  CHECK_MATCH_LANG ("::foo", "::", NORMAL, lang);
+  CHECK_MATCH_LANG ("::foo", "::foo", NORMAL, lang);
+  CHECK_MATCH_LANG (" :: foo ", "::foo", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a ::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a\t::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a \t::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a\t ::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a:: b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a::\tb", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a:: \tb", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a::\t b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a :: b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a ::\tb", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a\t:: b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b", "a \t::\t b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a ::b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a\t::b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a \t::b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a\t ::b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a:: b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::\tb", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a:: \tb", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::\t b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a :: b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a ::\tb", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a\t:: b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a \t::\t b", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG (" a:: b:: c", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", " a:: b:: c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a ::b ::c", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", "a :: b:: c", NORMAL, lang);
+  CHECK_MATCH_LANG ("\ta::\tb::\tc", "\ta::\tb::\tc", NORMAL, lang);
+  CHECK_MATCH_LANG ("a\t::b\t::c\t", "a\t::b\t::c\t", NORMAL, lang);
+  CHECK_MATCH_LANG (" \ta:: \tb:: \tc", " \ta:: \tb:: \tc", NORMAL, lang);
+  CHECK_MATCH_LANG ("\t a::\t b::\t c", "\t a::\t b::\t c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", "\ta::\tb::\tc", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", "a\t::b\t::c\t", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", " \ta:: \tb:: \tc", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b::c", "\t a::\t b::\t c", NORMAL, lang);
+  CHECK_MATCH_LANG ("\ta::\tb::\tc", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a\t::b\t::c\t", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG (" \ta:: \tb:: \tc", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG ("\t a::\t b::\t c", "a::b::c", NORMAL, lang);
+  CHECK_MATCH_LANG ("a :: b:: c\t", "\ta :: b\t::  c\t\t", NORMAL, lang);
+  CHECK_MATCH_LANG ("  a::\t  \t    b::     c\t", "\ta ::b::  c\t\t",
+             NORMAL, lang);
+  CHECK_MATCH_LANG ("a      :: b               :: \t\t\tc\t",
+             "\t\t\t\ta        ::   \t\t\t        b             \t\t::c",
+             NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b()", "a", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b()", "a::", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b()", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a)", "a", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a)", "a::", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a)", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b)", "a", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b)", "a::", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b)", "a::b", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b,c)", "a", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b,c)", "a::", NORMAL, lang);
+  CHECK_MATCH_LANG ("a::b(a,b,c)", "a::b", NORMAL, lang);
+
+  CHECK_NO_MATCH_LANG ("a::", "::a", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("::a", "::a()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("::", "::a", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a:::b", "a::b", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b()", "a::b(a)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b(a)", "a::b()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b(a,b)", "a::b(a,a)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::b()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a(a)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::(a)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::b()", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a(a,b)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::(a,b)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::b(a,b)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a(a,b,c)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::(a,b,c)", NORMAL, lang);
+  CHECK_NO_MATCH_LANG ("a::b", "a::b(a,b,c)", NORMAL, lang);
+}
+
+/* Callback for strncmp_iw_with_mode unit tests.  */
+
+static void
+strncmp_iw_with_mode_tests ()
+{
+  /* Some of the following tests are nonsensical, but could be input by a
+     deranged script (or user).  */
+
+  /* strncmp_iw_mode::NORMAL: strcmp()-like but ignore any whitespace...  */
+
+  CHECK_MATCH ("", "", NORMAL);
+  CHECK_MATCH ("foo", "foo", NORMAL);
+  CHECK_MATCH (" foo", "foo", NORMAL);
+  CHECK_MATCH ("foo ", "foo", NORMAL);
+  CHECK_MATCH (" foo ", "foo", NORMAL);
+  CHECK_MATCH ("  foo", "foo", NORMAL);
+  CHECK_MATCH ("foo  ", "foo", NORMAL);
+  CHECK_MATCH ("  foo  ", "foo", NORMAL);
+  CHECK_MATCH ("\tfoo", "foo", NORMAL);
+  CHECK_MATCH ("foo\t", "foo", NORMAL);
+  CHECK_MATCH ("\tfoo\t", "foo", NORMAL);
+  CHECK_MATCH (" \tfoo \t", "foo", NORMAL);
+  CHECK_MATCH ("\t foo\t ", "foo", NORMAL);
+  CHECK_MATCH ("\t \t     \t\t\t\t   foo\t\t\t  \t\t   \t   \t    \t  \t ",
+              "foo", NORMAL);
+  CHECK_MATCH ("foo",
+              "\t \t     \t\t\t\t   foo\t\t\t  \t\t   \t   \t    \t  \t ",
+              NORMAL);
+  CHECK_MATCH ("foo bar", "foo", NORMAL);
+  CHECK_NO_MATCH ("foo", "bar", NORMAL);
+  CHECK_NO_MATCH ("foo bar", "foobar", NORMAL);
+  CHECK_NO_MATCH (" foo ", "bar", NORMAL);
+  CHECK_NO_MATCH ("foo", " bar ", NORMAL);
+  CHECK_NO_MATCH (" \t\t    foo\t\t ", "\t    \t    \tbar\t", NORMAL);
+  CHECK_NO_MATCH ("@!%&", "@!%&foo", NORMAL);
+
+  /* ... and function parameters in STRING1.  */
+  CHECK_MATCH ("foo()", "foo()", NORMAL);
+  CHECK_MATCH ("foo ()", "foo()", NORMAL);
+  CHECK_MATCH ("foo  ()", "foo()", NORMAL);
+  CHECK_MATCH ("foo\t()", "foo()", NORMAL);
+  CHECK_MATCH ("foo\t  ()", "foo()", NORMAL);
+  CHECK_MATCH ("foo  \t()", "foo()", NORMAL);
+  CHECK_MATCH ("foo()", "foo ()", NORMAL);
+  CHECK_MATCH ("foo()", "foo  ()", NORMAL);
+  CHECK_MATCH ("foo()", "foo\t()", NORMAL);
+  CHECK_MATCH ("foo()", "foo\t ()", NORMAL);
+  CHECK_MATCH ("foo()", "foo \t()", NORMAL);
+  CHECK_MATCH ("foo()", "foo()", NORMAL);
+  CHECK_MATCH ("foo ()", "foo ()", NORMAL);
+  CHECK_MATCH ("foo  ()", "foo  ()", NORMAL);
+  CHECK_MATCH ("foo\t()", "foo\t()", NORMAL);
+  CHECK_MATCH ("foo\t  ()", "foo\t ()", NORMAL);
+  CHECK_MATCH ("foo  \t()", "foo \t()", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo( a)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(a )", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(\ta)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(a\t)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(\t a)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo( \ta)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(a\t )", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(a \t)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo( a )", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(\ta\t)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(\t a\t )", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo( \ta \t)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo( a)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(a )", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(\ta)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(a\t)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(\t a)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo( \ta)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(a\t )", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(a \t)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo( a )", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(\ta\t)", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo(\t a\t )", NORMAL);
+  CHECK_MATCH ("foo(a)", "foo( \ta \t)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a ,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a\t,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a,\tb)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a\t,\tb)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a \t,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a\t ,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a,\tb)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a, \tb)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a,\t b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a ,b)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a\t,b)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a,\tb)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a\t,\tb)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a \t,b)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a\t ,b)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a,\tb)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a, \tb)", NORMAL);
+  CHECK_MATCH ("foo(a,b)", "foo(a,\t b)", NORMAL);
+  CHECK_MATCH ("foo(a,b,c,d)", "foo(a,b,c,d)", NORMAL);
+  CHECK_MATCH (" foo ( a , b , c , d ) ", "foo(a,b,c,d)", NORMAL);
+  CHECK_MATCH (" foo ( a , b , c , d ) ", "foo( a , b , c , d )", NORMAL);
+  CHECK_MATCH ("foo &\t*(\ta b    *\t\t&)", "foo", NORMAL);
+  CHECK_MATCH ("foo &\t*(\ta b    *\t\t&)", "foo&*(a b * &)", NORMAL);
+  CHECK_MATCH ("foo(a) b", "foo(a)", NORMAL);
+  CHECK_MATCH ("*foo(*a&)", "*foo", NORMAL);
+  CHECK_MATCH ("*foo(*a&)", "*foo(*a&)", NORMAL);
+  CHECK_MATCH ("*a&b#c/^d$foo(*a&)", "*a&b#c/^d$foo", NORMAL);
+  CHECK_MATCH ("* foo", "*foo", NORMAL);
+  CHECK_MATCH ("foo&", "foo", NORMAL);
+  CHECK_MATCH ("foo*", "foo", NORMAL);
+  CHECK_MATCH ("foo.", "foo", NORMAL);
+  CHECK_MATCH ("foo->", "foo", NORMAL);
+
+  CHECK_NO_MATCH ("foo", "foo(", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo()", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo*", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo*", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo *", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo&", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo &", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo &*", "foo (&)", NORMAL);
+  CHECK_NO_MATCH ("foo & \t    *\t", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo & \t    *\t", "foo (*", NORMAL);
+  CHECK_NO_MATCH ("foo(a*) b", "foo(a) b", NORMAL);
+  CHECK_NO_MATCH ("foo[aqi:A](a)", "foo(b)", NORMAL);
+  CHECK_NO_MATCH ("*foo", "foo", NORMAL);
+  CHECK_NO_MATCH ("*foo", "foo*", NORMAL);
+  CHECK_NO_MATCH ("*foo*", "*foo&", NORMAL);
+  CHECK_NO_MATCH ("*foo*", "foo *", NORMAL);
+  CHECK_NO_MATCH ("&foo", "foo", NORMAL);
+  CHECK_NO_MATCH ("&foo", "foo&", NORMAL);
+  CHECK_NO_MATCH ("foo&", "&foo", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo&", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo*", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo.", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo->", NORMAL);
+  CHECK_NO_MATCH ("foo bar", "foo()", NORMAL);
+  CHECK_NO_MATCH ("foo bar", "foo bar()", NORMAL);
+  CHECK_NO_MATCH ("foo()", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("*(*)&", "*(*)*", NORMAL);
+  CHECK_NO_MATCH ("foo(a)", "foo()", NORMAL);
+  CHECK_NO_MATCH ("foo(a)", "foo(b)", NORMAL);
+  CHECK_NO_MATCH ("foo(a,b)", "foo(a,b,c)", NORMAL);
+  CHECK_NO_MATCH ("foo(a\\b)", "foo()", NORMAL);
+  CHECK_NO_MATCH ("foo bar(a b c d)", "foobar", NORMAL);
+  CHECK_NO_MATCH ("foo bar(a b c d)", "foobar ( a b   c \td\t)\t", NORMAL);
+
+  /* Test scope operator.  */
+  check_scope_operator (language_minimal);
+  check_scope_operator (language_cplus);
+  check_scope_operator (language_fortran);
+  check_scope_operator (language_rust);
+
+  /* Test C++ user-defined operators.  */
+  CHECK_MATCH_LANG ("operator foo(int&)", "operator foo(int &)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo(int &)", "operator foo(int &)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo(int\t&)", "operator foo(int\t&)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo (int)", "operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo\t(int)", "operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo \t(int)", "operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo (int)", "operator foo \t(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo\t(int)", "operator foo \t(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("operator foo \t(int)", "operator foo \t(int)", NORMAL,
+                   language_cplus);
+
+  CHECK_MATCH_LANG ("a::operator foo(int&)", "a::operator foo(int &)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a :: operator foo(int &)", "a::operator foo(int &)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a \t:: \toperator foo(int\t&)", "a::operator foo(int\t&)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo (int)", "a::operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo\t(int)", "a::operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo \t(int)", "a::operator foo(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo (int)", "a::operator foo \t(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo\t(int)", "a::operator foo \t(int)", NORMAL,
+                   language_cplus);
+  CHECK_MATCH_LANG ("a::operator foo \t(int)", "a::operator foo \t(int)", NORMAL,
+                   language_cplus);
+
+  CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(char)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int *)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int &)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("operator foo(int)", "operator foo(int, char *)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("operator foo(int)", "operator bar(int)", NORMAL,
+                      language_cplus);
+
+  CHECK_NO_MATCH_LANG ("a::operator b::foo(int)", "a::operator a::foo(char)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int *)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int &)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator foo(int, char *)", NORMAL,
+                      language_cplus);
+  CHECK_NO_MATCH_LANG ("a::operator foo(int)", "a::operator bar(int)", NORMAL,
+                      language_cplus);
+
+  /* Skip "[abi:cxx11]" tags in the symbol name if the lookup name
+     doesn't include them.  These are not language-specific in
+     strncmp_iw_with_mode.  */
+
+  CHECK_MATCH ("foo[abi:a]", "foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a]()", "foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a)", "foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a&,b*)", "foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a,b) c", "foo(a,b) c", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a)", "foo(a)", NORMAL);
+  CHECK_MATCH ("foo[abi:a](a,b)", "foo(a,b)", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[ abi:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[\tabi:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[ \tabi:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[\t abi:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi :a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi\t:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi \t:a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi\t :a]", "foo[abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[ abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[\tabi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[ \tabi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[\t abi:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi :a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi\t:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi \t:a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi\t :a]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi:a ]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi:a\t]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi:a \t]", NORMAL);
+  CHECK_MATCH ("foo[abi:a]", "foo[abi:a\t ]", NORMAL);
+  CHECK_MATCH ("foo[abi:a,b]", "foo[abi:a,b]", NORMAL);
+  CHECK_MATCH ("foo[abi:::]", "foo[abi:::]", NORMAL);
+  CHECK_MATCH ("foo[abi : : : ]", "foo[abi:::]", NORMAL);
+  CHECK_MATCH ("foo[abi:::]", "foo[abi : : : ]", NORMAL);
+  CHECK_MATCH ("foo[ \t abi  \t:\t:   :   \t]",
+              "foo[   abi :                \t    ::]",
+              NORMAL);
+  CHECK_MATCH ("foo< bar< baz< quxi > > >(int)", "foo<bar<baz<quxi>>>(int)",
+              NORMAL);
+  CHECK_MATCH ("\tfoo<\tbar<\tbaz\t<\tquxi\t>\t>\t>(int)",
+              "foo<bar<baz<quxi>>>(int)", NORMAL);
+  CHECK_MATCH (" \tfoo \t< \tbar \t< \tbaz \t< \tquxi \t> \t> \t> \t( \tint \t)",
+              "foo<bar<baz<quxi>>>(int)", NORMAL);
+  CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
+              "foo < bar < baz < quxi > > > (int)", NORMAL);
+  CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
+              "\tfoo\t<\tbar\t<\tbaz\t<\tquxi\t>\t>\t>\t(int)", NORMAL);
+  CHECK_MATCH ("foo<bar<baz<quxi>>>(int)",
+              " \tfoo \t< \tbar \t< \tbaz \t< \tquxi \t> \t> \t> \t( \tint \t)", NORMAL);
+  CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "fo", NORMAL);
+  CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo", NORMAL);
+  CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo<bar<baz>>::", NORMAL);
+  CHECK_MATCH ("foo<bar<baz>>::foo(quxi &)", "foo<bar<baz> >::foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c][abi:d])",
+              NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo(bar)", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a](bar)", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo(bar[abi:c])", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a](bar[abi:c])", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar)", NORMAL);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c])",
+              NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo", NORMAL);
+  CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo()", NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>", NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz)", NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz[abi:b])",
+             NORMAL);
+  CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar>(char*, baz[abi:A])",
+             NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:a]>(char*, baz)",
+             NORMAL);
+  CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:A]>(char*, baz)",
+             NORMAL);
+  CHECK_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])", "foo<bar[abi:a]>(char*, baz[abi:b])",
+             NORMAL);
+  CHECK_NO_MATCH("foo<bar[abi:a]>(char *, baz[abi:b])",
+                "foo<bar[abi:a]>(char*, baz[abi:B])", NORMAL);
+
+  CHECK_NO_MATCH ("foo", "foo[", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ a]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[a ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ a ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[\ta]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[a \t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[a\t ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ \ta]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[\t a]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ \ta \t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[\t a\t ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ abi]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[\tabi]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi\t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[ \tabi]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[\t abi]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi \t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi\t ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi :]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi\t:]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi \t:]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi\t :]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi: ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:\t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi: \t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:\t ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi: a]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:\ta]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi: \ta]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:\t a]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:a ]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:a\t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:a \t]", NORMAL);
+  CHECK_NO_MATCH ("foo", "foo[abi:a\t ]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) c", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) .", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) *", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a]()", "foo(a) &", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) c", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) .", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) *", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b) &", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)c", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b).", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)*", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b)", "foo(a,b)&", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a,b) d", "foo(a,b) c", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a)", "foo()", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a)", "foo(b)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a)", "foo[abi:b](a)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a](a)", "foo[abi:a](b)", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:]", "foo[abi:a]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:", "foo[abi:a]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:]", "foo[abi:a", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:,]", "foo[abi:a]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:a,b]", "foo[abi:a]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi::a]", "foo[abi:a]", NORMAL);
+  CHECK_NO_MATCH ("foo[abi:,([a]", "foo[abi:a]", NORMAL);
+
+  CHECK_MATCH ("foo <a, b [, c (",  "foo", NORMAL);
+  CHECK_MATCH ("foo >a, b ], c )",  "foo", NORMAL);
+  CHECK_MATCH ("@!%&\\*", "@!%&\\*", NORMAL);
+  CHECK_MATCH ("()", "()", NORMAL);
+  CHECK_MATCH ("*(*)*", "*(*)*", NORMAL);
+  CHECK_MATCH ("[]", "[]", NORMAL);
+  CHECK_MATCH ("<>", "<>", NORMAL);
+
+  /* strncmp_iw_with_mode::MATCH_PARAMS: the "strcmp_iw hack."  */
+  CHECK_MATCH ("foo2", "foo", NORMAL);
+  CHECK_NO_MATCH ("foo2", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "foo ", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "foo\t", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "foo \t", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "foo\t ", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "foo \t", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", " foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "\tfoo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", " \tfoo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2", "\t foo", MATCH_PARAMS);
+  CHECK_NO_MATCH (" foo2", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("\tfoo2", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH (" \tfoo2", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("\t foo2", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH (" foo2 ", " foo ", MATCH_PARAMS);
+  CHECK_NO_MATCH ("\tfoo2\t", "\tfoo\t", MATCH_PARAMS);
+  CHECK_NO_MATCH (" \tfoo2 \t", " \tfoo \t", MATCH_PARAMS);
+  CHECK_NO_MATCH ("\t foo2\t ", "\t foo\t ", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 ", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2\t", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 ", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 \t", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2\t ", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 (args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 (args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2\t(args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 \t(args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2\t (args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 ( args)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2(args )", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2(args\t)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 (args \t)", "foo", MATCH_PARAMS);
+  CHECK_NO_MATCH ("foo2 (args\t )", "foo", MATCH_PARAMS);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo[abi:a][abi:b](bar[abi:c][abi:d])",
+              MATCH_PARAMS);
+  CHECK_MATCH ("foo[abi:a][abi:b](bar[abi:c][abi:d])", "foo", MATCH_PARAMS);
+
+  /* strncmp_iw_with_mode also supports case insensitivity.  */
+  {
+    CHECK_NO_MATCH ("FoO", "foo", NORMAL);
+    CHECK_NO_MATCH ("FoO", "foo", MATCH_PARAMS);
+
+    scoped_restore restore_case = make_scoped_restore (&case_sensitivity);
+    case_sensitivity = case_sensitive_off;
+
+    CHECK_MATCH ("FoO", "foo", NORMAL);
+    CHECK_MATCH ("FoO", "foo", MATCH_PARAMS);
+    CHECK_MATCH ("foo", "FoO", NORMAL);
+    CHECK_MATCH ("foo", "FoO", MATCH_PARAMS);
+
+    CHECK_MATCH ("FoO[AbI:abC]()", "foo", NORMAL);
+    CHECK_NO_MATCH ("FoO[AbI:abC]()", "foo", MATCH_PARAMS);
+    CHECK_MATCH ("FoO2[AbI:abC]()", "foo", NORMAL);
+    CHECK_NO_MATCH ("FoO2[AbI:abC]()", "foo", MATCH_PARAMS);
+
+    CHECK_MATCH ("foo[abi:abc]()", "FoO[AbI:abC]()", NORMAL);
+    CHECK_MATCH ("foo[abi:abc]()", "FoO[AbI:AbC]()", MATCH_PARAMS);
+    CHECK_MATCH ("foo[abi:abc](xyz)", "FoO[AbI:abC](XyZ)", NORMAL);
+    CHECK_MATCH ("foo[abi:abc](xyz)", "FoO[AbI:abC](XyZ)", MATCH_PARAMS);
+    CHECK_MATCH ("foo[abi:abc][abi:def](xyz)", "FoO[AbI:abC](XyZ)", NORMAL);
+    CHECK_MATCH ("foo[abi:abc][abi:def](xyz)", "FoO[AbI:abC](XyZ)",
+                MATCH_PARAMS);
+    CHECK_MATCH ("foo<bar<baz>>(bar<baz>)", "FoO<bAr<BaZ>>(bAr<BaZ>)",
+                NORMAL);
+    CHECK_MATCH ("foo<bar<baz>>(bar<baz>)", "FoO<bAr<BaZ>>(bAr<BaZ>)",
+                MATCH_PARAMS);
+  }
+}
+
+#undef MATCH
+#undef NO_MATCH
+#endif
+
 /* See utils.h.  */
 
 int
@@ -2871,8 +3134,8 @@ static void
 show_debug_timestamp (struct ui_file *file, int from_tty,
                      struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("Timestamping debugging messages is %s.\n"),
-                   value);
+  gdb_printf (file, _("Timestamping debugging messages is %s.\n"),
+             value);
 }
 \f
 
@@ -2936,27 +3199,6 @@ print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
     return hex_string_custom (address, 16);
 }
 
-/* Callback hash_f for htab_create_alloc or htab_create_alloc_ex.  */
-
-hashval_t
-core_addr_hash (const void *ap)
-{
-  const CORE_ADDR *addrp = (const CORE_ADDR *) ap;
-
-  return *addrp;
-}
-
-/* Callback eq_f for htab_create_alloc or htab_create_alloc_ex.  */
-
-int
-core_addr_eq (const void *ap, const void *bp)
-{
-  const CORE_ADDR *addr_ap = (const CORE_ADDR *) ap;
-  const CORE_ADDR *addr_bp = (const CORE_ADDR *) bp;
-
-  return *addr_ap == *addr_bp;
-}
-
 /* Convert a string back into a CORE_ADDR.  */
 CORE_ADDR
 string_to_core_addr (const char *my_string)
@@ -3056,30 +3298,6 @@ gdb_argv_as_array_view_test ()
 
 #endif /* GDB_SELF_TEST */
 
-/* Allocation function for the libiberty hash table which uses an
-   obstack.  The obstack is passed as DATA.  */
-
-void *
-hashtab_obstack_allocate (void *data, size_t size, size_t count)
-{
-  size_t total = size * count;
-  void *ptr = obstack_alloc ((struct obstack *) data, total);
-
-  memset (ptr, 0, total);
-  return ptr;
-}
-
-/* Trivial deallocation function for the libiberty splay tree and hash
-   table - don't deallocate anything.  Rely on later deletion of the
-   obstack.  DATA will be the obstack, although it is not needed
-   here.  */
-
-void
-dummy_obstack_deallocate (void *object, void *data)
-{
-  return;
-}
-
 /* Simple, portable version of dirname that does not modify its
    argument.  */
 
@@ -3106,45 +3324,6 @@ ldirname (const char *filename)
   return dirname;
 }
 
-/* See utils.h.  */
-
-void
-gdb_argv::reset (const char *s)
-{
-  char **argv = buildargv (s);
-
-  freeargv (m_argv);
-  m_argv = argv;
-}
-
-#define AMBIGUOUS_MESS1        ".\nMatching formats:"
-#define AMBIGUOUS_MESS2        \
-  ".\nUse \"set gnutarget format-name\" to specify the format."
-
-std::string
-gdb_bfd_errmsg (bfd_error_type error_tag, char **matching)
-{
-  char **p;
-
-  /* Check if errmsg just need simple return.  */
-  if (error_tag != bfd_error_file_ambiguously_recognized || matching == NULL)
-    return bfd_errmsg (error_tag);
-
-  std::string ret (bfd_errmsg (error_tag));
-  ret += AMBIGUOUS_MESS1;
-
-  for (p = matching; *p; p++)
-    {
-      ret += " ";
-      ret += *p;
-    }
-  ret += AMBIGUOUS_MESS2;
-
-  xfree (matching);
-
-  return ret;
-}
-
 /* Return ARGS parsed as a valid pid, or throw an error.  */
 
 int
@@ -3553,5 +3732,8 @@ When set, debugging messages will be marked with seconds and microseconds."),
 #if GDB_SELF_TEST
   selftests::register_test ("gdb_realpath", gdb_realpath_tests);
   selftests::register_test ("gdb_argv_array_view", gdb_argv_as_array_view_test);
+  selftests::register_test ("strncmp_iw_with_mode",
+                           strncmp_iw_with_mode_tests);
+  selftests::register_test ("pager", test_pager);
 #endif
 }