Make gdb_stdout&co be per UI
[external/binutils.git] / gdb / top.c
index 6ae84ab..a34635b 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1,6 +1,6 @@
 /* Top level stuff for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2015 Free Software Foundation, Inc.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -49,6 +49,9 @@
 #include "observer.h"
 #include "maint.h"
 #include "filenames.h"
+#include "frame.h"
+#include "buffer.h"
+#include "gdb_select.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
 #include "tracepoint.h"
 #include "inf-loop.h"
 
+#if defined(TUI)
+# include "tui/tui.h"
+#endif
+
 extern void initialize_all_files (void);
 
 #define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
@@ -79,6 +86,21 @@ extern void initialize_all_files (void);
 #define DEFAULT_PROMPT "(gdb) "
 #endif
 
+/* Generate a function that exports a pointer to a field of the
+   current UI.  */
+
+#define gen_ret_current_ui_field_ptr(type, name)       \
+type *                                                 \
+current_ui_## name ## _ptr (void)                      \
+{                                                      \
+  return &current_ui->m_ ## name;              \
+}
+
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdout)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdin)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stderr)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdlog)
+
 /* Initialization file name for gdb.  This is host-dependent.  */
 
 const char gdbinit[] = GDBINIT;
@@ -119,17 +141,9 @@ char *current_directory;
 /* The directory name is actually stored here (usually).  */
 char gdb_dirbuf[1024];
 
-/* Function to call before reading a command, if nonzero.
-   The function receives two args: an input stream,
-   and a prompt string.  */
-
-void (*window_hook) (FILE *, char *);
-
-/* Buffer used for reading command lines, and the size
-   allocated for it so far.  */
-
+/* The last command line executed on the console.  Used for command
+   repetitions.  */
 char *saved_command_line;
-int saved_command_line_size = 100;
 
 /* Nonzero if the current command is modified by "server ".  This
    affects things like recording into the command history, commands
@@ -221,11 +235,6 @@ void (*deprecated_detach_hook) (void);
 
 void (*deprecated_interactive_hook) (void);
 
-/* Tell the GUI someone changed the register REGNO.  -1 means
-   that the caller does not know which register changed or
-   that several registers have changed (see value_assign).  */
-void (*deprecated_register_changed_hook) (int regno);
-
 /* Called when going to wait for the target.  Usually allows the GUI
    to run while waiting for target events.  */
 
@@ -278,7 +287,7 @@ void
 do_restore_instream_cleanup (void *stream)
 {
   /* Restore the previous input stream.  */
-  instream = stream;
+  instream = (FILE *) stream;
 }
 
 /* Read commands from STREAM.  */
@@ -289,7 +298,21 @@ read_command_file (FILE *stream)
 
   cleanups = make_cleanup (do_restore_instream_cleanup, instream);
   instream = stream;
-  command_loop ();
+
+  /* Read commands from `instream' and execute them until end of file
+     or error reading instream.  */
+
+  while (instream != NULL && !feof (instream))
+    {
+      char *command;
+
+      /* Get a command-line.  This calls the readline package.  */
+      command = command_line_input (NULL, 0, NULL);
+      if (command == NULL)
+       break;
+      command_handler (command);
+    }
+
   do_cleanups (cleanups);
 }
 \f
