gdb: remove TYPE_CODE macro
[deliverable/binutils-gdb.git] / gdb / cli / cli-cmds.c
index aa9a9a58d56a0819d1fda94c92c36e4ba2f47a71..58e9cf319569a390b0765da4e3bc34614293d7fc 100644 (file)
@@ -1,6 +1,6 @@
 /* GDB CLI commands.
 
-   Copyright (C) 2000-2015 Free Software Foundation, Inc.
+   Copyright (C) 2000-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include "defs.h"
 #include "arch-utils.h"
-#include "dyn-string.h"
-#include "readline/readline.h"
 #include "readline/tilde.h"
 #include "completer.h"
 #include "target.h"    /* For baud_rate, remote_debug and remote_timeout.  */
-#include "gdb_wait.h"  /* For shell escape implementation.  */
+#include "gdbsupport/gdb_wait.h"       /* For shell escape implementation.  */
+#include "gdbcmd.h"
 #include "gdb_regex.h" /* Used by apropos_command.  */
 #include "gdb_vfork.h"
 #include "linespec.h"
 #include "source.h"
 #include "disasm.h"
 #include "tracepoint.h"
-#include "filestuff.h"
+#include "gdbsupport/filestuff.h"
 #include "location.h"
+#include "block.h"
 
 #include "ui-out.h"
+#include "interps.h"
 
 #include "top.h"
 #include "cli/cli-decode.h"
 #include "cli/cli-script.h"
 #include "cli/cli-setshow.h"
 #include "cli/cli-cmds.h"
+#include "cli/cli-style.h"
 #include "cli/cli-utils.h"
 
 #include "extension.h"
+#include "gdbsupport/pathstuff.h"
 
 #ifdef TUI
 #include "tui/tui.h"   /* For tui_active et.al.  */
 #endif
 
 #include <fcntl.h>
-
-/* Prototypes for local command functions */
-
-static void complete_command (char *, int);
-
-static void echo_command (char *, int);
-
-static void pwd_command (char *, int);
-
-static void show_version (char *, int);
-
-static void help_command (char *, int);
-
-static void show_command (char *, int);
-
-static void info_command (char *, int);
-
-static void show_debug (char *, int);
-
-static void set_debug (char *, int);
-
-static void show_user (char *, int);
-
-static void make_command (char *, int);
-
-static void shell_escape (char *, int);
-
-static void edit_command (char *, int);
-
-static void list_command (char *, int);
+#include <algorithm>
+#include <string>
 
 /* Prototypes for local utility functions */
 
-static void ambiguous_line_spec (struct symtabs_and_lines *);
+static void print_sal_location (const symtab_and_line &sal);
+
+static void ambiguous_line_spec (gdb::array_view<const symtab_and_line> sals,
+                                const char *format, ...)
+  ATTRIBUTE_PRINTF (2, 3);
 
-static void filter_sals (struct symtabs_and_lines *);
+static void filter_sals (std::vector<symtab_and_line> &);
 
 \f
-/* Limit the call depth of user-defined commands */
+/* See cli-cmds.h. */
 unsigned int max_user_call_depth;
 
 /* Define all cmd_list_elements.  */
@@ -167,6 +146,10 @@ struct cmd_list_element *maintenanceinfolist;
 
 struct cmd_list_element *maintenanceprintlist;
 
+/* Chain containing all defined "maintenance check" subcommands.  */
+
+struct cmd_list_element *maintenancechecklist;
+
 struct cmd_list_element *setprintlist;
 
 struct cmd_list_element *showprintlist;
@@ -182,7 +165,7 @@ struct cmd_list_element *showchecklist;
 /* Command tracing state.  */
 
 int source_verbose = 0;
-int trace_commands = 0;
+bool trace_commands = false;
 \f
 /* 'script-extension' option support.  */
 
@@ -208,52 +191,154 @@ error_no_arg (const char *why)
   error (_("Argument required (%s)."), why);
 }
 
-/* The "info" command is defined as a prefix, with allow_unknown = 0.
-   Therefore, its own definition is called only for "info" with no
-   args.  */
+/* This implements the "info" prefix command.  Normally such commands
+   are automatically handled by add_basic_prefix_cmd, but in this case
+   a separate command is used so that it can be hooked into by
+   gdb-gdb.gdb.  */
 
 static void
-info_command (char *arg, int from_tty)
+info_command (const char *arg, int from_tty)
 {
-  printf_unfiltered (_("\"info\" must be followed by "
-                      "the name of an info command.\n"));
   help_list (infolist, "info ", all_commands, gdb_stdout);
 }
 
-/* The "show" command with no arguments shows all the settings.  */
+/* See cli/cli-cmds.h.  */
+
+void
+with_command_1 (const char *set_cmd_prefix,
+               cmd_list_element *setlist, const char *args, int from_tty)
+{
+  if (args == nullptr)
+    error (_("Missing arguments."));
+
+  const char *delim = strstr (args, "--");
+  const char *nested_cmd = nullptr;
+
+  if (delim == args)
+    error (_("Missing setting before '--' delimiter"));
+
+  if (delim == nullptr || *skip_spaces (&delim[2]) == '\0')
+    nested_cmd = repeat_previous ();
+
+  cmd_list_element *set_cmd = lookup_cmd (&args, setlist, set_cmd_prefix,
+                                         /*allow_unknown=*/ 0,
+                                         /*ignore_help_classes=*/ 1);
+  gdb_assert (set_cmd != nullptr);
+
+  if (set_cmd->var == nullptr)
+    error (_("Cannot use this setting with the \"with\" command"));
+
+  std::string temp_value
+    = (delim == nullptr ? args : std::string (args, delim - args));
+
+  if (nested_cmd == nullptr)
+    nested_cmd = skip_spaces (delim + 2);
+
+  std::string org_value = get_setshow_command_value_string (set_cmd);
+
+  /* Tweak the setting to the new temporary value.  */
+  do_set_command (temp_value.c_str (), from_tty, set_cmd);
+
+  try
+    {
+      scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
+
+      /* Execute the nested command.  */
+      execute_command (nested_cmd, from_tty);
+    }
+  catch (const gdb_exception &ex)
+    {
+      /* Restore the setting and rethrow.  If restoring the setting
+        throws, swallow the new exception and warn.  There's nothing
+        else we can reasonably do.  */
+      try
+       {
+         do_set_command (org_value.c_str (), from_tty, set_cmd);
+       }
+      catch (const gdb_exception &ex2)
+       {
+         warning (_("Couldn't restore setting: %s"), ex2.what ());
+       }
+
+      throw;
+    }
+
+  /* Restore the setting.  */
+  do_set_command (org_value.c_str (), from_tty, set_cmd);
+}
+
+/* See cli/cli-cmds.h.  */
+
+void
+with_command_completer_1 (const char *set_cmd_prefix,
+                         completion_tracker &tracker,
+                         const char *text)
+{
+  tracker.set_use_custom_word_point (true);
+
+  const char *delim = strstr (text, "--");
+
+  /* If we're still not past the "--" delimiter, complete the "with"
+     command as if it was a "set" command.  */
+  if (delim == text
+      || delim == nullptr
+      || !isspace (delim[-1])
+      || !(isspace (delim[2]) || delim[2] == '\0'))
+    {
+      std::string new_text = std::string (set_cmd_prefix) + text;
+      tracker.advance_custom_word_point_by (-(int) strlen (set_cmd_prefix));
+      complete_nested_command_line (tracker, new_text.c_str ());
+      return;
+    }
+
+  /* We're past the "--" delimiter.  Complete on the sub command.  */
+  const char *nested_cmd = skip_spaces (delim + 2);
+  tracker.advance_custom_word_point_by (nested_cmd - text);
+  complete_nested_command_line (tracker, nested_cmd);
+}
+
+/* The "with" command.  */
+
+static void
+with_command (const char *args, int from_tty)
+{
+  with_command_1 ("set ", setlist, args, from_tty);
+}
+
+/* "with" command completer.  */
 
 static void
-show_command (char *arg, int from_tty)
+with_command_completer (struct cmd_list_element *ignore,
+                       completion_tracker &tracker,
+                       const char *text, const char * /*word*/)
 {
-  cmd_show_list (showlist, from_tty, "");
+  with_command_completer_1 ("set ", tracker,  text);
 }
+
 \f
 /* Provide documentation on command or list given by COMMAND.  FROM_TTY
    is ignored.  */
 
 static void
-help_command (char *command, int from_tty)
+help_command (const char *command, int from_tty)
 {
   help_cmd (command, gdb_stdout);
 }
 \f
+
 /* Note: The "complete" command is used by Emacs to implement completion.
    [Is that why this function writes output with *_unfiltered?]  */
 
 static void