@@ -330,10 +353,11 @@ void
 check_frame_language_change (void)
 {
   static int warned = 0;
+  struct frame_info *frame;
 
   /* First make sure that a new frame has been selected, in case the
      command or the hooks changed the program state.  */
-  deprecated_safe_get_selected_frame ();
+  frame = deprecated_safe_get_selected_frame ();
   if (current_language != expected_language)
     {
       if (language_mode == language_mode_auto && info_verbose)
@@ -353,7 +377,7 @@ check_frame_language_change (void)
     {
       enum language flang;
 
-      flang = get_frame_language ();
+      flang = get_frame_language (frame);
       if (!warned
          && flang != language_unknown
          && flang != current_language->la_language)
@@ -367,6 +391,16 @@ check_frame_language_change (void)
 /* See top.h.  */
 
 void
+wait_sync_command_done (void)
+{
+  while (gdb_do_one_event () >= 0)
+    if (!sync_execution)
+      break;
+}
+
+/* See top.h.  */
+
+void
 maybe_wait_sync_command_done (int was_sync)
 {
   /* If the interpreter is in sync mode (we're running a user
@@ -374,11 +408,7 @@ maybe_wait_sync_command_done (int was_sync)
      just ran a synchronous command that started the target, wait
      for that command to end.  */
   if (!interpreter_async && !was_sync && sync_execution)
-    {
-      while (gdb_do_one_event () >= 0)
-       if (!sync_execution)
-         break;
-    }
+    wait_sync_command_done ();
 }
 
 /* Execute the line P as a command, in the current user context.
@@ -527,49 +557,6 @@ execute_command_to_string (char *p, int from_tty)
   return retval;
 }
 
-/* Read commands from `instream' and execute them
-   until end of file or error reading instream.  */
-
-void
-command_loop (void)
-{
-  struct cleanup *old_chain;
-  char *command;
-  int stdin_is_tty = ISATTY (stdin);
-
-  while (instream && !feof (instream))
-    {
-      if (window_hook && instream == stdin)
-       (*window_hook) (instream, get_prompt ());
-
-      clear_quit_flag ();
-      if (instream == stdin && stdin_is_tty)
-       reinitialize_more_filter ();
-      old_chain = make_cleanup (null_cleanup, 0);
-
-      /* Get a command-line.  This calls the readline package.  */
-      command = command_line_input (instream == stdin ?
-                                   get_prompt () : (char *) NULL,
-                                   instream == stdin, "prompt");
-      if (command == 0)
-       {
-         do_cleanups (old_chain);
-         return;
-       }
-
-      make_command_stats_cleanup (1);
-
-      /* Do not execute commented lines.  */
-      if (command[0] != '#')
-       {
-         execute_command (command, instream == stdin);
-
-         /* Do any commands attached to breakpoint we are stopped at.  */
-         bpstat_do_actions ();
-       }
-      do_cleanups (old_chain);
-    }
-}
 \f
 /* When nonzero, cause dont_repeat to do nothing.  This should only be
    set via prevent_dont_repeat.  */
@@ -606,64 +593,80 @@ prevent_dont_repeat (void)
 \f
 /* Read a line from the stream "instream" without command line editing.
 
-   It prints PROMPT_ARG once at the start.
+   It prints PROMPT once at the start.
    Action is compatible with "readline", e.g. space for the result is
    malloc'd and should be freed by the caller.
 
    A NULL return means end of file.  */
-char *
-gdb_readline (const char *prompt_arg)
+
+static char *
+gdb_readline_no_editing (const char *prompt)
 {
-  int c;
-  char *result;
-  int input_index = 0;
-  int result_size = 80;
+  struct buffer line_buffer;
+  /* Read from stdin if we are executing a user defined command.  This
+     is the right thing for prompt_for_continue, at least.  */
+  FILE *stream = instream != NULL ? instream : stdin;
+  int fd = fileno (stream);
 
-  if (prompt_arg)
+  buffer_init (&line_buffer);
+
+  if (prompt != NULL)
     {
       /* Don't use a _filtered function here.  It causes the assumed
          character position to be off, since the newline we read from
          the user is not accounted for.  */
-      fputs_unfiltered (prompt_arg, gdb_stdout);
+      fputs_unfiltered (prompt, gdb_stdout);
       gdb_flush (gdb_stdout);
     }
 
-  result = (char *) xmalloc (result_size);
-
   while (1)
     {
-      /* Read from stdin if we are executing a user defined command.
-         This is the right thing for prompt_for_continue, at least.  */
-      c = fgetc (instream ? instream : stdin);
+      int c;
+      int numfds;
+      fd_set readfds;
+
+      QUIT;
+
+      /* Wait until at least one byte of data is available.  Control-C
+        can interrupt interruptible_select, but not fgetc.  */
+      FD_ZERO (&readfds);
+      FD_SET (fd, &readfds);
+      if (interruptible_select (fd + 1, &readfds, NULL, NULL, NULL) == -1)
+       {
+         if (errno == EINTR)
+           {
+             /* If this was ctrl-c, the QUIT above handles it.  */
+             continue;
+           }
+         perror_with_name (("select"));
+       }
+
+      c = fgetc (stream);
 
       if (c == EOF)
        {
-         if (input_index > 0)
+         if (line_buffer.used_size > 0)
            /* The last line does not end with a newline.  Return it, and
               if we are called again fgetc will still return EOF and
               we'll return NULL then.  */
            break;
-         xfree (result);
+         xfree (buffer_finish (&line_buffer));
          return NULL;
        }
 
       if (c == '\n')
        {
-         if (input_index > 0 && result[input_index - 1] == '\r')
-           input_index--;
+         if (line_buffer.used_size > 0
+             && line_buffer.buffer[line_buffer.used_size - 1] == '\r')
+           line_buffer.used_size--;
          break;
        }
 
-      result[input_index++] = c;
-      while (input_index >= result_size)
-       {
-         result_size *= 2;
-         result = (char *) xrealloc (result, result_size);
-       }
+      buffer_grow_char (&line_buffer, c);
     }
 
-  result[input_index++] = '\0';
-  return result;
+  buffer_grow_char (&line_buffer, '\0');
+  return buffer_finish (&line_buffer);
 }
 
 /* Variables which control command line editing and history
@@ -698,6 +701,20 @@ show_history_size (struct ui_file *file, int from_tty,
                    value);
 }
 
+/* Variable associated with the "history remove-duplicates" option.
+   The value -1 means unlimited.  */
+static int history_remove_duplicates = 0;
+
+static void
+show_history_remove_duplicates (struct ui_file *file, int from_tty,
+                               struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file,
+                   _("The number of history entries to look back at for "
+                     "duplicates is %s.\n"),
+                   value);
+}
+
 static char *history_filename;
 static void
 show_history_filename (struct ui_file *file, int from_tty,
@@ -739,6 +756,21 @@ static char *gdb_readline_wrapper_result;
    return.  */
 static void (*saved_after_char_processing_hook) (void);
 
+
+/* The number of nested readline secondary prompts that are currently
+   active.  */
+
+static int gdb_secondary_prompt_depth = 0;
+
+/* See top.h.  */
+
+int
+gdb_in_secondary_prompt_p (void)
+{
+  return gdb_secondary_prompt_depth > 0;
+}
+
+
 /* This function is called when readline has seen a complete line of
    text.  */
 
@@ -777,12 +809,14 @@ struct gdb_readline_wrapper_cleanup
 static void
 gdb_readline_wrapper_cleanup (void *arg)
 {
-  struct gdb_readline_wrapper_cleanup *cleanup = arg;
+  struct ui *ui = current_ui;
+  struct gdb_readline_wrapper_cleanup *cleanup
+    = (struct gdb_readline_wrapper_cleanup *) arg;
 
   rl_already_prompted = cleanup->already_prompted_orig;
 
-  gdb_assert (input_handler == gdb_readline_wrapper_line);
-  input_handler = cleanup->handler_orig;
+  gdb_assert (ui->input_handler == gdb_readline_wrapper_line);
+  ui->input_handler = cleanup->handler_orig;
 
   /* Don't restore our input handler in readline yet.  That would make
      readline prep the terminal (putting it in raw mode), while the
@@ -793,6 +827,8 @@ gdb_readline_wrapper_cleanup (void *arg)
 
   gdb_readline_wrapper_result = NULL;
   gdb_readline_wrapper_done = 0;
+  gdb_secondary_prompt_depth--;
+  gdb_assert (gdb_secondary_prompt_depth >= 0);
 
   after_char_processing_hook = saved_after_char_processing_hook;
   saved_after_char_processing_hook = NULL;
@@ -806,18 +842,20 @@ gdb_readline_wrapper_cleanup (void *arg)
 char *
 gdb_readline_wrapper (const char *prompt)
 {
+  struct ui *ui = current_ui;
   struct cleanup *back_to;
   struct gdb_readline_wrapper_cleanup *cleanup;
   char *retval;
 
-  cleanup = xmalloc (sizeof (*cleanup));
-  cleanup->handler_orig = input_handler;
-  input_handler = gdb_readline_wrapper_line;
+  cleanup = XNEW (struct gdb_readline_wrapper_cleanup);
+  cleanup->handler_orig = ui->input_handler;
+  ui->input_handler = gdb_readline_wrapper_line;
 
   cleanup->already_prompted_orig = rl_already_prompted;
 
   cleanup->target_is_async_orig = target_is_async_p ();
 
+  gdb_secondary_prompt_depth++;
   back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup);
 
   if (cleanup->target_is_async_orig)
@@ -897,8 +935,43 @@ static int command_count = 0;
 void
 gdb_add_history (const char *command)
 {
-  add_history (command);
   command_count++;
+
+  if (history_remove_duplicates != 0)
+    {
+      int lookbehind;
+      int lookbehind_threshold;
+
+      /* The lookbehind threshold for finding a duplicate history entry is
+        bounded by command_count because we can't meaningfully delete
+        history entries that are already stored in the history file since
+        the history file is appended to.  */
+      if (history_remove_duplicates == -1
+         || history_remove_duplicates > command_count)
+       lookbehind_threshold = command_count;
+      else
+       lookbehind_threshold = history_remove_duplicates;
+
+      using_history ();
+      for (lookbehind = 0; lookbehind < lookbehind_threshold; lookbehind++)
+       {
+         HIST_ENTRY *temp = previous_history ();
+
+         if (temp == NULL)
+           break;
+
+         if (strcmp (temp->line, command) == 0)
+           {
+             HIST_ENTRY *prev = remove_history (where_history ());
+             command_count--;
+             free_history_entry (prev);
+             break;
+           }
+       }
+      using_history ();
+    }
+
+  add_history (command);
 }
 
 /* Safely append new history entries to the history file in a corruption-free
@@ -956,32 +1029,26 @@ gdb_safe_append_history (void)
   do_cleanups (old_chain);
 }
 
-/* Read one line from the command input stream `instream'
-   into the local static buffer `linebuffer' (whose current length
-   is `linelength').
-   The buffer is made bigger as necessary.
-   Returns the address of the start of the line.
+/* Read one line from the command input stream `instream' into a local
+   static buffer.  The buffer is made bigger as necessary.  Returns
+   the address of the start of the line.
 
    NULL is returned for end of file.
 
-   *If* the instream == stdin & stdin is a terminal, the line read
-   is copied into the file line saver (global var char *line,
-   length linesize) so that it can be duplicated.
+   *If* the instream == stdin & stdin is a terminal, the line read is
+   copied into the global 'saved_command_line' so that it can be
+   repeated.
 
-   This routine either uses fancy command line editing or
-   simple input as the user has requested.  */
+   This routine either uses fancy command line editing or simple input
+   as the user has requested.  */
 
 char *
 command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 {
-  static char *linebuffer = 0;
-  static unsigned linelength = 0;
+  static struct buffer cmd_line_buffer;
+  static int cmd_line_buffer_initialized;
   const char *prompt = prompt_arg;
-  char *p;
-  char *p1;
-  char *rl;
-  char *nline;
-  char got_eof = 0;
+  char *cmd;
 
   /* The annotation suffix must be non-NULL.  */
   if (annotation_suffix == NULL)
@@ -991,8 +1058,9 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
     {
       char *local_prompt;
 
-      local_prompt = alloca ((prompt == NULL ? 0 : strlen (prompt))
-                            + strlen (annotation_suffix) + 40);
+      local_prompt
+       = (char *) alloca ((prompt == NULL ? 0 : strlen (prompt))
+                          + strlen (annotation_suffix) + 40);
       if (prompt == NULL)
        local_prompt[0] = '\0';
       else
@@ -1004,18 +1072,15 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
       prompt = local_prompt;
     }
 
-  if (linebuffer == 0)
+  if (!cmd_line_buffer_initialized)
     {
-      linelength = 80;
-      linebuffer = (char *) xmalloc (linelength);
+      buffer_init (&cmd_line_buffer);
+      cmd_line_buffer_initialized = 1;
     }
 
-  p = linebuffer;
+  /* Starting a new command line.  */
+  cmd_line_buffer.used_size = 0;
 
-  /* Control-C quits instantly if typed while in this loop
-     since it should not wait until the user types a newline.  */
-  immediate_quit++;
-  QUIT;
 #ifdef STOP_SIGNAL
   if (job_control)
     signal (STOP_SIGNAL, handle_stop_sig);
@@ -1023,6 +1088,8 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 
   while (1)
     {
+      char *rl;
+
       /* Make sure that all output has been output.  Some machines may
          let you get away with leaving out some of the gdb_flush, but
          not all.  */
@@ -1051,40 +1118,19 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
        }
       else
        {
-         rl = gdb_readline (prompt);
+         rl = gdb_readline_no_editing (prompt);
        }
 
-      if (annotation_level > 1 && instream == stdin)
+      cmd = handle_line_of_input (&cmd_line_buffer, rl,
+                                 repeat, annotation_suffix);
+      if (cmd == (char *) EOF)
        {
-         puts_unfiltered ("\n\032\032post-");
-         puts_unfiltered (annotation_suffix);
-         puts_unfiltered ("\n");
-       }
-
-      if (!rl || rl == (char *) EOF)
-       {
-         got_eof = 1;
+         cmd = NULL;
          break;
        }
-      if (strlen (rl) + 1 + (p - linebuffer) > linelength)
-       {
-         linelength = strlen (rl) + 1 + (p - linebuffer);
-         nline = (char *) xrealloc (linebuffer, linelength);
-         p += nline - linebuffer;
-         linebuffer = nline;
-       }
-      p1 = rl;
-      /* Copy line.  Don't copy null at end.  (Leaves line alone
-         if this was just a newline).  */
-      while (*p1)
-       *p++ = *p1++;
-
-      xfree (rl);              /* Allocated in readline.  */
-
-      if (p == linebuffer || *(p - 1) != '\\')
+      if (cmd != NULL)
        break;
 
-      p--;                     /* Put on top of '\'.  */
       prompt = NULL;
     }
 
@@ -1092,83 +1138,8 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
   if (job_control)
     signal (STOP_SIGNAL, SIG_DFL);
 #endif
-  immediate_quit--;
-
-  if (got_eof)
-    return NULL;
-
-#define SERVER_COMMAND_LENGTH 7
-  server_command =
-    (p - linebuffer > SERVER_COMMAND_LENGTH)
-    && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
-  if (server_command)
-    {
-      /* Note that we don't set `line'.  Between this and the check in
-         dont_repeat, this insures that repeating will still do the
-         right thing.  */
-      *p = '\0';
-      return linebuffer + SERVER_COMMAND_LENGTH;
-    }
-
-  /* Do history expansion if that is wished.  */
-  if (history_expansion_p && instream == stdin
-      && ISATTY (instream))
-    {
-      char *history_value;
-      int expanded;
-
-      *p = '\0';               /* Insert null now.  */
-      expanded = history_expand (linebuffer, &history_value);
-      if (expanded)
-       {
-         /* Print the changes.  */
-         printf_unfiltered ("%s\n", history_value);
-
-         /* If there was an error, call this function again.  */
-         if (expanded < 0)
-           {
-             xfree (history_value);
-             return command_line_input (prompt, repeat,
-                                        annotation_suffix);
-           }
-         if (strlen (history_value) > linelength)
-           {
-             linelength = strlen (history_value) + 1;
-             linebuffer = (char *) xrealloc (linebuffer, linelength);
-           }
-         strcpy (linebuffer, history_value);
-         p = linebuffer + strlen (linebuffer);
-       }
-      xfree (history_value);
-    }
-
-  /* If we just got an empty line, and that is supposed to repeat the
-     previous command, return the value in the global buffer.  */
-  if (repeat && p == linebuffer)
-    return saved_command_line;
-  for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
-  if (repeat && !*p1)
-    return saved_command_line;
 
-  *p = 0;
-
-  /* Add line to history if appropriate.  */
-  if (*linebuffer && input_from_terminal_p ())
-    gdb_add_history (linebuffer);
-
-  /* Save into global buffer if appropriate.  */
-  if (repeat)
-    {
-      if (linelength > saved_command_line_size)
-       {
-         saved_command_line = xrealloc (saved_command_line, linelength);
-         saved_command_line_size = linelength;
-       }
-      strcpy (saved_command_line, linebuffer);
-      return saved_command_line;
-    }
-
-  return linebuffer;
+  return cmd;
 }
 \f
 /* Print the GDB banner.  */
@@ -1184,7 +1155,7 @@ print_gdb_version (struct ui_file *stream)
   /* Second line is a copyright notice.  */
 
   fprintf_filtered (stream,
-                   "Copyright (C) 2015 Free Software Foundation, Inc.\n");
+                   "Copyright (C) 2016 Free Software Foundation, Inc.\n");
 
   /* Following the copyright is a brief statement that the program is
      free software, that users are free to copy and change it on
@@ -1363,7 +1334,7 @@ struct qt_args
 static int
 kill_or_detach (struct inferior *inf, void *args)
 {
-  struct qt_args *qt = args;
+  struct qt_args *qt = (struct qt_args *) args;
   struct thread_info *thread;
 
   if (inf->pid == 0)
@@ -1394,7 +1365,7 @@ kill_or_detach (struct inferior *inf, void *args)
 static int
 print_inferior_quit_action (struct inferior *inf, void *arg)
 {
-  struct ui_file *stb = arg;
+  struct ui_file *stb = (struct ui_file *) arg;
 
   if (inf->pid == 0)
     return 0;
@@ -1442,6 +1413,21 @@ quit_confirm (void)
   return qr;
 }
 
+/* Prepare to exit GDB cleanly by undoing any changes made to the
+   terminal so that we leave the terminal in the state we acquired it.  */
+
+static void
+undo_terminal_modifications_before_exit (void)
+{
+  target_terminal_ours ();
+#if defined(TUI)
+  tui_disable ();
+#endif
+  if (async_command_editing_p)
+    gdb_disable_readline ();
+}
+
+
 /* Quit without asking for confirmation.  */
 
 void
@@ -1450,6 +1436,8 @@ quit_force (char *args, int from_tty)
   int exit_code = 0;
   struct qt_args qt;
 
+  undo_terminal_modifications_before_exit ();
+
   /* An optional expression may be used to cause gdb to terminate with the 
      value of that expression.  */
   if (args)
@@ -1685,10 +1673,13 @@ init_history (void)
   if (tmpenv)
     {
       long var;
+      int saved_errno;
       char *endptr;
 
       tmpenv = skip_spaces (tmpenv);
+      errno = 0;
       var = strtol (tmpenv, &endptr, 10);
+      saved_errno = errno;
       endptr = skip_spaces (endptr);
 
       /* If GDBHISTSIZE is non-numeric then ignore it.  If GDBHISTSIZE is the
@@ -1700,7 +1691,12 @@ init_history (void)
        ;
       else if (*tmpenv == '\0'
               || var < 0
-              || var > INT_MAX)
+              || var > INT_MAX
+              /* On targets where INT_MAX == LONG_MAX, we have to look at
+                 errno after calling strtol to distinguish between a value that
+                 is exactly INT_MAX and an overflowing value that was clamped
+                 to INT_MAX.  */
+              || (var == INT_MAX && saved_errno == ERANGE))
        history_size_setshow_var = -1;
       else
        history_size_setshow_var = var;