-complete_command (char *arg, int from_tty)
+complete_command (const char *arg, int from_tty)
 {
-  int argpoint;
-  char *point, *arg_prefix;
-  VEC (char_ptr) *completions;
-
   dont_repeat ();
 
   if (max_completions == 0)
     {
       /* Only print this for non-mi frontends.  An MI frontend may not
         be able to handle this.  */
-      if (!ui_out_is_mi_like_p (current_uiout))
+      if (!current_uiout->is_mi_like_p ())
        {
          printf_unfiltered (_("max-completions is zero,"
                               " completion is disabled.\n"));
@@ -263,57 +348,39 @@ complete_command (char *arg, int from_tty)
 
   if (arg == NULL)
     arg = "";
-  argpoint = strlen (arg);
-
-  /* complete_line assumes that its first argument is somewhere
-     within, and except for filenames at the beginning of, the word to
-     be completed.  The following crude imitation of readline's
-     word-breaking tries to accomodate this.  */
-  point = arg + argpoint;
-  while (point > arg)
-    {
-      if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
-        break;
-      point--;
-    }
 
-  arg_prefix = alloca (point - arg + 1);
-  memcpy (arg_prefix, arg, point - arg);
-  arg_prefix[point - arg] = 0;
+  int quote_char = '\0';
+  const char *word;
 
-  completions = complete_line (point, arg, argpoint);
+  completion_result result = complete (arg, &word, &quote_char);
 
-  if (completions)
+  if (result.number_matches != 0)
     {
-      int ix, size = VEC_length (char_ptr, completions);
-      char *item, *prev = NULL;
-
-      qsort (VEC_address (char_ptr, completions), size,
-            sizeof (char *), compare_strings);
+      std::string arg_prefix (arg, word - arg);
 
-      /* We do extra processing here since we only want to print each
-        unique item once.  */
-      for (ix = 0; VEC_iterate (char_ptr, completions, ix, item); ++ix)
+      if (result.number_matches == 1)
+       printf_unfiltered ("%s%s\n", arg_prefix.c_str (), result.match_list[0]);
+      else
        {
-         if (prev == NULL || strcmp (item, prev) != 0)
+         result.sort_match_list ();
+
+         for (size_t i = 0; i < result.number_matches; i++)
            {
-             printf_unfiltered ("%s%s\n", arg_prefix, item);
-             xfree (prev);
-             prev = item;
+             printf_unfiltered ("%s%s",
+                                arg_prefix.c_str (),
+                                result.match_list[i + 1]);
+             if (quote_char)
+               printf_unfiltered ("%c", quote_char);
+             printf_unfiltered ("\n");
            }
-         else
-           xfree (item);
        }
 
-      xfree (prev);
-      VEC_free (char_ptr, completions);
-
-      if (size == max_completions)
+      if (result.number_matches == max_completions)
        {
-         /* ARG_PREFIX and POINT are included in the output so that emacs
+         /* ARG_PREFIX and WORD are included in the output so that emacs
             will include the message in the output.  */
          printf_unfiltered (_("%s%s %s\n"),
-                            arg_prefix, point,
+                            arg_prefix.c_str (), word,
                             get_max_completions_reached_message ());
        }
     }
@@ -326,14 +393,14 @@ is_complete_command (struct cmd_list_element *c)
 }
 
 static void
-show_version (char *args, int from_tty)
+show_version (const char *args, int from_tty)
 {
-  print_gdb_version (gdb_stdout);
+  print_gdb_version (gdb_stdout, true);
   printf_filtered ("\n");
 }
 
 static void
-show_configuration (char *args, int from_tty)
+show_configuration (const char *args, int from_tty)
 {
   print_gdb_configuration (gdb_stdout);
 }
@@ -341,50 +408,65 @@ show_configuration (char *args, int from_tty)
 /* Handle the quit command.  */
 
 void
-quit_command (char *args, int from_tty)
+quit_command (const char *args, int from_tty)
 {
+  int exit_code = 0;
+
+  /* An optional expression may be used to cause gdb to terminate with
+     the value of that expression.  */
+  if (args)
+    {
+      struct value *val = parse_and_eval (args);
+
+      exit_code = (int) value_as_long (val);
+    }
+
   if (!quit_confirm ())
     error (_("Not confirmed."));
 
   query_if_trace_running (from_tty);
 
-  quit_force (args, from_tty);
+  quit_force (args ? &exit_code : NULL, from_tty);
 }
 
 static void
-pwd_command (char *args, int from_tty)
+pwd_command (const char *args, int from_tty)
 {
   if (args)
     error (_("The \"pwd\" command does not take an argument: %s"), args);
-  if (! getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)))
+
+  gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+
+  if (cwd == NULL)
     error (_("Error finding name of working directory: %s"),
            safe_strerror (errno));
 
-  if (strcmp (gdb_dirbuf, current_directory) != 0)
-    printf_unfiltered (_("Working directory %s\n (canonically %s).\n"),
-                      current_directory, gdb_dirbuf);
+  if (strcmp (cwd.get (), current_directory) != 0)
+    printf_unfiltered (_("Working directory %ps\n (canonically %ps).\n"),
+                      styled_string (file_name_style.style (),
+                                     current_directory),
+                      styled_string (file_name_style.style (), cwd.get ()));
   else
-    printf_unfiltered (_("Working directory %s.\n"), current_directory);
+    printf_unfiltered (_("Working directory %ps.\n"),
+                      styled_string (file_name_style.style (),
+                                     current_directory));
 }
 
 void
-cd_command (char *dir, int from_tty)
+cd_command (const char *dir, int from_tty)
 {
   int len;
   /* Found something other than leading repetitions of "/..".  */
   int found_real_path;
   char *p;
-  struct cleanup *cleanup;
 
   /* If the new directory is absolute, repeat is a no-op; if relative,
      repeat might be useful but is more likely to be a mistake.  */
   dont_repeat ();
 
-  if (dir == 0)
-    dir = "~";
-
-  dir = tilde_expand (dir);
-  cleanup = make_cleanup (xfree, dir);
+  gdb::unique_xmalloc_ptr<char> dir_holder
+    (tilde_expand (dir != NULL ? dir : "~"));
+  dir = dir_holder.get ();
 
   if (chdir (dir) < 0)
     perror_with_name (dir);
@@ -393,7 +475,8 @@ cd_command (char *dir, int from_tty)
   /* There's too much mess with DOSish names like "d:", "d:.",
      "d:./foo" etc.  Instead of having lots of special #ifdef'ed code,
      simply get the canonicalized name of the current directory.  */
-  dir = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
+  gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
+  dir = cwd.get ();
 #endif
 
   len = strlen (dir);
@@ -409,17 +492,20 @@ cd_command (char *dir, int from_tty)
        len--;
     }
 
-  dir = savestring (dir, len);
-  if (IS_ABSOLUTE_PATH (dir))
-    current_directory = dir;
+  dir_holder.reset (savestring (dir, len));
+  if (IS_ABSOLUTE_PATH (dir_holder.get ()))
+    {
+      xfree (current_directory);
+      current_directory = dir_holder.release ();
+    }
   else
     {
       if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
-       current_directory = concat (current_directory, dir, (char *)NULL);
+       current_directory = concat (current_directory, dir_holder.get (),
+                                   (char *) NULL);
       else
        current_directory = concat (current_directory, SLASH_STRING,
-                                   dir, (char *)NULL);
-      xfree (dir);
+                                   dir_holder.get (), (char *) NULL);
     }
 
   /* Now simplify any occurrences of `.' and `..' in the pathname.  */
@@ -468,8 +554,6 @@ cd_command (char *dir, int from_tty)
 
   if (from_tty)
     pwd_command ((char *) 0, 1);
-
-  do_cleanups (cleanup);
 }
 \f
 /* Show the current value of the 'script-extension' option.  */
@@ -485,63 +569,58 @@ show_script_ext_mode (struct ui_file *file, int from_tty,
 
 /* Try to open SCRIPT_FILE.
    If successful, the full path name is stored in *FULL_PATHP,
-   the stream is stored in *STREAMP, and return 1.
-   The caller is responsible for freeing *FULL_PATHP.
-   If not successful, return 0; errno is set for the last file
+   and the stream is returned.
+   If not successful, return NULL; errno is set for the last file
    we tried to open.
 
    If SEARCH_PATH is non-zero, and the file isn't found in cwd,
    search for it in the source search path.  */
 
-int
-find_and_open_script (const char *script_file, int search_path,
-                     FILE **streamp, char **full_pathp)
+gdb::optional<open_script>
+find_and_open_script (const char *script_file, int search_path)
 {
-  char *file;
   int fd;
-  struct cleanup *old_cleanups;
-  int search_flags = OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH;
+  openp_flags search_flags = OPF_TRY_CWD_FIRST | OPF_RETURN_REALPATH;
+  gdb::optional<open_script> opened;
 
-  file = tilde_expand (script_file);
-  old_cleanups = make_cleanup (xfree, file);
+  gdb::unique_xmalloc_ptr<char> file (tilde_expand (script_file));
 
   if (search_path)
     search_flags |= OPF_SEARCH_IN_PATH;
 
   /* Search for and open 'file' on the search path used for source
      files.  Put the full location in *FULL_PATHP.  */
+  gdb::unique_xmalloc_ptr<char> full_path;
   fd = openp (source_path, search_flags,
-             file, O_RDONLY, full_pathp);
+             file.get (), O_RDONLY, &full_path);
 
   if (fd == -1)
-    {
-      int save_errno = errno;
-      do_cleanups (old_cleanups);
-      errno = save_errno;
-      return 0;
-    }
-
-  do_cleanups (old_cleanups);
+    return opened;
 
-  *streamp = fdopen (fd, FOPEN_RT);
-  if (*streamp == NULL)
+  FILE *result = fdopen (fd, FOPEN_RT);
+  if (result == NULL)
     {
       int save_errno = errno;
 
       close (fd);
-      if (full_pathp)
-       xfree (*full_pathp);
       errno = save_errno;
-      return 0;
     }
+  else
+    opened.emplace (gdb_file_up (result), std::move (full_path));
 
-  return 1;
+  return opened;
 }
 
-/* Load script FILE, which has already been opened as STREAM.  */
+/* Load script FILE, which has already been opened as STREAM.
+   FILE_TO_OPEN is the form of FILE to use if one needs to open the file.
+   This is provided as FILE may have been found via the source search path.
+   An important thing to note here is that FILE may be a symlink to a file
+   with a different or non-existing suffix, and thus one cannot infer the
+   extension language from FILE_TO_OPEN.  */
 
 static void
-source_script_from_stream (FILE *stream, const char *file)
+source_script_from_stream (FILE *stream, const char *file,
+                          const char *file_to_open)
 {
   if (script_ext_mode != script_ext_off)
     {
@@ -556,7 +635,7 @@ source_script_from_stream (FILE *stream, const char *file)
                = ext_lang_script_sourcer (extlang);
 
              gdb_assert (sourcer != NULL);
-             sourcer (extlang, stream, file);
+             sourcer (extlang, stream, file_to_open);
              return;
            }
          else if (script_ext_mode == script_ext_soft)
@@ -580,14 +659,12 @@ source_script_from_stream (FILE *stream, const char *file)
 static void
 source_script_with_search (const char *file, int from_tty, int search_path)
 {
-  FILE *stream;
-  char *full_path;
-  struct cleanup *old_cleanups;
 
   if (file == NULL || *file == 0)
     error (_("source command requires file name of file to source."));
 
-  if (!find_and_open_script (file, search_path, &stream, &full_path))
+  gdb::optional<open_script> opened = find_and_open_script (file, search_path);
+  if (!opened)
     {
       /* The script wasn't found, or was otherwise inaccessible.
          If the source command was invoked interactively, throw an
@@ -602,15 +679,13 @@ source_script_with_search (const char *file, int from_tty, int search_path)
        }
     }
 
-  old_cleanups = make_cleanup (xfree, full_path);
-  make_cleanup_fclose (stream);
   /* The python support reopens the file, so we need to pass full_path here
      in case the file was found on the search path.  It's useful to do this
      anyway so that error messages show the actual file used.  But only do
      this if we (may have) used search_path, as printing the full path in
      errors for the non-search case can be more noise than signal.  */
-  source_script_from_stream (stream, search_path ? full_path : file);
-  do_cleanups (old_cleanups);
+  source_script_from_stream (opened->stream.get (), file,
+                            search_path ? opened->full_path.get () : file);
 }
 
 /* Wrapper around source_script_with_search to export it to main.c
@@ -622,26 +697,13 @@ source_script (const char *file, int from_tty)
   source_script_with_search (file, from_tty, 0);
 }
 
-/* Return the source_verbose global variable to its previous state
-   on exit from the source command, by whatever means.  */
 static void
-source_verbose_cleanup (void *old_value)
+source_command (const char *args, int from_tty)
 {
-  source_verbose = *(int *)old_value;
-  xfree (old_value);
-}
-
-static void
-source_command (char *args, int from_tty)
-{
-  struct cleanup *old_cleanups;
-  char *file = args;
-  int *old_source_verbose = XNEW (int);
+  const char *file = args;
   int search_path = 0;
 
-  *old_source_verbose = source_verbose;
-  old_cleanups = make_cleanup (source_verbose_cleanup, 
-                              old_source_verbose);
+  scoped_restore save_source_verbose = make_scoped_restore (&source_verbose);
 
   /* -v causes the source command to run in verbose mode.
      -s causes the file to be searched in the source search path,
@@ -682,13 +744,11 @@ source_command (char *args, int from_tty)
     }
 
   source_script_with_search (file, from_tty, search_path);
-
-  do_cleanups (old_cleanups);
 }
 
 
 static void
-echo_command (char *text, int from_tty)
+echo_command (const char *text, int from_tty)
 {
   const char *p = text;
   int c;
@@ -711,13 +771,46 @@ echo_command (char *text, int from_tty)
          printf_filtered ("%c", c);
       }
 
+  reset_terminal_style (gdb_stdout);
+
   /* Force this output to appear now.  */
   wrap_here ("");
   gdb_flush (gdb_stdout);
 }
 
+/* Sets the last launched shell command convenience variables based on
+   EXIT_STATUS.  */
+
+static void
+exit_status_set_internal_vars (int exit_status)
+{
+  struct internalvar *var_code = lookup_internalvar ("_shell_exitcode");
+  struct internalvar *var_signal = lookup_internalvar ("_shell_exitsignal");
+
+  clear_internalvar (var_code);
+  clear_internalvar (var_signal);
+  if (WIFEXITED (exit_status))
+    set_internalvar_integer (var_code, WEXITSTATUS (exit_status));
+#ifdef __MINGW32__
+  else if (WIFSIGNALED (exit_status) && WTERMSIG (exit_status) == -1)
+    {
+      /* The -1 condition can happen on MinGW, if we don't recognize
+        the fatal exception code encoded in the exit status; see
+        gdbsupport/gdb_wait.c.  We don't want to lose information in
+        the exit status in that case.  Record it as a normal exit
+        with the full exit status, including the higher 0xC0000000
+        bits.  */
+      set_internalvar_integer (var_code, exit_status);
+    }
+#endif
+  else if (WIFSIGNALED (exit_status))
+    set_internalvar_integer (var_signal, WTERMSIG (exit_status));
+  else
+    warning (_("unexpected shell command exit status %d"), exit_status);
+}
+
 static void
-shell_escape (char *arg, int from_tty)
+shell_escape (const char *arg, int from_tty)
 {
 #if defined(CANT_FORK) || \
       (!defined(HAVE_WORKING_VFORK) && !defined(HAVE_WORKING_FORK))
@@ -729,33 +822,25 @@ shell_escape (char *arg, int from_tty)
     arg = "inferior shell";
 
   if (rc == -1)
-    {
-      fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", arg,
-                         safe_strerror (errno));
-      gdb_flush (gdb_stderr);
-    }
+    fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", arg,
+                       safe_strerror (errno));
   else if (rc)
-    {
-      fprintf_unfiltered (gdb_stderr, "%s exited with status %d\n", arg, rc);
-      gdb_flush (gdb_stderr);
-    }
+    fprintf_unfiltered (gdb_stderr, "%s exited with status %d\n", arg, rc);
 #ifdef GLOBAL_CURDIR
   /* Make sure to return to the directory GDB thinks it is, in case
      the shell command we just ran changed it.  */
   chdir (current_directory);
+  exit_status_set_internal_vars (rc);
 #endif
 #else /* Can fork.  */
   int status, pid;
 
   if ((pid = vfork ()) == 0)
     {
-      const char *p, *user_shell;
+      const char *p, *user_shell = get_shell ();
 
       close_most_fds ();
 
-      if ((user_shell = (char *) getenv ("SHELL")) == NULL)
-       user_shell = "/bin/sh";
-
       /* Get the name of the shell for arg0.  */
       p = lbasename (user_shell);
 
@@ -766,7 +851,6 @@ shell_escape (char *arg, int from_tty)
 
       fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,
                          safe_strerror (errno));
-      gdb_flush (gdb_stderr);
       _exit (0177);
     }
 
@@ -774,16 +858,24 @@ shell_escape (char *arg, int from_tty)
     waitpid (pid, &status, 0);
   else
     error (_("Fork failed"));
+  exit_status_set_internal_vars (status);
 #endif /* Can fork.  */
 }
 
+/* Implementation of the "shell" command.  */
+
 static void
-edit_command (char *arg, int from_tty)
+shell_command (const char *arg, int from_tty)
+{
+  shell_escape (arg, from_tty);
+}
+
+static void
+edit_command (const char *arg, int from_tty)
 {
-  struct symtabs_and_lines sals;
   struct symtab_and_line sal;
   struct symbol *sym;
-  char *editor;
+  const char *editor;
   char *p;
   const char *fn;
 
@@ -804,33 +896,30 @@ edit_command (char *arg, int from_tty)
     }
   else
     {
-      struct cleanup *cleanup;
-      struct event_location *location;
-      char *arg1;
+      const char *arg1;
 
       /* Now should only be one argument -- decode it in SAL.  */
       arg1 = arg;
-      location = string_to_event_location (&arg1, current_language);
-      cleanup = make_cleanup_delete_event_location (location);
-      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
-
-      filter_sals (&sals);
-      if (! sals.nelts)
+      event_location_up location = string_to_event_location (&arg1,
+                                                            current_language);
+      std::vector<symtab_and_line> sals = decode_line_1 (location.get (),
+                                                        DECODE_LINE_LIST_MODE,
+                                                        NULL, NULL, 0);
+
+      filter_sals (sals);
+      if (sals.empty ())
        {
          /*  C++  */
-         do_cleanups (cleanup);
          return;
        }
-      if (sals.nelts > 1)
+      if (sals.size () > 1)
        {
-         ambiguous_line_spec (&sals);
-         xfree (sals.sals);
-         do_cleanups (cleanup);
+         ambiguous_line_spec (sals,
+                              _("Specified line is ambiguous:\n"));
          return;
        }
 
-      sal = sals.sals[0];
-      xfree (sals.sals);
+      sal = sals[0];
 
       if (*arg1)
         error (_("Junk at end of line specification."));
@@ -847,12 +936,12 @@ edit_command (char *arg, int from_tty)
            error (_("No source file for address %s."),
                   paddress (get_current_arch (), sal.pc));
 
-         gdbarch = get_objfile_arch (SYMTAB_OBJFILE (sal.symtab));
+         gdbarch = SYMTAB_OBJFILE (sal.symtab)->arch ();
           sym = find_pc_function (sal.pc);
           if (sym)
            printf_filtered ("%s is in %s (%s:%d).\n",
                             paddress (gdbarch, sal.pc),
-                            SYMBOL_PRINT_NAME (sym),
+                            sym->print_name (),
                             symtab_to_filename_for_display (sal.symtab),
                             sal.line);
           else
@@ -867,11 +956,10 @@ edit_command (char *arg, int from_tty)
 
       if (sal.symtab == 0)
         error (_("No line number known for %s."), arg);
-      do_cleanups (cleanup);
     }
 
-  if ((editor = (char *) getenv ("EDITOR")) == NULL)
-      editor = "/bin/ex";
+  if ((editor = getenv ("EDITOR")) == NULL)
+    editor = "/bin/ex";
 
   fn = symtab_to_fullname (sal.symtab);
 
@@ -882,29 +970,154 @@ edit_command (char *arg, int from_tty)
   xfree (p);
 }
 