@@ -1805,10 +1801,6 @@ init_main (void)
      the DEFAULT_PROMPT is.  */
   set_prompt (DEFAULT_PROMPT);
 
-  /* Set things up for annotation_level > 1, if the user ever decides
-     to use it.  */
-  async_annotation_suffix = "prompt";
-
   /* Set the important stuff up for command editing.  */
   command_editing_p = 1;
   history_expansion_p = 0;
@@ -1872,6 +1864,21 @@ variable \"GDBHISTSIZE\", or to 256 if this variable is not set."),
                            show_history_size,
                            &sethistlist, &showhistlist);
 
+  add_setshow_zuinteger_unlimited_cmd ("remove-duplicates", no_class,
+                                      &history_remove_duplicates, _("\
+Set how far back in history to look for and remove duplicate entries."), _("\
+Show how far back in history to look for and remove duplicate entries."), _("\
+If set to a nonzero value N, GDB will look back at the last N history entries\n\
+and remove the first history entry that is a duplicate of the most recent\n\
+entry, each time a new history entry is added.\n\
+If set to \"unlimited\", this lookbehind is unbounded.\n\
+Only history entries added during this session are considered for removal.\n\
+If set to 0, removal of duplicate history entries is disabled.\n\
+By default this option is set to 0."),
+                          NULL,
+                          show_history_remove_duplicates,
+                          &sethistlist, &showhistlist);
+
   add_setshow_filename_cmd ("filename", no_class, &history_filename, _("\
 Set the filename in which to record the command history"), _("\
 Show the filename in which to record the command history"), _("\