+/* The options for the "pipe" command.  */
+
+struct pipe_cmd_opts
+{
+  /* For "-d".  */
+  char *delimiter = nullptr;
+
+  ~pipe_cmd_opts ()
+  {
+    xfree (delimiter);
+  }
+};
+
+static const gdb::option::option_def pipe_cmd_option_defs[] = {
+
+  gdb::option::string_option_def<pipe_cmd_opts> {
+    "d",
+    [] (pipe_cmd_opts *opts) { return &opts->delimiter; },
+    nullptr,
+    N_("Indicates to use the specified delimiter string to separate\n\
+COMMAND from SHELL_COMMAND, in alternative to |.  This is useful in\n\
+case COMMAND contains a | character."),
+  },
+
+};
+
+/* Create an option_def_group for the "pipe" command's options, with
+   OPTS as context.  */
+
+static inline gdb::option::option_def_group
+make_pipe_cmd_options_def_group (pipe_cmd_opts *opts)
+{
+  return {{pipe_cmd_option_defs}, opts};
+}
+
+/* Implementation of the "pipe" command.  */
+
+static void
+pipe_command (const char *arg, int from_tty)
+{
+  pipe_cmd_opts opts;
+
+  auto grp = make_pipe_cmd_options_def_group (&opts);
+  gdb::option::process_options
+    (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+
+  const char *delim = "|";
+  if (opts.delimiter != nullptr)
+    delim = opts.delimiter;
+
+  const char *command = arg;
+  if (command == nullptr)
+    error (_("Missing COMMAND"));
+
+  arg = strstr (arg, delim);
+
+  if (arg == nullptr)
+    error (_("Missing delimiter before SHELL_COMMAND"));
+
+  std::string gdb_cmd (command, arg - command);
+
+  arg += strlen (delim); /* Skip the delimiter.  */
+
+  if (gdb_cmd.empty ())
+    gdb_cmd = repeat_previous ();
+
+  const char *shell_command = skip_spaces (arg);
+  if (*shell_command == '\0')
+    error (_("Missing SHELL_COMMAND"));
+
+  FILE *to_shell_command = popen (shell_command, "w");
+
+  if (to_shell_command == nullptr)
+    error (_("Error launching \"%s\""), shell_command);
+
+  try
+    {
+      stdio_file pipe_file (to_shell_command);
+
+      execute_command_to_ui_file (&pipe_file, gdb_cmd.c_str (), from_tty);
+    }
+  catch (...)
+    {
+      pclose (to_shell_command);
+      throw;
+    }
+
+  int exit_status = pclose (to_shell_command);
+
+  if (exit_status < 0)
+    error (_("shell command \"%s\" failed: %s"), shell_command,
+           safe_strerror (errno));
+  exit_status_set_internal_vars (exit_status);
+}
+
+/* Completer for the pipe command.  */
+
 static void
-list_command (char *arg, int from_tty)
+pipe_command_completer (struct cmd_list_element *ignore,
+                       completion_tracker &tracker,
+                       const char *text, const char *word_ignored)
+{
+  pipe_cmd_opts opts;
+
+  const char *org_text = text;
+  auto grp = make_pipe_cmd_options_def_group (&opts);
+  if (gdb::option::complete_options
+      (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp))
+    return;
+
+  const char *delimiter = "|";
+  if (opts.delimiter != nullptr)
+    delimiter = opts.delimiter;
+
+  /* Check if we're past option values already.  */
+  if (text > org_text && !isspace (text[-1]))
+    return;
+
+  const char *delim = strstr (text, delimiter);
+
+  /* If we're still not past the delimiter, complete the gdb
+     command.  */
+  if (delim == nullptr || delim == text)
+    {
+      complete_nested_command_line (tracker, text);
+      return;
+    }
+
+  /* We're past the delimiter.  What follows is a shell command, which
+     we don't know how to complete.  */
+}
+
+static void
+list_command (const char *arg, int from_tty)
 {
-  struct symtabs_and_lines sals, sals_end;
-  struct symtab_and_line sal = { 0 };
-  struct symtab_and_line sal_end = { 0 };
-  struct symtab_and_line cursal = { 0 };
   struct symbol *sym;
-  char *arg1;
+  const char *arg1;
   int no_end = 1;
   int dummy_end = 0;
   int dummy_beg = 0;
   int linenum_beg = 0;
-  char *p;
-  struct cleanup *cleanup;
-
-  cleanup = make_cleanup (null_cleanup, NULL);
+  const char *p;
 
   /* Pull in the current default source line if necessary.  */
-  if (arg == 0 || arg[0] == '+' || arg[0] == '-')
+  if (arg == NULL || ((arg[0] == '+' || arg[0] == '-') && arg[1] == '\0'))
     {
       set_default_source_symtab_and_line ();
-      cursal = get_current_source_symtab_and_line ();
+      symtab_and_line cursal = get_current_source_symtab_and_line ();
 
       /* If this is the first "list" since we've set the current
         source line, center the listing around that line.  */
@@ -912,7 +1125,7 @@ list_command (char *arg, int from_tty)
        {
          int first;
 
-         first = max (cursal.line - get_lines_to_list () / 2, 1);
+         first = std::max (cursal.line - get_lines_to_list () / 2, 1);
 
          /* A small special case --- if listing backwards, and we
             should list only one line, list the preceding line,
@@ -922,29 +1135,26 @@ list_command (char *arg, int from_tty)
              && get_lines_to_list () == 1 && first > 1)
            first -= 1;
 
-         print_source_lines (cursal.symtab, first,
-                             first + get_lines_to_list (), 0);
-         return;
+         print_source_lines (cursal.symtab, source_lines_range (first), 0);
        }
-    }
 
-  /* "l" or "l +" lists next ten lines.  */
+      /* "l" or "l +" lists next ten lines.  */
+      else if (arg == NULL || arg[0] == '+')
+       print_source_lines (cursal.symtab,
+                           source_lines_range (cursal.line), 0);
 
-  if (arg == 0 || strcmp (arg, "+") == 0)
-    {
-      print_source_lines (cursal.symtab, cursal.line,
-                         cursal.line + get_lines_to_list (), 0);
-      return;
-    }
+      /* "l -" lists previous ten lines, the ones before the ten just
+        listed.  */
+      else if (arg[0] == '-')
+       {
+         if (get_first_line_listed () == 1)
+           error (_("Already at the start of %s."),
+                  symtab_to_filename_for_display (cursal.symtab));
+         source_lines_range range (get_first_line_listed (),
+                                   source_lines_range::BACKWARD);
+         print_source_lines (cursal.symtab, range, 0);
+       }
 
-  /* "l -" lists previous ten lines, the ones before the ten just
-     listed.  */
-  if (strcmp (arg, "-") == 0)
-    {
-      print_source_lines (cursal.symtab,
-                         max (get_first_line_listed () 
-                              - get_lines_to_list (), 1),
-                         get_first_line_listed (), 0);
       return;
     }
 
@@ -957,34 +1167,26 @@ list_command (char *arg, int from_tty)
   if (!have_full_symbols () && !have_partial_symbols ())
     error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  std::vector<symtab_and_line> sals;
+  symtab_and_line sal, sal_end;
+
   arg1 = arg;
   if (*arg1 == ',')
     dummy_beg = 1;
   else
     {
-      struct event_location *location;
-
-      location = string_to_event_location (&arg1, current_language);
-      make_cleanup_delete_event_location (location);
-      sals = decode_line_1 (location, DECODE_LINE_LIST_MODE, 0, 0);
-
-      filter_sals (&sals);
-      if (!sals.nelts)
+      event_location_up location = string_to_event_location (&arg1,
+                                                            current_language);
+      sals = decode_line_1 (location.get (), DECODE_LINE_LIST_MODE,
+                           NULL, NULL, 0);
+      filter_sals (sals);
+      if (sals.empty ())
        {
          /*  C++  */
-         do_cleanups (cleanup);
-         return;
-       }
-      if (sals.nelts > 1)
-       {
-         ambiguous_line_spec (&sals);
-         xfree (sals.sals);
-         do_cleanups (cleanup);
          return;
        }
 
-      sal = sals.sals[0];
-      xfree (sals.sals);
+      sal = sals[0];
     }
 
   /* Record whether the BEG arg is all digits.  */
@@ -992,11 +1194,23 @@ list_command (char *arg, int from_tty)
   for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
   linenum_beg = (p == arg1);
 
+  /* Save the range of the first argument, in case we need to let the
+     user know it was ambiguous.  */
+  const char *beg = arg;
+  size_t beg_len = arg1 - beg;
+
   while (*arg1 == ' ' || *arg1 == '\t')
     arg1++;
   if (*arg1 == ',')
     {
       no_end = 0;
+      if (sals.size () > 1)
+       {
+         ambiguous_line_spec (sals,
+                              _("Specified first line '%.*s' is ambiguous:\n"),
+                              (int) beg_len, beg);
+         return;
+       }
       arg1++;
       while (*arg1 == ' ' || *arg1 == '\t')
        arg1++;
@@ -1004,32 +1218,31 @@ list_command (char *arg, int from_tty)
        dummy_end = 1;
       else
        {
-         struct event_location *location;
-
-         location = string_to_event_location (&arg1, current_language);
-         make_cleanup_delete_event_location (location);
-         if (dummy_beg)
-           sals_end = decode_line_1 (location,
-                                     DECODE_LINE_LIST_MODE, 0, 0);
-         else
-           sals_end = decode_line_1 (location, DECODE_LINE_LIST_MODE,
-                                     sal.symtab, sal.line);
-
-         filter_sals (&sals_end);
-         if (sals_end.nelts == 0)
+         /* Save the last argument, in case we need to let the user
+            know it was ambiguous.  */
+         const char *end_arg = arg1;
+
+         event_location_up location
+           = string_to_event_location (&arg1, current_language);
+
+         std::vector<symtab_and_line> sals_end
+           = (dummy_beg
+              ? decode_line_1 (location.get (), DECODE_LINE_LIST_MODE,
+                               NULL, NULL, 0)
+              : decode_line_1 (location.get (), DECODE_LINE_LIST_MODE,
+                               NULL, sal.symtab, sal.line));
+
+         filter_sals (sals_end);
+         if (sals_end.empty ())
+           return;
+         if (sals_end.size () > 1)
            {
-             do_cleanups (cleanup);
+             ambiguous_line_spec (sals_end,
+                                  _("Specified last line '%s' is ambiguous:\n"),
+                                  end_arg);
              return;
            }
-         if (sals_end.nelts > 1)
-           {
-             ambiguous_line_spec (&sals_end);
-             xfree (sals_end.sals);
-             do_cleanups (cleanup);
-             return;
-           }
-         sal_end = sals_end.sals[0];
-         xfree (sals_end.sals);
+         sal_end = sals_end[0];
        }
     }
 
@@ -1038,7 +1251,7 @@ list_command (char *arg, int from_tty)
 
   if (!no_end && !dummy_beg && !dummy_end
       && sal.symtab != sal_end.symtab)
-    error (_("Specified start and end are in different files."));
+    error (_("Specified first and last lines are in different files."));
   if (dummy_beg && dummy_end)
     error (_("Two empty args do not say what lines to list."));
 
@@ -1055,12 +1268,12 @@ list_command (char *arg, int from_tty)
        error (_("No source file for address %s."),
               paddress (get_current_arch (), sal.pc));
 
-      gdbarch = get_objfile_arch (SYMTAB_OBJFILE (sal.symtab));
+      gdbarch = SYMTAB_OBJFILE (sal.symtab)->arch ();
       sym = find_pc_function (sal.pc);
       if (sym)
        printf_filtered ("%s is in %s (%s:%d).\n",
                         paddress (gdbarch, sal.pc),
-                        SYMBOL_PRINT_NAME (sym),
+                        sym->print_name (),
                         symtab_to_filename_for_display (sal.symtab), sal.line);
       else
        printf_filtered ("%s is at %s:%d.\n",
@@ -1079,86 +1292,105 @@ list_command (char *arg, int from_tty)
      turn it into the no-arg variant.  */
 
   if (from_tty)
-    *arg = 0;
+    set_repeat_arguments ("");
 
   if (dummy_beg && sal_end.symtab == 0)
     error (_("No default source file yet.  Do \"help list\"."));
   if (dummy_beg)
-    print_source_lines (sal_end.symtab,
-                       max (sal_end.line - (get_lines_to_list () - 1), 1),
-                       sal_end.line + 1, 0);
+    {
+      source_lines_range range (sal_end.line + 1,
+                               source_lines_range::BACKWARD);
+      print_source_lines (sal_end.symtab, range, 0);
+    }
   else if (sal.symtab == 0)
     error (_("No default source file yet.  Do \"help list\"."));
   else if (no_end)
     {
-      int first_line = sal.line - get_lines_to_list () / 2;
-
-      if (first_line < 1) first_line = 1;
-
-      print_source_lines (sal.symtab,
-                         first_line,
-                         first_line + get_lines_to_list (),
-                         0);
+      for (int i = 0; i < sals.size (); i++)
+       {
+         sal = sals[i];
+         int first_line = sal.line - get_lines_to_list () / 2;
+         if (first_line < 1)
+           first_line = 1;
+         if (sals.size () > 1)
+           print_sal_location (sal);
+         print_source_lines (sal.symtab, source_lines_range (first_line), 0);
+       }
     }
+  else if (dummy_end)
+    print_source_lines (sal.symtab, source_lines_range (sal.line), 0);
   else
-    print_source_lines (sal.symtab, sal.line,
-                       (dummy_end
-                        ? sal.line + get_lines_to_list ()
-                        : sal_end.line + 1),
+    print_source_lines (sal.symtab,
+                       source_lines_range (sal.line, (sal_end.line + 1)),
                        0);
-  do_cleanups (cleanup);
 }
 
 /* Subroutine of disassemble_command to simplify it.
    Perform the disassembly.
    NAME is the name of the function if known, or NULL.
    [LOW,HIGH) are the range of addresses to disassemble.
+   BLOCK is the block to disassemble; it needs to be provided
+   when non-contiguous blocks are disassembled; otherwise
+   it can be NULL.
    MIXED is non-zero to print source with the assembler.  */
 
 static void
 print_disassembly (struct gdbarch *gdbarch, const char *name,
-                  CORE_ADDR low, CORE_ADDR high, int flags)
+                  CORE_ADDR low, CORE_ADDR high,
+                  const struct block *block,
+                  gdb_disassembly_flags flags)
 {
 #if defined(TUI)
-  if (!tui_is_window_visible (DISASSEM_WIN))
+  if (tui_is_window_visible (DISASSEM_WIN))
+    tui_show_assembly (gdbarch, low);
+  else
 #endif
     {
       printf_filtered ("Dump of assembler code ");
       if (name != NULL)
-        printf_filtered ("for function %s:\n", name);
-      else
-        printf_filtered ("from %s to %s:\n",
-                        paddress (gdbarch, low), paddress (gdbarch, high));
-
-      /* Dump the specified range.  */
-      gdb_disassembly (gdbarch, current_uiout, 0, flags, -1, low, high);
+       printf_filtered ("for function %s:\n", name);
+      if (block == nullptr || BLOCK_CONTIGUOUS_P (block))
+        {
+         if (name == NULL)
+           printf_filtered ("from %s to %s:\n",
+                            paddress (gdbarch, low), paddress (gdbarch, high));
 
+         /* Dump the specified range.  */
+         gdb_disassembly (gdbarch, current_uiout, flags, -1, low, high);
+       }
+      else
+        {
+         for (int i = 0; i < BLOCK_NRANGES (block); i++)
+           {
+             CORE_ADDR range_low = BLOCK_RANGE_START (block, i);
+             CORE_ADDR range_high = BLOCK_RANGE_END (block, i);
+             printf_filtered (_("Address range %s to %s:\n"),
+                              paddress (gdbarch, range_low),
+                              paddress (gdbarch, range_high));
+             gdb_disassembly (gdbarch, current_uiout, flags, -1,
+                              range_low, range_high);
+           }
+       }
       printf_filtered ("End of assembler dump.\n");
-      gdb_flush (gdb_stdout);
     }
-#if defined(TUI)
-  else
-    {
-      tui_show_assembly (gdbarch, low);
-    }
-#endif
 }
 
 /* Subroutine of disassemble_command to simplify it.
    Print a disassembly of the current function according to FLAGS.  */
 
 static void
-disassemble_current_function (int flags)
+disassemble_current_function (gdb_disassembly_flags flags)
 {
   struct frame_info *frame;
   struct gdbarch *gdbarch;
   CORE_ADDR low, high, pc;
   const char *name;
+  const struct block *block;
 
   frame = get_selected_frame (_("No frame selected."));
   gdbarch = get_frame_arch (frame);
   pc = get_frame_address_in_block (frame);
-  if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+  if (find_pc_partial_function (pc, &name, &low, &high, &block) == 0)
     error (_("No function contains program counter for selected frame."));
 #if defined(TUI)
   /* NOTE: cagney/2003-02-13 The `tui_active' was previously
@@ -1169,7 +1401,7 @@ disassemble_current_function (int flags)
 #endif
   low += gdbarch_deprecated_function_start_offset (gdbarch);
 
-  print_disassembly (gdbarch, name, low, high, flags);
+  print_disassembly (gdbarch, name, low, high, block, flags);
 }
 
 /* Dump a specified section of assembly code.
@@ -1197,14 +1429,15 @@ disassemble_current_function (int flags)
    2) File names and contents for all relevant source files are displayed.  */
 
 static void
-disassemble_command (char *arg, int from_tty)
+disassemble_command (const char *arg, int from_tty)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   CORE_ADDR low, high;
   const char *name;
   CORE_ADDR pc;
-  int flags;
+  gdb_disassembly_flags flags;
   const char *p;
+  const struct block *block = nullptr;
 
   p = arg;
   name = NULL;
@@ -1235,7 +1468,7 @@ disassemble_command (char *arg, int from_tty)
            }
        }
 
-      p = skip_spaces_const (p);
+      p = skip_spaces (p);
     }
 
   if ((flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE))
@@ -1255,7 +1488,7 @@ disassemble_command (char *arg, int from_tty)
   if (p[0] == '\0')
     {
       /* One argument.  */
-      if (find_pc_partial_function (pc, &name, &low, &high) == 0)
+      if (find_pc_partial_function (pc, &name, &low, &high, &block) == 0)
        error (_("No function contains specified address."));
 #if defined(TUI)
       /* NOTE: cagney/2003-02-13 The `tui_active' was previously
@@ -1272,7 +1505,7 @@ disassemble_command (char *arg, int from_tty)
       /* Two arguments.  */
       int incl_flag = 0;
       low = pc;
-      p = skip_spaces_const (p);
+      p = skip_spaces (p);
       if (p[0] == '+')
        {
          ++p;
@@ -1283,31 +1516,26 @@ disassemble_command (char *arg, int from_tty)
        high += low;
     }
 
-  print_disassembly (gdbarch, name, low, high, flags);
+  print_disassembly (gdbarch, name, low, high, block, flags);
 }
 
 static void
-make_command (char *arg, int from_tty)
+make_command (const char *arg, int from_tty)
 {
-  char *p;
-
   if (arg == 0)
-    p = "make";
+    shell_escape ("make", from_tty);
   else
     {
-      p = xmalloc (sizeof ("make ") + strlen (arg));
-      strcpy (p, "make ");
-      strcpy (p + sizeof ("make ") - 1, arg);
-    }
+      std::string cmd = std::string ("make ") + arg;
 
-  shell_escape (p, from_tty);
+      shell_escape (cmd.c_str (), from_tty);
+    }
 }
 
 static void
-show_user (char *args, int from_tty)
+show_user (const char *args, int from_tty)
 {
   struct cmd_list_element *c;
-  extern struct cmd_list_element *cmdlist;
 
   if (args)
     {
@@ -1331,31 +1559,18 @@ show_user (char *args, int from_tty)
 /* Search through names of commands and documentations for a certain
    regular expression.  */
 
-static void 
-apropos_command (char *searchstr, int from_tty)
+static void
+apropos_command (const char *arg, int from_tty)
 {
-  regex_t pattern;
-  int code;
+  bool verbose = arg && check_for_argument (&arg, "-v", 2);
 
-  if (searchstr == NULL)
+  if (arg == NULL || *arg == '\0')
     error (_("REGEXP string is empty"));
 
-  code = regcomp (&pattern, searchstr, REG_ICASE);
-  if (code == 0)
-    {
-      struct cleanup *cleanups;
+  compiled_regex pattern (arg, REG_ICASE,
+                         _("Error in regular expression"));
 
-      cleanups = make_regfree_cleanup (&pattern);
-      apropos_cmd (gdb_stdout, cmdlist, &pattern, "");
-      do_cleanups (cleanups);
-    }
-  else
-    {
-      char *err = get_regcomp_error (code, &pattern);
-
-      make_cleanup (xfree, err);
-      error (_("Error in regular expression: %s"), err);
-    }
+  apropos_cmd (gdb_stdout, cmdlist, verbose, pattern, "");
 }
 
 /* Subroutine of alias_command to simplify it.
@@ -1365,11 +1580,11 @@ apropos_command (char *searchstr, int from_tty)
    This does not take care of quoting elements in case they contain spaces
    on purpose.  */
 
-static dyn_string_t
-argv_to_dyn_string (char **argv, int n)
+static std::string
+argv_to_string (char **argv, int n)
 {
   int i;
-  dyn_string_t result = dyn_string_new (10);
+  std::string result;
 
   gdb_assert (argv != NULL);
   gdb_assert (n >= 0 && n <= countargv (argv));
@@ -1377,17 +1592,17 @@ argv_to_dyn_string (char **argv, int n)
   for (i = 0; i < n; ++i)
     {
       if (i > 0)
-       dyn_string_append_char (result, ' ');
-      dyn_string_append_cstr (result, argv[i]);
+       result += " ";
+      result += argv[i];
     }
 
   return result;
 }
 
 /* Subroutine of alias_command to simplify it.
-   Return TRUE if COMMAND exists, unambiguously.  Otherwise FALSE.  */
+   Return true if COMMAND exists, unambiguously.  Otherwise false.  */
 
-static int
+static bool
 valid_command_p (const char *command)
 {
   struct cmd_list_element *c;
@@ -1395,7 +1610,7 @@ valid_command_p (const char *command)
   c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
 
   if (c == NULL || c == (struct cmd_list_element *) -1)
-    return FALSE;
+    return false;
 
   /* This is the slightly tricky part.
      lookup_cmd_1 will return a pointer to the last part of COMMAND
@@ -1405,39 +1620,42 @@ valid_command_p (const char *command)
   return *command == '\0';
 }
 
+/* Called when "alias" was incorrectly used.  */
+
+static void
+alias_usage_error (void)
+{
+  error (_("Usage: alias [-a] [--] ALIAS = COMMAND"));
+}
+
 /* Make an alias of an existing command.  */
 
 static void
-alias_command (char *args, int from_tty)
+alias_command (const char *args, int from_tty)
 {
   int i, alias_argc, command_argc;
   int abbrev_flag = 0;
-  char *args2, *equals, *alias, *command;
-  char **alias_argv, **command_argv;
-  dyn_string_t alias_dyn_string, command_dyn_string;
-  struct cleanup *cleanup;
-  static const char usage[] = N_("Usage: alias [-a] [--] ALIAS = COMMAND");
+  const char *equals;
+  const char *alias, *command;
 
   if (args == NULL || strchr (args, '=') == NULL)
-    error (_(usage));
-
-  args2 = xstrdup (args);
-  cleanup = make_cleanup (xfree, args2);
-  equals = strchr (args2, '=');
-  *equals = '\0';
-  alias_argv = gdb_buildargv (args2);
-  make_cleanup_freeargv (alias_argv);
-  command_argv = gdb_buildargv (equals + 1);
-  make_cleanup_freeargv (command_argv);
-
-  for (i = 0; alias_argv[i] != NULL; )
+    alias_usage_error ();
+
+  equals = strchr (args, '=');
+  std::string args2 (args, equals - args);
+
+  gdb_argv built_alias_argv (args2.c_str ());
+  gdb_argv command_argv (equals + 1);
+
+  char **alias_argv = built_alias_argv.get ();
+  while (alias_argv[0] != NULL)
     {
-      if (strcmp (alias_argv[i], "-a") == 0)
+      if (strcmp (alias_argv[0], "-a") == 0)
        {
          ++alias_argv;
          abbrev_flag = 1;
        }
-      else if (strcmp (alias_argv[i], "--") == 0)
+      else if (strcmp (alias_argv[0], "--") == 0)
        {
          ++alias_argv;
          break;
@@ -1448,7 +1666,7 @@ alias_command (char *args, int from_tty)
 
   if (alias_argv[0] == NULL || command_argv[0] == NULL
       || *alias_argv[0] == '\0' || *command_argv[0] == '\0')
-    error (_(usage));
+    alias_usage_error ();
 
   for (i = 0; alias_argv[i] != NULL; ++i)
     {
@@ -1462,21 +1680,20 @@ alias_command (char *args, int from_tty)
     }
 
   alias_argc = countargv (alias_argv);
-  command_argc = countargv (command_argv);
+  command_argc = command_argv.count ();
 
   /* COMMAND must exist.
      Reconstruct the command to remove any extraneous spaces,
      for better error messages.  */
-  command_dyn_string = argv_to_dyn_string (command_argv, command_argc);
-  make_cleanup_dyn_string_delete (command_dyn_string);
-  command = dyn_string_buf (command_dyn_string);
+  std::string command_string (argv_to_string (command_argv.get (),
+                                             command_argc));
+  command = command_string.c_str ();
   if (! valid_command_p (command))
     error (_("Invalid command to alias to: %s"), command);
 
   /* ALIAS must not exist.  */
-  alias_dyn_string = argv_to_dyn_string (alias_argv, alias_argc);
-  make_cleanup_dyn_string_delete (alias_dyn_string);
-  alias = dyn_string_buf (alias_dyn_string);
+  std::string alias_string (argv_to_string (alias_argv, alias_argc));
+  alias = alias_string.c_str ();
   if (valid_command_p (alias))
     error (_("Alias already exists: %s"), alias);
 
@@ -1484,8 +1701,8 @@ alias_command (char *args, int from_tty)
      Example: alias spe = set print elements
 
      Otherwise ALIAS and COMMAND must have the same number of words,
-     and every word except the last must match; and the last word of
-     ALIAS is made an alias of the last word of COMMAND.
+     and every word except the last must identify the same prefix command;
+     and the last word of ALIAS is made an alias of the last word of COMMAND.
      Example: alias set print elms = set pr elem
      Note that unambiguous abbreviations are allowed.  */
 
@@ -1497,7 +1714,6 @@ alias_command (char *args, int from_tty)
     }
   else
     {
-      dyn_string_t alias_prefix_dyn_string, command_prefix_dyn_string;
       const char *alias_prefix, *command_prefix;
       struct cmd_list_element *c_alias, *c_command;
 
@@ -1505,15 +1721,14 @@ alias_command (char *args, int from_tty)
        error (_("Mismatched command length between ALIAS and COMMAND."));
 
       /* Create copies of ALIAS and COMMAND without the last word,
-        and use that to verify the leading elements match.  */
-      alias_prefix_dyn_string =
-       argv_to_dyn_string (alias_argv, alias_argc - 1);
-      make_cleanup_dyn_string_delete (alias_prefix_dyn_string);
-      command_prefix_dyn_string =
-       argv_to_dyn_string (alias_argv, command_argc - 1);
-      make_cleanup_dyn_string_delete (command_prefix_dyn_string);
-      alias_prefix = dyn_string_buf (alias_prefix_dyn_string);
-      command_prefix = dyn_string_buf (command_prefix_dyn_string);
+        and use that to verify the leading elements give the same
+        prefix command.  */
+      std::string alias_prefix_string (argv_to_string (alias_argv,
+                                                      alias_argc - 1));
+      std::string command_prefix_string (argv_to_string (command_argv.get (),
+                                                        command_argc - 1));
+      alias_prefix = alias_prefix_string.c_str ();
+      command_prefix = command_prefix_string.c_str ();
 
       c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
       /* We've already tried to look up COMMAND.  */
@@ -1529,35 +1744,53 @@ alias_command (char *args, int from_tty)
                     command_argv[command_argc - 1],
                     class_alias, abbrev_flag, c_command->prefixlist);
     }
-
-  do_cleanups (cleanup);
 }
 \f
+/* Print the file / line number / symbol name of the location
+   specified by SAL.  */
+
+static void
+print_sal_location (const symtab_and_line &sal)
+{
+  scoped_restore_current_program_space restore_pspace;
+  set_current_program_space (sal.pspace);
+
+  const char *sym_name = NULL;
+  if (sal.symbol != NULL)
+    sym_name = sal.symbol->print_name ();
+  printf_filtered (_("file: \"%s\", line number: %d, symbol: \"%s\"\n"),
+                  symtab_to_filename_for_display (sal.symtab),
+                  sal.line, sym_name != NULL ? sym_name : "???");
+}
+
 /* Print a list of files and line numbers which a user may choose from
    in order to list a function which was specified ambiguously (as
-   with `list classname::overloadedfuncname', for example).  The
-   vector in SALS provides the filenames and line numbers.  */
+   with `list classname::overloadedfuncname', for example).  The SALS
+   array provides the filenames and line numbers.  FORMAT is a
+   printf-style format string used to tell the user what was
+   ambiguous.  */
 
 static void
-ambiguous_line_spec (struct symtabs_and_lines *sals)
+ambiguous_line_spec (gdb::array_view<const symtab_and_line> sals,
+                    const char *format, ...)
 {
-  int i;
+  va_list ap;
+  va_start (ap, format);
+  vprintf_filtered (format, ap);
+  va_end (ap);
 
-  for (i = 0; i < sals->nelts; ++i)
-    printf_filtered (_("file: \"%s\", line number: %d\n"),
-                    symtab_to_filename_for_display (sals->sals[i].symtab),
-                    sals->sals[i].line);
+  for (const auto &sal : sals)
+    print_sal_location (sal);
 }
 
-/* Sort function for filter_sals.  */
+/* Comparison function for filter_sals.  Returns a qsort-style
+   result.  */
 
 static int
-compare_symtabs (const void *a, const void *b)
+cmp_symtabs (const symtab_and_line &sala, const symtab_and_line &salb)
 {
-  const struct symtab_and_line *sala = a;
-  const struct symtab_and_line *salb = b;
-  const char *dira = SYMTAB_DIRNAME (sala->symtab);
-  const char *dirb = SYMTAB_DIRNAME (salb->symtab);
+  const char *dira = SYMTAB_DIRNAME (sala.symtab);
+  const char *dirb = SYMTAB_DIRNAME (salb.symtab);
   int r;
 
   if (dira == NULL)
@@ -1577,72 +1810,37 @@ compare_symtabs (const void *a, const void *b)
        return r;
     }
 
-  r = filename_cmp (sala->symtab->filename, salb->symtab->filename);
+  r = filename_cmp (sala.symtab->filename, salb.symtab->filename);
   if (r)
     return r;
 
-  if (sala->line < salb->line)
+  if (sala.line < salb.line)
     return -1;
-  return sala->line == salb->line ? 0 : 1;
+  return sala.line == salb.line ? 0 : 1;
 }
 
 /* Remove any SALs that do not match the current program space, or
    which appear to be "file:line" duplicates.  */
 
 static void
-filter_sals (struct symtabs_and_lines *sals)
+filter_sals (std::vector<symtab_and_line> &sals)
 {
-  int i, out, prev;
-
-  out = 0;
-  for (i = 0; i < sals->nelts; ++i)
-    {
-      if (sals->sals[i].pspace == current_program_space
-         && sals->sals[i].symtab != NULL)
-       {
-         sals->sals[out] = sals->sals[i];
-         ++out;
-       }
-    }
-  sals->nelts = out;
-
-  qsort (sals->sals, sals->nelts, sizeof (struct symtab_and_line),
-        compare_symtabs);
-
-  out = 1;
-  prev = 0;
-  for (i = 1; i < sals->nelts; ++i)
-    {
-      if (compare_symtabs (&sals->sals[prev], &sals->sals[i]))
-       {
-         /* Symtabs differ.  */
-         sals->sals[out] = sals->sals[i];
-         prev = out;
-         ++out;
-       }
-    }
-
-  if (sals->nelts == 0)
-    {
-      xfree (sals->sals);
-      sals->sals = NULL;
-    }
-  else
-    sals->nelts = out;
-}
-
-static void
-set_debug (char *arg, int from_tty)
-{
-  printf_unfiltered (_("\"set debug\" must be followed by "
-                      "the name of a debug subcommand.\n"));
-  help_list (setdebuglist, "set debug ", all_commands, gdb_stdout);
-}
-
-static void
-show_debug (char *args, int from_tty)
-{
-  cmd_show_list (showdebuglist, from_tty, "");
+  /* Remove SALs that do not match.  */
+  auto from = std::remove_if (sals.begin (), sals.end (),
+                             [&] (const symtab_and_line &sal)
+    { return (sal.pspace != current_program_space || sal.symtab == NULL); });
+
+  /* Remove dups.  */
+  std::sort (sals.begin (), from,
+            [] (const symtab_and_line &sala, const symtab_and_line &salb)
+   { return cmp_symtabs (sala, salb) < 0; });
+
+  from = std::unique (sals.begin (), from,
+                     [&] (const symtab_and_line &sala,
+                          const symtab_and_line &salb)
+    { return cmp_symtabs (sala, salb) == 0; });
+
+  sals.erase (from, sals.end ());
 }
 
 void
@@ -1698,40 +1896,231 @@ show_max_user_call_depth (struct ui_file *file, int from_tty,
                    value);
 }
 
-\f
+/* Returns the cmd_list_element in SHOWLIST corresponding to the first
+   argument of ARGV, which must contain one single value.
+   Throws an error if no value provided, or value not correct.
+   FNNAME is used in the error message.  */
+
+static cmd_list_element *
+setting_cmd (const char *fnname, struct cmd_list_element *showlist,
+            int argc, struct value **argv)
+{
+  if (argc == 0)
+    error (_("You must provide an argument to %s"), fnname);
+  if (argc != 1)
+    error (_("You can only provide one argument to %s"), fnname);
+
+  struct type *type0 = check_typedef (value_type (argv[0]));
+
+  if (type0->code () != TYPE_CODE_ARRAY
+      && type0->code () != TYPE_CODE_STRING)
+    error (_("First argument of %s must be a string."), fnname);
+
+  const char *a0 = (const char *) value_contents (argv[0]);
+  cmd_list_element *cmd = lookup_cmd (&a0, showlist, "", -1, 0);
+
+  if (cmd == nullptr || cmd_type (cmd) != show_cmd)
+    error (_("First argument of %s must be a "
+            "valid setting of the 'show' command."), fnname);
+
+  return cmd;
+}
+
+/* Builds a value from the show CMD.  */
+
+static struct value *
+value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch)
+{
+  switch (cmd->var_type)
+    {
+    case var_integer:
+      if (*(int *) cmd->var == INT_MAX)
+       return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                  0);
+      else
+       return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                  *(int *) cmd->var);
+    case var_zinteger:
+      return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                *(int *) cmd->var);
+    case var_boolean:
+      return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                *(bool *) cmd->var ? 1 : 0);
+    case var_zuinteger_unlimited:
+      return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                *(int *) cmd->var);
+    case var_auto_boolean:
+      {
+       int val;
+
+       switch (*(enum auto_boolean*) cmd->var)
+         {
+         case AUTO_BOOLEAN_TRUE:
+           val = 1;
+           break;
+         case AUTO_BOOLEAN_FALSE:
+           val = 0;
+           break;
+         case AUTO_BOOLEAN_AUTO:
+           val = -1;
+           break;
+         default:
+           gdb_assert_not_reached ("invalid var_auto_boolean");
+         }
+       return value_from_longest (builtin_type (gdbarch)->builtin_int,
+                                  val);
+      }
+    case var_uinteger:
+      if (*(unsigned int *) cmd->var == UINT_MAX)
+       return value_from_ulongest
+         (builtin_type (gdbarch)->builtin_unsigned_int, 0);
+      else
+       return value_from_ulongest
+         (builtin_type (gdbarch)->builtin_unsigned_int,
+          *(unsigned int *) cmd->var);
+    case var_zuinteger:
+      return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
+                                 *(unsigned int *) cmd->var);
+    case var_string:
+    case var_string_noescape:
+    case var_optional_filename:
+    case var_filename:
+    case var_enum:
+      if (*(char **) cmd->var)
+       return value_cstring (*(char **) cmd->var, strlen (*(char **) cmd->var),
+                             builtin_type (gdbarch)->builtin_char);
+      else
+       return value_cstring ("", 1,
+                             builtin_type (gdbarch)->builtin_char);
+    default:
+      gdb_assert_not_reached ("bad var_type");
+    }
+}
+
+/* Implementation of the convenience function $_gdb_setting.  */
+
+static struct value *
+gdb_setting_internal_fn (struct gdbarch *gdbarch,
+                        const struct language_defn *language,
+                        void *cookie, int argc, struct value **argv)
+{
+  return value_from_setting (setting_cmd ("$_gdb_setting", showlist,
+                                         argc, argv),
+                            gdbarch);
+}
 
-initialize_file_ftype _initialize_cli_cmds;
+/* Implementation of the convenience function $_gdb_maint_setting.  */
 
+static struct value *
+gdb_maint_setting_internal_fn (struct gdbarch *gdbarch,
+                              const struct language_defn *language,
+                              void *cookie, int argc, struct value **argv)
+{
+  return value_from_setting (setting_cmd ("$_gdb_maint_setting",
+                                         maintenance_show_cmdlist,
+                                         argc, argv),
+                            gdbarch);
+}
+
+/* Builds a string value from the show CMD.  */
+
+static struct value *
+str_value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch)
+{
+  switch (cmd->var_type)
+    {
+    case var_integer:
+    case var_zinteger:
+    case var_boolean:
+    case var_zuinteger_unlimited:
+    case var_auto_boolean:
+    case var_uinteger:
+    case var_zuinteger:
+      {
+       std::string cmd_val = get_setshow_command_value_string (cmd);
+
+       return value_cstring (cmd_val.c_str (), cmd_val.size (),
+                             builtin_type (gdbarch)->builtin_char);
+      }
+
+    case var_string:
+    case var_string_noescape:
+    case var_optional_filename:
+    case var_filename:
+    case var_enum:
+      /* For these cases, we do not use get_setshow_command_value_string,
+        as this function handle some characters specially, e.g. by
+        escaping quotes.  So, we directly use the cmd->var string value,
+        similarly to the value_from_setting code for these cases.  */
+      if (*(char **) cmd->var)
+       return value_cstring (*(char **) cmd->var, strlen (*(char **) cmd->var),
+                             builtin_type (gdbarch)->builtin_char);
+      else
+       return value_cstring ("", 1,
+                             builtin_type (gdbarch)->builtin_char);
+
+    default:
+      gdb_assert_not_reached ("bad var_type");
+    }
+}
+
+/* Implementation of the convenience function $_gdb_setting_str.  */
+
+static struct value *
+gdb_setting_str_internal_fn (struct gdbarch *gdbarch,
+                            const struct language_defn *language,
+                            void *cookie, int argc, struct value **argv)
+{
+  return str_value_from_setting (setting_cmd ("$_gdb_setting_str",
+                                             showlist, argc, argv),
+                                gdbarch);
+}
+
+
+/* Implementation of the convenience function $_gdb_maint_setting_str.  */
+
+static struct value *
+gdb_maint_setting_str_internal_fn (struct gdbarch *gdbarch,
+                                  const struct language_defn *language,
+                                  void *cookie, int argc, struct value **argv)
+{
+  return str_value_from_setting (setting_cmd ("$_gdb_maint_setting_str",
+                                             maintenance_show_cmdlist,
+                                             argc, argv),
+                                gdbarch);
+}
+
+void _initialize_cli_cmds ();
 void
-_initialize_cli_cmds (void)
+_initialize_cli_cmds ()
 {
   struct cmd_list_element *c;
 
   /* Define the classes of commands.
      They will appear in the help list in alphabetical order.  */
 
-  add_cmd ("internals", class_maintenance, NULL, _("\
+  add_cmd ("internals", class_maintenance, _("\
 Maintenance commands.\n\
 Some gdb commands are provided just for use by gdb maintainers.\n\
 These commands are subject to frequent change, and may not be as\n\
 well documented as user commands."),
           &cmdlist);
-  add_cmd ("obscure", class_obscure, NULL, _("Obscure features."), &cmdlist);
-  add_cmd ("aliases", class_alias, NULL,
+  add_cmd ("obscure", class_obscure, _("Obscure features."), &cmdlist);
+  add_cmd ("aliases", class_alias,
           _("Aliases of other commands."), &cmdlist);
-  add_cmd ("user-defined", class_user, NULL, _("\
+  add_cmd ("user-defined", class_user, _("\
 User-defined commands.\n\
 The commands in this class are those defined by the user.\n\
 Use the \"define\" command to define a command."), &cmdlist);
-  add_cmd ("support", class_support, NULL, _("Support facilities."), &cmdlist);
+  add_cmd ("support", class_support, _("Support facilities."), &cmdlist);
   if (!dbx_commands)
-    add_cmd ("status", class_info, NULL, _("Status inquiries."), &cmdlist);
-  add_cmd ("files", class_files, NULL, _("Specifying and examining files."),
+    add_cmd ("status", class_info, _("Status inquiries."), &cmdlist);
+  add_cmd ("files", class_files, _("Specifying and examining files."),
           &cmdlist);
-  add_cmd ("breakpoints", class_breakpoint, NULL,
+  add_cmd ("breakpoints", class_breakpoint,
           _("Making program stop at certain points."), &cmdlist);
-  add_cmd ("data", class_vars, NULL, _("Examining data."), &cmdlist);
-  add_cmd ("stack", class_stack, NULL, _("\
+  add_cmd ("data", class_vars, _("Examining data."), &cmdlist);
+  add_cmd ("stack", class_stack, _("\
 Examining the stack.\n\
 The stack is made up of stack frames.  Gdb assigns numbers to stack frames\n\
 counting from zero for the innermost (currently executing) frame.\n\n\
@@ -1740,17 +2129,20 @@ Variable lookups are done with respect to the selected frame.\n\
 When the program being debugged stops, gdb selects the innermost frame.\n\
 The commands below can be used to select other frames by number or address."),
           &cmdlist);
-  add_cmd ("running", class_run, NULL, _("Running the program."), &cmdlist);
+  add_cmd ("running", class_run, _("Running the program."), &cmdlist);
 
   /* Define general commands.  */
 
   add_com ("pwd", class_files, pwd_command, _("\
-Print working directory.  This is used for your program as well."));
+Print working directory.\n\
+This is used for your program as well."));
 
   c = add_cmd ("cd", class_files, cd_command, _("\
-Set working directory to DIR for debugger and program being debugged.\n\
-The change does not take effect for the program being debugged\n\
-until the next time it is started."), &cmdlist);
+Set working directory to DIR for debugger.\n\
+The debugger's current working directory specifies where scripts and other\n\
+files that can be loaded by GDB are located.\n\
+In order to change the inferior's current working directory, the recommended\n\
+way is to use the \"set cwd\" command."), &cmdlist);
   set_cmd_completer (c, filename_completer);
 
   add_com ("echo", class_support, echo_command, _("\
@@ -1793,12 +2185,12 @@ Show verbosity."), NULL,
                           show_info_verbose,
                           &setlist, &showlist);
 
-  add_prefix_cmd ("history", class_support, set_history,
-                 _("Generic command for setting command history parameters."),
-                 &sethistlist, "set history ", 0, &setlist);
-  add_prefix_cmd ("history", class_support, show_history,
-                 _("Generic command for showing command history parameters."),
-                 &showhistlist, "show history ", 0, &showlist);
+  add_basic_prefix_cmd ("history", class_support, _("\
+Generic command for setting command history parameters."),
+                       &sethistlist, "set history ", 0, &setlist);
+  add_show_prefix_cmd ("history", class_support, _("\
+Generic command for showing command history parameters."),
+                      &showhistlist, "show history ", 0, &showlist);
 
   add_setshow_boolean_cmd ("expansion", no_class, &history_expansion_p, _("\
 Set history expansion on command input."), _("\
@@ -1817,11 +2209,67 @@ Generic command for showing things about the program being debugged."),
   add_com ("complete", class_obscure, complete_command,
           _("List the completions for the rest of the line as a command."));
 
-  add_prefix_cmd ("show", class_info, show_command, _("\
+  add_show_prefix_cmd ("show", class_info, _("\
 Generic command for showing things about the debugger."),
-                 &showlist, "show ", 0, &cmdlist);
+                      &showlist, "show ", 0, &cmdlist);
   /* Another way to get at the same thing.  */
-  add_info ("set", show_command, _("Show all GDB settings."));
+  add_show_prefix_cmd ("set", class_info, _("Show all GDB settings."),
+                      &showlist, "info set ", 0, &infolist);
+
+  c = add_com ("with", class_vars, with_command, _("\
+Temporarily set SETTING to VALUE, run COMMAND, and restore SETTING.\n\
+Usage: with SETTING [VALUE] [-- COMMAND]\n\
+Usage: w SETTING [VALUE] [-- COMMAND]\n\
+With no COMMAND, repeats the last executed command.\n\
+\n\
+SETTING is any setting you can change with the \"set\" subcommands.\n\
+E.g.:\n\
+  with language pascal -- print obj\n\
+  with print elements unlimited -- print obj\n\
+\n\
+You can change multiple settings using nested with, and use\n\
+abbreviations for commands and/or values.  E.g.:\n\
+  w la p -- w p el u -- p obj"));
+  set_cmd_completer_handle_brkchars (c, with_command_completer);
+  add_com_alias ("w", "with", class_vars, 1);
+
+  add_internal_function ("_gdb_setting_str", _("\
+$_gdb_setting_str - returns the value of a GDB setting as a string.\n\
+Usage: $_gdb_setting_str (setting)\n\
+\n\
+auto-boolean values are \"off\", \"on\", \"auto\".\n\
+boolean values are \"off\", \"on\".\n\
+Some integer settings accept an unlimited value, returned\n\
+as \"unlimited\"."),
+                        gdb_setting_str_internal_fn, NULL);
+
+  add_internal_function ("_gdb_setting", _("\
+$_gdb_setting - returns the value of a GDB setting.\n\
+Usage: $_gdb_setting (setting)\n\
+auto-boolean values are \"off\", \"on\", \"auto\".\n\
+boolean values are \"off\", \"on\".\n\
+Some integer settings accept an unlimited value, returned\n\
+as 0 or -1 depending on the setting."),
+                        gdb_setting_internal_fn, NULL);
+
+  add_internal_function ("_gdb_maint_setting_str", _("\
+$_gdb_maint_setting_str - returns the value of a GDB maintenance setting as a string.\n\
+Usage: $_gdb_maint_setting_str (setting)\n\
+\n\
+auto-boolean values are \"off\", \"on\", \"auto\".\n\
+boolean values are \"off\", \"on\".\n\
+Some integer settings accept an unlimited value, returned\n\
+as \"unlimited\"."),
+                        gdb_maint_setting_str_internal_fn, NULL);
+
+  add_internal_function ("_gdb_maint_setting", _("\
+$_gdb_maint_setting - returns the value of a GDB maintenance setting.\n\
+Usage: $_gdb_maint_setting (setting)\n\
+auto-boolean values are \"off\", \"on\", \"auto\".\n\
+boolean values are \"off\", \"on\".\n\
+Some integer settings accept an unlimited value, returned\n\
+as 0 or -1 depending on the setting."),
+                        gdb_maint_setting_internal_fn, NULL);
 
   add_cmd ("commands", no_set_class, show_commands, _("\
 Show the history of commands you typed.\n\
@@ -1854,19 +2302,21 @@ from the target."),
                                       show_remote_timeout,
                                       &setlist, &showlist);
 
-  add_prefix_cmd ("debug", no_class, set_debug,
-                 _("Generic command for setting gdb debugging flags"),
-                 &setdebuglist, "set debug ", 0, &setlist);
+  add_basic_prefix_cmd ("debug", no_class,
+                       _("Generic command for setting gdb debugging flags."),
+                       &setdebuglist, "set debug ", 0, &setlist);
 
-  add_prefix_cmd ("debug", no_class, show_debug,
-                 _("Generic command for showing gdb debugging flags"),
-                 &showdebuglist, "show debug ", 0, &showlist);
+  add_show_prefix_cmd ("debug", no_class,
+                      _("Generic command for showing gdb debugging flags."),
+                      &showdebuglist, "show debug ", 0, &showlist);
 
-  c = add_com ("shell", class_support, shell_escape, _("\
+  c = add_com ("shell", class_support, shell_command, _("\
 Execute the rest of the line as a shell command.\n\
 With no arguments, run an inferior shell."));
   set_cmd_completer (c, filename_completer);
 
+  add_com_alias ("!", "shell", class_support, 0);
+
   c = add_com ("edit", class_files, edit_command, _("\
 Edit specified file or function.\n\
 With no argument, edits file containing most recent line listed.\n\
@@ -1879,6 +2329,24 @@ Uses EDITOR environment variable contents as editor (or ex as default)."));
 
   c->completer = location_completer;
 
+  c = add_com ("pipe", class_support, pipe_command, _("\
+Send the output of a gdb command to a shell command.\n\
+Usage: | [COMMAND] | SHELL_COMMAND\n\
+Usage: | -d DELIM COMMAND DELIM SHELL_COMMAND\n\
+Usage: pipe [COMMAND] | SHELL_COMMAND\n\
+Usage: pipe -d DELIM COMMAND DELIM SHELL_COMMAND\n\
+\n\
+Executes COMMAND and sends its output to SHELL_COMMAND.\n\
+\n\
+The -d option indicates to use the string DELIM to separate COMMAND\n\
+from SHELL_COMMAND, in alternative to |.  This is useful in\n\
+case COMMAND contains a | character.\n\
+\n\
+With no COMMAND, repeat the last executed command\n\
+and send its output to SHELL_COMMAND."));
+  set_cmd_completer_handle_brkchars (c, pipe_command_completer);
+  add_com_alias ("|", "pipe", class_support, 0);
+
   add_com ("list", class_files, list_command, _("\
 List specified function or line.\n\
 With no argument, lists ten more lines after or around previous listing.\n\
@@ -1891,8 +2359,12 @@ Lines can be specified in these ways:\n\
   FUNCTION, to list around beginning of that function,\n\
   FILE:FUNCTION, to distinguish among like-named static functions.\n\
   *ADDRESS, to list around the line containing that address.\n\
-With two args if one is empty it stands for ten lines away from \
-the other arg."));
+With two args, if one is empty, it stands for ten lines away from\n\
+the other arg.\n\
+\n\
+By default, when a single location is given, display ten lines.\n\
+This can be changed using \"set listsize\", and the current value\n\
+can be shown using \"show listsize\"."));
 
   add_com_alias ("l", "list", class_files, 1);
 
@@ -1927,8 +2399,6 @@ So, for example, if you want to disassemble function bar in file foo.c\n\
 you must type \"disassemble 'foo.c'::bar\" and not \"disassemble foo.c:bar\"."));
   set_cmd_completer (c, location_completer);
 
-  add_com_alias ("!", "shell", class_support, 0);
-
   c = add_com ("make", class_support, make_command, _("\
 Run the ``make'' program using the rest of the line as arguments."));
   set_cmd_completer (c, filename_completer);
@@ -1936,8 +2406,11 @@ Run the ``make'' program using the rest of the line as arguments."));
 Show definitions of non-python/scheme user defined commands.\n\
 Argument is the name of the user defined command.\n\
 With no argument, show definitions of all user defined commands."), &showlist);
-  add_com ("apropos", class_support, apropos_command,
-          _("Search for commands matching a REGEXP"));
+  add_com ("apropos", class_support, apropos_command, _("\
+Search for commands matching a REGEXP.\n\
+Usage: apropos [-v] REGEXP\n\
+Flag -v indicates to produce a verbose output, showing full documentation\n\
+of the matching commands."));
 
   add_setshow_uinteger_cmd ("max-user-call-depth", no_class,
                           &max_user_call_depth, _("\
@@ -1968,15 +2441,8 @@ Make \"spe\" an alias of \"set print elements\":\n\
   alias spe = set print elements\n\
 Make \"elms\" an alias of \"elements\" in the \"set print\" command:\n\
   alias -a set print elms = set print elements"));
-}
-
-void
-init_cli_cmds (void)
-{
-  struct cmd_list_element *c;
-  char *source_help_text;
 
-  source_help_text = xstrprintf (_("\
+  const char *source_help_text = xstrprintf (_("\
 Read commands from a file named FILE.\n\
 \n\
 Usage: source [-s] [-v] FILE\n\
@@ -1985,7 +2451,7 @@ Usage: source [-s] [-v] FILE\n\
 -v: each command in FILE is echoed as it is executed.\n\
 \n\
 Note that the file \"%s\" is read automatically in this way\n\
-when GDB is started."), gdbinit);
+when GDB is started."), GDBINIT);
   c = add_cmd ("source", class_support, source_command,
               source_help_text, &cmdlist);
   set_cmd_completer (c, filename_completer);
This page took 0.050758 seconds and 4 git commands to generate.