[RFA 0/3] Allow the user to define default leading args for commands and aliases

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFA 0/3] Allow the user to define default leading args for commands and aliases

Philippe Waroquiers
Allow the user to define default leading args for commands and aliases.

This patch series implements, tests and documents the following commands:

  set leading-args COMMAND [= LEADING-ARGS...]
  show leading-args [COMMAND]
  set enable-leading-args [on|off]
  show enable-leading-args


It also changes the alias command to be:
  alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]


Using the above leading-args commands and arguments, you can
define default arguments for commands or define powerful aliases.

For example:

  alias bt_ALL = backtrace = -entry-values both -frame-arg all -past-main -past-entry -full

defines the alias bt_ALL that will give as much information as possible
in a backtrace.

Leading args can usefully be combined with the (soon to be pushed I hope)
'with' command, such as:

Make "wLapPeu" an alias of 2 nested "with":
  alias wLapPeu = with = language pascal -- with print elements unlimited --

or have an alias pp10 to pretty print an expression with a maximum of
10 elements:

  alias pp10 = with = print pretty -- with print elem 10 -- print


This patch series also adds a completer for 'alias'.


Note 1: a preliminary version of this idea (using a command called
'add-args' was discussed in
https://sourceware.org/ml/gdb-patches/2019-06/msg00395.html
where Tom suggested to make it more GDB like, using 'set' command.

Note 2: I have made the '=' character mandatory in the 'set leading-args'
command to be sure to unambiguously separate the COMMAND from the
specified leading args.

Also, an '=' character must be specified in the alias command before
the LEADING-ARGS for consistency with set leading-args.
This also ensures that the user cannot type a wrong command name
that would be interpreted as leading args and/or cause 'mismatch'
of length between ALIAS and COMMAND
(see https://sourceware.org/ml/gdb-patches/2019-06/msg00459.html
[RFA] Fix alias command not detecting non matching prefix & sometimes asserting.).


Reply | Threaded
Open this post in threaded view
|

[RFA 1/3] leading-args: allow to define default command/alias arguments

Philippe Waroquiers
Currently, a user can define an alias, but cannot have default
arguments for this alias.

This patch provides the following:

* A new command 'set leading-args' that can define default leading args
  to preprend to the command or alias arguments before executing it.
  Note that leading args can be used for an alias and can nicely
  combine nested "with" (see below the changes for the alias command).

      (gdb) help set leading-args
      Set or clear leading args automatically preprended to a command or alias.
      Usage: set leading-args COMMAND [= LEADING-ARGS...]
      Set or clear the leading arguments automatically prepended
      to the arguments the user provides when COMMAND is run.
      Note that COMMAND can be an alias.  Commands and their aliases
      do not share their leading arguments, so you can specify different
      leading arguments for a command and for each of its aliases.
      Without the [= LEADING-ARGS...], clears COMMAND leading arguments.

  Note that 'set leading-args' command has a completer to help typing
  COMMAND and its leading-args.

* A new command 'show leading-args'.

        (gdb) help show leading-args
        Show the leading args of a command, or of all commands.
        Usage: show leading-args [COMMAND]
        Show the leading args of COMMAND.  Without COMMAND, show the leading args
        of all commands.

* The 'alias' command is modified so as to directly accepts leading-args.
  Note that the help alias assumes this patch will be pushed after the
  'with command' is pushed.

        (gdb) help alias
        Define a new command that is an alias of an existing command.
        Usage: alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]
        ALIAS is the name of the alias command to create.
        COMMAND is the command being aliased to.
        If "-a" is specified, the command is an abbreviation,
        and will not appear in help command list output.

        You can optionally provide LEADING-ARGS to define at the same time
        ALIAS and its leading args.  This is the equivalent of:
          alias ALIAS = COMMAND
          set leading-args ALIAS = LEADING-ARGS...

        Examples:
        Make "spe" an alias of "set print elements":
          alias spe = set print elements
        Make "elms" an alias of "elements" in the "set print" command:
          alias -a set print elms = set print elements
        Make "btf" an alias of "backtrace -full -past-entry -past-main" :
          alias btf = backtrace = -full -past-entry -past-main
        Make "wLapPeu" an alias of 2 nested "with":
          alias wLapPeu = with = language pascal -- with print elements unlimited --

* 'alias' command now has a completer that helps to complete:
   ALIAS (if the user defines an alias after a prefix),
   the aliased COMMAND
   the possible options for the aliased COMMAND.

* A new setting 'set enable-leading-args'.  This can be used if the
  user wants to temporarily disable the usage of leading args.
  'show enable-leading-args' shows the value of 'enable-leading-args'.

gdb/ChangeLog
2019-06-23  Philippe Waroquiers  <[hidden email]>

        * cli/cli-cmds.c (leading_args_cmd_completer,
        lookup_cmd_for_leading_args, set_leading_args_command,
        show_leading_args, show_leading_args_command_1,
        show_leading_args_command, alias_command_completer): New functions.
        (alias_usage_error): Update usage.
        (alias_command): Handles optional LEADING-ARGS... arguments.
        (_initialize_cli_cmds): Install 'set|show leading-args' commands.
        Update alias command help.
        (show_user, valid_command_p):
        Add NULL for new leading_args lookup_cmd argument.
        * cli/cli-decode.c (help_cmd): Show leading args if command has
        some.
        (lookup_cmd_1, lookup_cmd): New argument leading_args.
        (add_alias_cmd):
        Add NULL for new leading_args lookup_cmd argument.
        * cli/cli-decode.h (struct cmd_list_element): New member leading_args.
        xfree leading_args in destructor.
        * cli/cli-script.c (process_next_line, do_define_command):
        Add NULL for new leading_args lookup_cmd argument.
        * command.h: Declare new leading_args argument in lookup_cmd
        and lookup_cmd_1.
        * completer.c (complete_line_internal_1):
        Add NULL for new leading_args lookup_cmd or lookup_cmd_1 argument.
        * guile/scm-cmd.c (gdbscm_parse_command_name): Likewise.
        * guile/scm-param.c (add_setshow_generic, pascm_parameter_defined_p):
         Likewise.
        * infcmd.c (_initialize_infcmd): Likewise.
        * python/py-auto-load.c (gdbpy_initialize_auto_load): Likewise.
        * python/py-cmd.c (gdbpy_parse_command_name): Likewise.
        * python/py-param.c (add_setshow_generic): Likewise.
        * remote.c (_initialize_remote): Likewise.
        * top.c (enable_leading_args_var): New flag.
        (execute_command): Prepend leading_args if command has some.
        (set_verbose):
        Add NULL for new leading_args lookup_cmd or  lookup_cmd_1 argument.
        (init_main): Install 'set|show enable-leading-args.
        * tracepoint.c (validate_actionline, encode_actions_1):
        Add NULL for new leading_args lookup_cmd or lookup_cmd_1 argument.
---
 gdb/cli/cli-cmds.c        | 278 ++++++++++++++++++++++++++++++++++++--
 gdb/cli/cli-decode.c      |  88 ++++++++++--
 gdb/cli/cli-decode.h      |   6 +
 gdb/cli/cli-script.c      |  10 +-
 gdb/command.h             |   2 +
 gdb/completer.c           |   2 +-
 gdb/guile/scm-cmd.c       |   2 +-
 gdb/guile/scm-param.c     |   6 +-
 gdb/infcmd.c              |   6 +-
 gdb/python/py-auto-load.c |   4 +-
 gdb/python/py-cmd.c       |   2 +-
 gdb/python/py-param.c     |   4 +-
 gdb/remote.c              |   4 +-
 gdb/top.c                 |  41 +++++-
 gdb/tracepoint.c          |   6 +-
 15 files changed, 411 insertions(+), 50 deletions(-)

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 62f4d7f0c5..ca3b5db14d 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -50,6 +50,7 @@
 #include "cli/cli-setshow.h"
 #include "cli/cli-cmds.h"
 #include "cli/cli-utils.h"
+#include "cli/cli-style.h"
 
 #include "extension.h"
 #include "common/pathstuff.h"
@@ -211,6 +212,177 @@ show_command (const char *arg, int from_tty)
   cmd_show_list (showlist, from_tty, "");
 }
 
+/* Completer for the "set|show leading-args" commands.  */
+
+static void
+leading_args_cmd_completer (struct cmd_list_element *ignore,
+    completion_tracker &tracker,
+    const char *text, const char *word)
+{
+  tracker.set_use_custom_word_point (true);
+
+  const char *delim = strstr (text, "=");
+
+  /* If we're past the "=" delimiter, complete the
+     "set|show leading-args COMMAND = " as if the user has typed COMMAND.  */
+  if (delim != text
+      && delim != nullptr
+      && isspace (delim[-1])
+      && (isspace (delim[1]) || delim[1] == '\0'))
+    {
+      std::string new_text = std::string (text);
+
+      new_text.replace (delim - text, 1, "");
+      tracker.advance_custom_word_point_by (1);
+      complete_nested_command_line (tracker, new_text.c_str ());
+      return;
+    }
+
+  /* We're not yet past the "=" delimiter.  Complete a command.  */
+  complete_nested_command_line (tracker, text);
+}
+
+/* Look up the contents of TEXT as a command usable with leading args.
+   Throws an error if no such command is found.
+   Return the found command.  If the found command is a postfix command,
+   set *PREFIX_CMD to its prefix command.  */
+
+static struct cmd_list_element *
+lookup_cmd_for_leading_args (const char *text,
+     struct cmd_list_element **prefix_cmd)
+{
+  struct cmd_list_element *lcmd, *alias, *cmd;
+
+  if (text == nullptr || skip_spaces (text) == nullptr)
+    error (_("COMMAND missing."));
+
+  /* We first use lookup_cmd to verify TEXT unambiguously identifies
+     a command.  */
+  const char *line = text;
+  lcmd = lookup_cmd (&line, cmdlist, "", NULL,
+     /*allow_unknown=*/ 0,
+     /*ignore_help_classes=*/ 1);
+
+  /* Note that we accept leading args for prefix commands,
+     as a prefix command can also be a valid usable
+     command accepting some arguments.
+     For example, "thread apply" applies a command to a
+     list of thread id, and is also the prefix command for
+     thread apply all.  */
+
+  /* We have an unambiguous command for which leading args
+     can be specified.  What remains after having found LCMD
+     is either spaces, or the = character.  */
+  size_t cmd_len = line - text;
+  line = skip_spaces (line);
+  if (*line != '=' && *line != '\0')
+    error (_("Junk after command \"%.*s\": %s"),
+   (int) cmd_len, text, line);
+
+  /* We then use lookup_cmd_composition to detect if the user
+     has specified an alias, and find the possible prefix_cmd
+     of cmd.  */
+  (void) lookup_cmd_composition (text, &alias, prefix_cmd, &cmd);
+  gdb_assert (cmd != nullptr);
+  gdb_assert (cmd == lcmd);
+  if (alias != nullptr)
+    cmd = alias;
+
+  return cmd;
+}
+
+/* Implementation of the "set leading-args" command.  */
+
+static void
+set_leading_args_command (const char *arg, int from_tty)
+{
+  struct cmd_list_element *prefix_cmd;
+  struct cmd_list_element *cmd = lookup_cmd_for_leading_args (arg, &prefix_cmd);
+
+  const char *equals = strchr (arg, '=');;
+  const char *leading_args;
+
+  if (equals != nullptr)
+    {
+      leading_args = skip_spaces (++equals);
+      if (*leading_args == '\0')
+ error (_("Leading args missing after =."));
+    }
+  else
+    leading_args = nullptr;
+
+  if (cmd->leading_args)
+    xfree ((char *) cmd->leading_args);
+  if (leading_args == nullptr)
+    cmd->leading_args = nullptr;
+  else
+    cmd->leading_args = xstrdup (leading_args);
+}
+
+/* Print a message showing C name and its leading args or <no leading args>
+   if C has no leading args.
+   If SILENT_FOR_NO_LEADING_ARGS, does nothing if C has no leading args.  */
+
+static void
+show_leading_args (struct cmd_list_element *c,
+   const char *prefix,
+   bool silent_for_no_leading_args)
+{
+  if (c->leading_args != nullptr || !silent_for_no_leading_args)
+    {
+      fputs_filtered ("leading-args ", gdb_stdout);
+      fprintf_styled (gdb_stdout, title_style.style (),
+      "%s%s",
+      prefix == nullptr ? "" : prefix, c->name);
+      fprintf_filtered (gdb_stdout, " = %s\n",
+ c->leading_args == nullptr ?
+ "<no leading args>" : c->leading_args);
+    }
+}
+
+/* Recursively traverse COMMANDLIST and prints a message showing
+   the leading-args of the commands have have non-null leading args.
+   PREFIX is the prefix that led to COMMANDLIST.  */
+
+static void
+show_leading_args_command_1 (struct cmd_list_element *commandlist,
+     const char *prefix)
+{
+  struct cmd_list_element *c;
+
+  /* Walk through the commands.  */
+  for (c = commandlist; c; c = c->next)
+    {
+      show_leading_args (c, prefix, true);
+      /* If C has subcommands, recursively search if its subcommands
+ have leading args.
+ Do not recurse for abbreviations to avoid duplicates
+ in the output.  */
+      if (c->prefixlist != NULL && !c->abbrev_flag)
+ show_leading_args_command_1 (*c->prefixlist, c->prefixname);
+    }
+}
+
+/* Implementation of the "show leading-args" command.  */
+
+static void
+show_leading_args_command (const char *arg, int from_tty)
+{
+  if (arg != nullptr && skip_spaces (arg) != nullptr)
+    {
+      struct cmd_list_element *prefix_cmd;
+      struct cmd_list_element *c = lookup_cmd_for_leading_args (arg,
+ &prefix_cmd);
+
+      show_leading_args (c,
+ prefix_cmd == nullptr ?
+ "" : prefix_cmd->prefixname,
+ false);
+    }
+  else
+    show_leading_args_command_1 (cmdlist, "");
+}
+
 
 /* Provide documentation on command or list given by COMMAND.  FROM_TTY
    is ignored.  */
@@ -1358,7 +1530,7 @@ show_user (const char *args, int from_tty)
     {
       const char *comname = args;
 
-      c = lookup_cmd (&comname, cmdlist, "", 0, 1);
+      c = lookup_cmd (&comname, cmdlist, "", NULL, 0, 1);
       if (!cli_user_command_p (c))
  error (_("Not a user command."));
       show_user_1 (c, "", args, gdb_stdout);
@@ -1390,6 +1562,37 @@ apropos_command (const char *arg, int from_tty)
   apropos_cmd (gdb_stdout, cmdlist, verbose, pattern, "");
 }
 
+/* Completer for the "alias_command".  */
+
+static void
+alias_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char *word)
+{
+  tracker.set_use_custom_word_point (true);
+
+  const char *delim = strstr (text, "=");
+
+  /* If we're past the "=" delimiter, complete the
+     "alias ALIAS = COMMAND" as if the user is typing
+     set leading-args COMMAND = LEADING-ARGS...  */
+  if (delim != text
+      && delim != nullptr
+      && isspace (delim[-1])
+      && (isspace (delim[1]) || delim[1] == '\0'))
+    {
+      std::string new_text = std::string (delim + 1);
+
+      tracker.advance_custom_word_point_by (delim + 1 - text);
+      leading_args_cmd_completer (ignore, tracker, new_text.c_str (), word);
+      return;
+    }
+
+  /* We're not yet past the "=" delimiter.  Complete a command, as
+     the user maybe is typing an alias following a prefix.  */
+  complete_nested_command_line (tracker, text);
+}
+
 /* Subroutine of alias_command to simplify it.
    Return the first N elements of ARGV flattened back to a string
    with a space separating each element.
@@ -1424,7 +1627,7 @@ valid_command_p (const char *command)
 {
   struct cmd_list_element *c;
 
-  c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
+  c = lookup_cmd_1 (& command, cmdlist, NULL, NULL, 1);
 
   if (c == NULL || c == (struct cmd_list_element *) -1)
     return false;
@@ -1442,7 +1645,7 @@ valid_command_p (const char *command)
 static void
 alias_usage_error (void)
 {
-  error (_("Usage: alias [-a] [--] ALIAS = COMMAND"));
+  error (_("Usage: alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]"));
 }
 
 /* Make an alias of an existing command.  */
@@ -1462,7 +1665,12 @@ alias_command (const char *args, int from_tty)
   std::string args2 (args, equals - args);
 
   gdb_argv built_alias_argv (args2.c_str ());
-  gdb_argv command_argv (equals + 1);
+  const char *equals_leading_args =  strchr (equals + 1, '=');
+  std::string command_argv_str (equals + 1,
+ equals_leading_args == nullptr ?
+ strlen (equals + 1)
+ : equals_leading_args - equals - 1);
+  gdb_argv command_argv (command_argv_str.c_str ());
 
   char **alias_argv = built_alias_argv.get ();
   while (alias_argv[0] != NULL)
@@ -1514,6 +1722,8 @@ alias_command (const char *args, int from_tty)
   if (valid_command_p (alias))
     error (_("Alias already exists: %s"), alias);
 
+  struct cmd_list_element *alias_cmd;
+
   /* If ALIAS is one word, it is an alias for the entire COMMAND.
      Example: alias spe = set print elements
 
@@ -1526,8 +1736,8 @@ alias_command (const char *args, int from_tty)
   if (alias_argc == 1)
     {
       /* add_cmd requires *we* allocate space for name, hence the xstrdup.  */
-      add_com_alias (xstrdup (alias_argv[0]), command, class_alias,
-     abbrev_flag);
+      alias_cmd = add_com_alias (xstrdup (alias_argv[0]), command, class_alias,
+ abbrev_flag);
     }
   else
     {
@@ -1546,19 +1756,30 @@ alias_command (const char *args, int from_tty)
       alias_prefix = alias_prefix_string.c_str ();
       command_prefix = command_prefix_string.c_str ();
 
-      c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, 1);
+      c_command = lookup_cmd_1 (& command_prefix, cmdlist, NULL, NULL, 1);
       /* We've already tried to look up COMMAND.  */
       gdb_assert (c_command != NULL
   && c_command != (struct cmd_list_element *) -1);
       gdb_assert (c_command->prefixlist != NULL);
-      c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, 1);
+      c_alias = lookup_cmd_1 (& alias_prefix, cmdlist, NULL, NULL, 1);
       if (c_alias != c_command)
  error (_("ALIAS and COMMAND prefixes do not match."));
 
       /* add_cmd requires *we* allocate space for name, hence the xstrdup.  */
-      add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
-     command_argv[command_argc - 1],
-     class_alias, abbrev_flag, c_command->prefixlist);
+      alias_cmd = add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
+ command_argv[command_argc - 1],
+ class_alias, abbrev_flag,
+ c_command->prefixlist);
+    }
+
+  gdb_assert (alias_cmd);
+  gdb_assert (alias_cmd->leading_args == nullptr);
+  if (equals_leading_args != nullptr)
+    {
+      const char *leading_args = skip_spaces (equals_leading_args + 1);
+
+      if (*leading_args != '\0')
+ alias_cmd->leading_args = xstrdup (leading_args);
     }
 }
 
@@ -1855,6 +2076,26 @@ You can supply a command number to start with, or a `+' to start after\n\
 the previous command number shown."),
    &showlist);
 
+  c = add_cmd ("leading-args", class_support, set_leading_args_command, _("\
+Set or clear leading args automatically preprended to a command or alias.\n\
+Usage: set leading-args COMMAND [= LEADING-ARGS...]\n\
+Set or clear the leading arguments automatically prepended\n\
+to the arguments the user provides when COMMAND is run.\n\
+Note that COMMAND can be an alias.  Commands and their aliases\n\
+do not share their leading arguments, so you can specify different\n\
+leading arguments for a command and for each of its aliases.\n\
+Without the [= LEADING-ARGS...], clears COMMAND leading arguments."),
+   &setlist);
+  set_cmd_completer_handle_brkchars (c, leading_args_cmd_completer);
+
+  c = add_cmd ("leading-args", class_support, show_leading_args_command, _("\
+Show the leading args of a command, or of all commands.\n\
+Usage: show leading-args [COMMAND]\n\
+Show the leading args of COMMAND.  Without COMMAND, show the leading args\n\
+of all commands."),
+   &showlist);
+  set_cmd_completer_handle_brkchars (c, leading_args_cmd_completer);
+
   add_cmd ("version", no_set_class, show_version,
    _("Show what version of GDB this is."), &showlist);
 
@@ -2007,17 +2248,28 @@ When 'on', each command is displayed as it is executed."),
 
   c = add_com ("alias", class_support, alias_command, _("\
 Define a new command that is an alias of an existing command.\n\
-Usage: alias [-a] [--] ALIAS = COMMAND\n\
+Usage: alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]\n\
 ALIAS is the name of the alias command to create.\n\
 COMMAND is the command being aliased to.\n\
 If \"-a\" is specified, the command is an abbreviation,\n\
 and will not appear in help command list output.\n\
 \n\
+You can optionally provide LEADING-ARGS to define at the same time\n\
+ALIAS and its leading args.  This is the equivalent of:\n\
+  alias ALIAS = COMMAND\n\
+  set leading-args ALIAS = LEADING-ARGS...\n\
+\n\
 Examples:\n\
 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"));
+  alias -a set print elms = set print elements\n\
+Make \"btf\" an alias of \"backtrace -full -past-entry -past-main\" :\n\
+  alias btf = backtrace = -full -past-entry -past-main\n\
+Make \"wLapPeu\" an alias of 2 nested \"with\":\n\
+  alias wLapPeu = with = language pascal -- with print elements unlimited --"));
+
+  set_cmd_completer_handle_brkchars (c, alias_command_completer);
 }
 
 void
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index a6ddd8cc6d..f01c8a59c2 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -343,7 +343,7 @@ add_alias_cmd (const char *name, const char *oldname,
   struct cmd_list_element *old;
 
   tmp = oldname;
-  old = lookup_cmd (&tmp, *list, "", 1, 1);
+  old = lookup_cmd (&tmp, *list, "", NULL, 1, 1);
 
   return add_alias_cmd (name, old, theclass, abbrev_flag, list);
 }
@@ -1045,6 +1045,7 @@ void
 help_cmd (const char *command, struct ui_file *stream)
 {
   struct cmd_list_element *c;
+  const char *initial_command = command;
 
   if (!command)
     {
@@ -1058,7 +1059,7 @@ help_cmd (const char *command, struct ui_file *stream)
       return;
     }
 
-  c = lookup_cmd (&command, cmdlist, "", 0, 0);
+  c = lookup_cmd (&command, cmdlist, "", NULL, 0, 0);
 
   if (c == 0)
     return;
@@ -1078,6 +1079,41 @@ help_cmd (const char *command, struct ui_file *stream)
   fputs_filtered (c->doc, stream);
   fputs_filtered ("\n", stream);
 
+  if (c->func != nullptr)
+    {
+      /* Print the leading args of the command if it has some.
+ Use lookup_cmd_composition to find if help was requested for
+ an alias.  In this case, rather print the alias leading_args.  */
+
+      struct cmd_list_element *alias, *prefix_cmd, *cmd;
+      const char *name, *leading_args;
+
+      (void) lookup_cmd_composition (initial_command,
+     &alias, &prefix_cmd, &cmd);
+      gdb_assert (cmd != nullptr);
+      gdb_assert (cmd == c);
+
+      if (alias == nullptr)
+ {
+  name = c->name;
+  leading_args = c->leading_args;
+ }
+      else
+ {
+  name = alias->name;
+  leading_args = alias->leading_args;
+ }
+      if (leading_args != nullptr)
+ {
+  fputs_filtered ("leading-args ", stream);
+  fprintf_styled (stream, title_style.style (),
+  "%s%s",
+  prefix_cmd == nullptr ? "" : prefix_cmd->prefixname,
+  name);
+  fprintf_filtered (stream, " = %s\n", leading_args);
+ }
+    }
+
   if (c->prefixlist == 0 && c->func != NULL)
     return;
   fprintf_filtered (stream, "\n");
@@ -1409,8 +1445,12 @@ valid_user_defined_cmd_name_p (const char *name)
    the list in which there are ambiguous choices (and *TEXT will be set to
    the ambiguous text string).
 
+   if LEADING_ARGS is not null and the found command has leading args defined,
+   then *LEADING_ARGS points at these leading args.
+
    If the located command was an abbreviation, this routine returns the base
-   command of the abbreviation.
+   command of the abbreviation.  Note that *LEADING_ARGS will point at the
+   leading args defined for the alias.
 
    It does no error reporting whatsoever; control will always return
    to the superior routine.
@@ -1437,11 +1477,13 @@ valid_user_defined_cmd_name_p (const char *name)
 
 struct cmd_list_element *
 lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
-      struct cmd_list_element **result_list, int ignore_help_classes)
+      struct cmd_list_element **result_list, const char **leading_args,
+      int ignore_help_classes)
 {
   char *command;
   int len, nfound;
   struct cmd_list_element *found, *c;
+  bool found_alias = false;
   const char *line = *text;
 
   while (**text == ' ' || **text == '\t')
@@ -1477,6 +1519,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
  /* Will be modified in calling routine
    if we know what the prefix command is.  */
  *result_list = 0;
+      if (leading_args != NULL)
+ *leading_args = nullptr;
       return CMD_LIST_AMBIGUOUS; /* Ambiguous.  */
     }
 
@@ -1492,22 +1536,30 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
        are warning about the alias, we may also warn about the command
        itself and we will adjust the appropriate DEPRECATED_WARN_USER
        flags.  */
-      
+
       if (found->deprecated_warn_user)
  deprecated_cmd_warning (line);
+
+      /* Return the leading_args of the alias, not the leading_args
+ of the command it is pointing to.  */
+      if (leading_args != NULL)
+ *leading_args = found->leading_args;
       found = found->cmd_pointer;
+      found_alias = true;
     }
   /* If we found a prefix command, keep looking.  */
 
   if (found->prefixlist)
     {
       c = lookup_cmd_1 (text, *found->prefixlist, result_list,
- ignore_help_classes);
+ leading_args, ignore_help_classes);
       if (!c)
  {
   /* Didn't find anything; this is as far as we got.  */
   if (result_list != NULL)
     *result_list = clist;
+  if (!found_alias && leading_args != NULL)
+    *leading_args = found->leading_args;
   return found;
  }
       else if (c == CMD_LIST_AMBIGUOUS)
@@ -1522,11 +1574,18 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
          at the top of this function to clarify what is
          supposed to be going on.  */
       *result_list = found;
+  /* For ambiguous commands, do not return any leading_args args.  */
+  if (leading_args != nullptr)
+    *leading_args = nullptr;
   return c;
  }
       else
  {
   /* We matched!  */
+  /*
+  if (leading_args != NULL && *leading_args == nullptr)
+    *leading_args = c->leading_args;
+    */
   return c;
  }
     }
@@ -1534,6 +1593,8 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
     {
       if (result_list != NULL)
  *result_list = clist;
+      if (!found_alias && leading_args != NULL)
+ *leading_args = found->leading_args;
       return found;
     }
 }
@@ -1553,21 +1614,28 @@ undef_cmd_error (const char *cmdtype, const char *q)
 
 /* Look up the contents of *LINE as a command in the command list LIST.
    LIST is a chain of struct cmd_list_element's.
-   If it is found, return the struct cmd_list_element for that command
-   and update *LINE to point after the command name, at the first argument.
+   If it is found, return the struct cmd_list_element for that command,
+   update *LINE to point after the command name, at the first argument
+   and update *LEADING_ARGS (if LEADING_ARGS is not null) to point at
+   the leading args to prepend to the user provided args when running
+   the command.
+   Note that if the found cmd_list_element is found via an alias,
+   the leading args of the alias are returned.
+
    If not found, call error if ALLOW_UNKNOWN is zero
    otherwise (or if error returns) return zero.
    Call error if specified command is ambiguous,
    unless ALLOW_UNKNOWN is negative.
    CMDTYPE precedes the word "command" in the error message.
 
-   If INGNORE_HELP_CLASSES is nonzero, ignore any command list
+   If IGNORE_HELP_CLASSES is nonzero, ignore any command list
    elements which are actually help classes rather than commands (i.e.
    the function field of the struct cmd_list_element is 0).  */
 
 struct cmd_list_element *
 lookup_cmd (const char **line, struct cmd_list_element *list,
     const char *cmdtype,
+    const char **leading_args,
     int allow_unknown, int ignore_help_classes)
 {
   struct cmd_list_element *last_list = 0;
@@ -1579,7 +1647,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
   if (!*line)
     error (_("Lack of needed %scommand"), cmdtype);
 
-  c = lookup_cmd_1 (line, list, &last_list, ignore_help_classes);
+  c = lookup_cmd_1 (line, list, &last_list, leading_args, ignore_help_classes);
 
   if (!c)
     {
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 05280d9d22..82a0858351 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -68,6 +68,8 @@ struct cmd_list_element
     {
       if (doc && doc_allocated)
  xfree ((char *) doc);
+      if (leading_args)
+ xfree ((char *) leading_args);
     }
 
     DISABLE_COPY_AND_ASSIGN (cmd_list_element);
@@ -175,6 +177,10 @@ struct cmd_list_element
     /* Hook for another command to be executed after this command.  */
     struct cmd_list_element *hook_post = nullptr;
 
+    /* Leading arguments to automatically prepend to the user
+       provided arguments when running this command or alias.  */
+    const char *leading_args = nullptr;
+
     /* Nonzero identifies a prefix command.  For them, the address
        of the variable containing the list of subcommands.  */
     struct cmd_list_element **prefixlist = nullptr;
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 361ead4725..23bbbe546c 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -971,7 +971,7 @@ process_next_line (const char *p, struct command_line **command,
       /* Resolve command abbreviations (e.g. 'ws' for 'while-stepping').  */
       const char *cmd_name = p;
       struct cmd_list_element *cmd
- = lookup_cmd_1 (&cmd_name, cmdlist, NULL, 1);
+ = lookup_cmd_1 (&cmd_name, cmdlist, NULL, NULL, 1);
       cmd_name = skip_spaces (cmd_name);
       bool inline_cmd = *cmd_name != '\0';
 
@@ -1328,7 +1328,7 @@ validate_comname (const char **comname)
       std::string prefix (*comname, last_word - 1);
       const char *tem = prefix.c_str ();
 
-      c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+      c = lookup_cmd (&tem, cmdlist, "", NULL, 0, 1);
       if (c->prefixlist == NULL)
  error (_("\"%s\" is not a prefix command."), prefix.c_str ());
 
@@ -1384,7 +1384,7 @@ do_define_command (const char *comname, int from_tty,
 
   /* Look it up, and verify that we got an exact match.  */
   tem = comname;
-  c = lookup_cmd (&tem, *list, "", -1, 1);
+  c = lookup_cmd (&tem, *list, "", NULL, -1, 1);
   if (c && strcmp (comname, c->name) != 0)
     c = 0;
 
@@ -1419,7 +1419,7 @@ do_define_command (const char *comname, int from_tty,
     {
       /* Look up cmd it hooks, and verify that we got an exact match.  */
       tem = comname + hook_name_size;
-      hookc = lookup_cmd (&tem, *list, "", -1, 0);
+      hookc = lookup_cmd (&tem, *list, "", NULL, -1, 0);
       if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
  hookc = 0;
       if (!hookc && commands == nullptr)
@@ -1488,7 +1488,7 @@ document_command (const char *comname, int from_tty)
   list = validate_comname (&comname);
 
   tem = comname;
-  c = lookup_cmd (&tem, *list, "", 0, 1);
+  c = lookup_cmd (&tem, *list, "", NULL, 0, 1);
 
   if (c->theclass != class_user)
     error (_("Command \"%s\" is built-in."), comfull);
diff --git a/gdb/command.h b/gdb/command.h
index 4d52f00de5..224bb1b6bc 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -244,11 +244,13 @@ extern enum cmd_types cmd_type (struct cmd_list_element *cmd);
 extern struct cmd_list_element *lookup_cmd (const char **,
     struct cmd_list_element *,
     const char *,
+    const char **,
     int, int);
 
 extern struct cmd_list_element *lookup_cmd_1 (const char **,
       struct cmd_list_element *,
       struct cmd_list_element **,
+      const char **,
       int);
 
 extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,
diff --git a/gdb/completer.c b/gdb/completer.c
index 6892a62bb9..b93134ed5e 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -1341,7 +1341,7 @@ complete_line_internal_1 (completion_tracker &tracker,
     }
   else
     {
-      c = lookup_cmd_1 (&p, cmdlist, &result_list, ignore_help_classes);
+      c = lookup_cmd_1 (&p, cmdlist, &result_list, NULL, ignore_help_classes);
     }
 
   /* Move p up to the next interesting thing.  */
diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c
index f2fa40e453..8cf70f6e52 100644
--- a/gdb/guile/scm-cmd.c
+++ b/gdb/guile/scm-cmd.c
@@ -515,7 +515,7 @@ gdbscm_parse_command_name (const char *name,
   prefix_text[i + 1] = '\0';
 
   prefix_text2 = prefix_text;
-  elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
+  elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
   if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
     {
       msg = xstrprintf (_("could not find command prefix '%s'"), prefix_text);
diff --git a/gdb/guile/scm-param.c b/gdb/guile/scm-param.c
index 53120cb23e..4d3ce6770a 100644
--- a/gdb/guile/scm-param.c
+++ b/gdb/guile/scm-param.c
@@ -463,13 +463,13 @@ add_setshow_generic (enum var_types param_type, enum command_class cmd_class,
   /* Lookup created parameter, and register Scheme object against the
      parameter context.  Perform this task against both lists.  */
   tmp_name = cmd_name;
-  param = lookup_cmd (&tmp_name, *show_list, "", 0, 1);
+  param = lookup_cmd (&tmp_name, *show_list, "", NULL, 0, 1);
   gdb_assert (param != NULL);
   set_cmd_context (param, self);
   *set_cmd = param;
 
   tmp_name = cmd_name;
-  param = lookup_cmd (&tmp_name, *set_list, "", 0, 1);
+  param = lookup_cmd (&tmp_name, *set_list, "", NULL, 0, 1);
   gdb_assert (param != NULL);
   set_cmd_context (param, self);
   *show_cmd = param;
@@ -966,7 +966,7 @@ pascm_parameter_defined_p (const char *name, struct cmd_list_element *list)
 {
   struct cmd_list_element *c;
 
-  c = lookup_cmd_1 (&name, list, NULL, 1);
+  c = lookup_cmd_1 (&name, list, NULL, NULL, 1);
 
   /* If the name is ambiguous that's ok, it's a new parameter still.  */
   return c != NULL && c != CMD_LIST_AMBIGUOUS;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 0f94100438..bd06474688 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -3148,7 +3148,7 @@ is restored."),
      show_inferior_tty_command,
      &setlist, &showlist);
   cmd_name = "inferior-tty";
-  c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+  c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
   gdb_assert (c != NULL);
   add_alias_cmd ("tty", c, class_alias, 0, &cmdlist);
 
@@ -3161,7 +3161,7 @@ Follow this command with any number of args, to be passed to the program."),
    set_args_command,
    show_args_command,
    &setlist, &showlist);
-  c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+  c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
   gdb_assert (c != NULL);
   set_cmd_completer (c, filename_completer);
 
@@ -3180,7 +3180,7 @@ working directory."),
    set_cwd_command,
    show_cwd_command,
    &setlist, &showlist);
-  c = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+  c = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
   gdb_assert (c != NULL);
   set_cmd_completer (c, filename_completer);
 
diff --git a/gdb/python/py-auto-load.c b/gdb/python/py-auto-load.c
index c7b9afdb11..559652de93 100644
--- a/gdb/python/py-auto-load.c
+++ b/gdb/python/py-auto-load.c
@@ -84,12 +84,12 @@ Show the debugger's behaviour regarding auto-loaded Python scripts, "
    NULL, NULL, show_auto_load_python_scripts,
    &setlist, &showlist);
   cmd_name = "auto-load-scripts";
-  cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+  cmd = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
   deprecate_cmd (cmd, "set auto-load python-scripts");
 
   /* It is needed because lookup_cmd updates the CMD_NAME pointer.  */
   cmd_name = "auto-load-scripts";
-  cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1);
+  cmd = lookup_cmd (&cmd_name, showlist, "", NULL, -1, 1);
   deprecate_cmd (cmd, "show auto-load python-scripts");
 
   add_cmd ("python-scripts", class_info, info_auto_load_python_scripts,
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index 87d1888c52..70e328080c 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -396,7 +396,7 @@ gdbpy_parse_command_name (const char *name,
   std::string prefix_text (name, i + 1);
 
   prefix_text2 = prefix_text.c_str ();
-  elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, 1);
+  elt = lookup_cmd_1 (&prefix_text2, *start_list, NULL, NULL, 1);
   if (elt == NULL || elt == CMD_LIST_AMBIGUOUS)
     {
       PyErr_Format (PyExc_RuntimeError, _("Could not find command prefix %s."),
diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c
index afeff581ee..87af351051 100644
--- a/gdb/python/py-param.c
+++ b/gdb/python/py-param.c
@@ -566,12 +566,12 @@ add_setshow_generic (int parmclass, enum command_class cmdclass,
   /* Lookup created parameter, and register Python object against the
      parameter context.  Perform this task against both lists.  */
   tmp_name = cmd_name;
-  param = lookup_cmd (&tmp_name, *show_list, "", 0, 1);
+  param = lookup_cmd (&tmp_name, *show_list, "", NULL, 0, 1);
   if (param)
     set_cmd_context (param, self);
 
   tmp_name = cmd_name;
-  param = lookup_cmd (&tmp_name, *set_list, "", 0, 1);
+  param = lookup_cmd (&tmp_name, *set_list, "", NULL, 0, 1);
   if (param)
     set_cmd_context (param, self);
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index 124d254478..801091c9aa 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -14312,10 +14312,10 @@ If set, a break, instead of a cntrl-c, is sent to the remote target."),
    set_remotebreak, show_remotebreak,
    &setlist, &showlist);
   cmd_name = "remotebreak";
-  cmd = lookup_cmd (&cmd_name, setlist, "", -1, 1);
+  cmd = lookup_cmd (&cmd_name, setlist, "", NULL, -1, 1);
   deprecate_cmd (cmd, "set remote interrupt-sequence");
   cmd_name = "remotebreak"; /* needed because lookup_cmd updates the pointer */
-  cmd = lookup_cmd (&cmd_name, showlist, "", -1, 1);
+  cmd = lookup_cmd (&cmd_name, showlist, "", NULL, -1, 1);
   deprecate_cmd (cmd, "show remote interrupt-sequence");
 
   add_setshow_enum_cmd ("interrupt-sequence", class_support,
diff --git a/gdb/top.c b/gdb/top.c
index be736b0a87..14bd5375fd 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -542,6 +542,11 @@ set_repeat_arguments (const char *args)
   repeat_arguments = args;
 }
 
+/* Flag for whether we want to use the configured leading args.
+   Default is yes.  */
+
+static int enable_leading_args_var = 1;
+
 /* Execute the line P as a command, in the current user context.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -570,6 +575,8 @@ execute_command (const char *p, int from_tty)
     {
       const char *cmd = p;
       const char *arg;
+      const char *leading_args;
+      std::string leading_args_and_arg;
       int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
 
       line = p;
@@ -577,15 +584,28 @@ execute_command (const char *p, int from_tty)
       /* If trace-commands is set then this will print this command.  */
       print_command_trace ("%s", p);
 
-      c = lookup_cmd (&cmd, cmdlist, "", 0, 1);
+      c = lookup_cmd (&cmd, cmdlist, "", &leading_args, 0, 1);
       p = cmd;
 
       scoped_restore save_repeat_args
  = make_scoped_restore (&repeat_arguments, nullptr);
       const char *args_pointer = p;
 
-      /* Pass null arg rather than an empty one.  */
-      arg = *p ? p : 0;
+      if (leading_args != nullptr && enable_leading_args_var)
+ {
+  leading_args_and_arg = std::string (leading_args);
+  if (*p)
+    leading_args_and_arg = std::string (leading_args)
+      + ' ' + std::string (p);
+  else
+    leading_args_and_arg = std::string (leading_args);
+  arg = leading_args_and_arg.c_str ();
+ }
+      else
+ {
+  /* Pass null arg rather than an empty one.  */
+  arg = *p ? p : 0;
+ }
 
       /* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy
          while the is_complete_command(cfunc) test is just plain
@@ -1896,7 +1916,7 @@ set_verbose (const char *args, int from_tty, struct cmd_list_element *c)
   const char *cmdname = "verbose";
   struct cmd_list_element *showcmd;
 
-  showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+  showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, NULL, 1);
   gdb_assert (showcmd != NULL && showcmd != CMD_LIST_AMBIGUOUS);
 
   if (c->doc && c->doc_allocated)
@@ -2126,6 +2146,19 @@ EMACS-like or VI-like commands like control-P or ESC."),
    show_editing,
    &setlist, &showlist);
 
+  add_setshow_boolean_cmd ("enable-leading-args", class_support,
+   &enable_leading_args_var, _("\
+Set whether GDB prepends leading args when running a command.\n\
+The leading args for a command are configured using\n\
+\"set leading-args COMMAND = LEADING-ARGS..."), _("\
+Show whether GDB prepends leading args when running a command."), _("\
+Use \"on\" to enable the usage of the configured leading args,\n\
+and \"off\" to disable it.\n\
+Without an argument, leading args usage is enabled."),
+   NULL,
+   NULL,
+   &setlist, &showlist);
+
   add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\
 Set saving of the history record on exit."), _("\
 Show saving of the history record on exit."), _("\
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index af5dcd1e33..918a485b5e 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -651,7 +651,7 @@ validate_actionline (const char *line, struct breakpoint *b)
   if (*p == '#') /* comment line */
     return;
 
-  c = lookup_cmd (&p, cmdlist, "", -1, 1);
+  c = lookup_cmd (&p, cmdlist, "", NULL, -1, 1);
   if (c == 0)
     error (_("`%s' is not a tracepoint action, or is ambiguous."), p);
 
@@ -1309,7 +1309,7 @@ encode_actions_1 (struct command_line *action,
       action_exp = action->line;
       action_exp = skip_spaces (action_exp);
 
-      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+      cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
       if (cmd == 0)
  error (_("Bad action list item: %s"), action_exp);
 
@@ -2679,7 +2679,7 @@ trace_dump_actions (struct command_line *action,
       if (*action_exp == '#') /* comment line */
  continue;
 
-      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
+      cmd = lookup_cmd (&action_exp, cmdlist, "", NULL, -1, 1);
       if (cmd == 0)
  error (_("Bad action list item: %s"), action_exp);
 
--
2.20.1

Reply | Threaded
Open this post in threaded view
|

[RFA 2/3] Add tests for new leading-args related commands and arguments.

Philippe Waroquiers
In reply to this post by Philippe Waroquiers
Test the new leading-args behaviour and completion.
Note that gdb.base/leading-args.exp is somewhat copied from
with.exp (the test of the with command), while leading-exp.c
is a plain copy of with.c.

gdb/testsuite/ChangeLog
2019-06-23  Philippe Waroquiers  <[hidden email]>

        * gdb.base/leading-args.exp: New test.
        * gdb.base/leading.c: New file.
---
 gdb/testsuite/gdb.base/leading-args.c   |  41 +++++++
 gdb/testsuite/gdb.base/leading-args.exp | 155 ++++++++++++++++++++++++
 2 files changed, 196 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/leading-args.c
 create mode 100644 gdb/testsuite/gdb.base/leading-args.exp

diff --git a/gdb/testsuite/gdb.base/leading-args.c b/gdb/testsuite/gdb.base/leading-args.c
new file mode 100644
index 0000000000..c6426625d4
--- /dev/null
+++ b/gdb/testsuite/gdb.base/leading-args.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int xxx1 = 123;
+
+struct S
+{
+  int a;
+  int b;
+  int c;
+};
+
+struct S g_s = {1, 2, 3};
+
+static void
+inc ()
+{
+  g_s.a++;;
+}
+
+int
+main ()
+{
+  inc ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/leading-args.exp b/gdb/testsuite/gdb.base/leading-args.exp
new file mode 100644
index 0000000000..e419cceab8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/leading-args.exp
@@ -0,0 +1,155 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the "leading-args" related commands and arguments.
+
+load_lib completion-support.exp
+
+standard_testfile .c
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+    return -1
+}
+
+clean_restart $binfile
+
+# Basic/core tests using user-visible commands.
+with_test_prefix "basics" {
+    # Define an alias to pretty print something.
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" "simple print"
+    gdb_test_no_output "alias PP = print = -pretty --" "alias PP"
+    gdb_test "show leading-args PP" "leading-args PP = -pretty --"
+    gdb_test "PP g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"]
+
+    # Define leading-args for "inspect", should not impact "print".
+    gdb_test_no_output "set leading-args inspect = -pretty --" "inspect -pretty"
+    gdb_test "show leading-args inspect" "leading-args inspect = -pretty --"
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" "simple print not impacted"
+    gdb_test "inspect g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"]
+
+    # Set hex as default FMT for print.
+    gdb_test_no_output "set leading-args print = -- /x" "print hex"
+    gdb_test "inspect g_s" \
+ [multi_line  \
+     " = {" \
+     "  a = 1," \
+     "  b = 2," \
+     "  c = 3" \
+     "}"] "inspect g_s still pretty"
+    gdb_test "print g_s" " = {a = 0x1, b = 0x2, c = 0x3}" "simple print hex"
+
+    # Test disabling leading args.
+    gdb_test "show enable-leading-args" \
+ "Whether GDB prepends leading args when running a command is on\."
+    gdb_test_no_output "set enable-leading-args off"
+    gdb_test "print g_s" " = {a = 1, b = 2, c = 3}" \
+ "simple print with enable-leading-args off"
+    gdb_test_no_output "set enable-leading-args on"
+    
+
+    # Define leading-args for an alias of frame apply all
+    gdb_test_no_output "alias frame apply tout = frame apply all = -past-entry -past-main" \
+ "alias frame apply tout"
+    gdb_test "show leading-args frame apply tout" \
+ "leading-args frame apply tout = -past-entry -past-main"
+
+    # Show all leading args.
+    gdb_test "show leading-args" \
+ [multi_line  \
+     "leading-args PP = -pretty --" \
+     "leading-args frame apply tout = -past-entry -past-main" \
+     "leading-args inspect = -pretty --" \
+     "leading-args print = -- /x"] "show leading-args"
+
+    # Clear the leading-args of "inspect".
+    gdb_test_no_output "set leading-args inspect" "clear inspect leading-args"
+    gdb_test "show leading-args inspect" "leading-args inspect = <no leading args>"
+    gdb_test "inspect g_s" " = {a = 1, b = 2, c = 3}" "simple inspect"
+
+}
+
+# Check errors.
+with_test_prefix "errors" {
+    # Try both an unknown root setting and an unknown prefixed
+    # setting.  The errors come from different locations in the
+    # sources.
+    gdb_test "set leading-args xxxx yyyy = -someoption" \
+ "Undefined command: \"xxxx\".  Try \"help\"\\."
+    gdb_test "set leading-args frame apply everyframe = -someoption" \
+ "Junk after command \"frame apply \": everyframe = -someoption"
+
+    # Try ambiguous command.
+    gdb_test "set leading-args a" \
+ "Ambiguous command \"a\":.*" "ambiguous a"
+    gdb_test "set leading-args frame a" \
+ "Ambiguous frame command \"a\":.*" "ambiguous frame a"
+}
+
+
+# Check completion.
+with_test_prefix "completion" {
+    test_gdb_complete_unique \
+ "alias set pri" \
+ "alias set print"
+
+    test_gdb_complete_unique \
+ "alias set print items = set pri" \
+ "alias set print items = set print"
+
+    test_gdb_complete_unique \
+ "alias set print items = set print ele" \
+ "alias set print items = set print elements"
+
+   test_gdb_complete_unique \
+ "alias btfu = backt" \
+ "alias btfu = backtrace"
+
+   test_gdb_complete_unique \
+ "alias btfu = backtrace = -fu" \
+ "alias btfu = backtrace = -full"
+
+   test_gdb_complete_unique \
+ "alias btfu = backtrace = -full -past-e" \
+ "alias btfu = backtrace = -full -past-entry"
+
+    gdb_test_no_output "alias btfu = backtrace = -full -past-entry" \
+ "alias btfu"
+
+    # Test completion of 'set leading-args' (sharing most
+    # of the code that alias command uses to complete after
+    # the first =.
+    test_gdb_complete_unique \
+ "set leading-args btf" \
+ "set leading-args btfu"
+
+    test_gdb_complete_unique \
+ "set leading-args btfu = -frame-a" \
+ "set leading-args btfu = -frame-arguments"
+
+}
--
2.20.1

Reply | Threaded
Open this post in threaded view
|

[RFA 3/3] NEWS and documentation for leading-args related concept and commands.

Philippe Waroquiers
In reply to this post by Philippe Waroquiers
gdb/ChangeLog
2019-06-25  Philippe Waroquiers  <[hidden email]>

        * NEWS: Mention new leading-args commands.  Mention change
        to the alias command.

gdb/doc/ChangeLog
2019-06-25  Philippe Waroquiers  <[hidden email]>

        * gdb.texinfo (Command leading args): New node documenting
        'set|show leading-args' and 'set|show enable-leading-args'.
        (Aliases): Document the new '= LEADING-ARGS...' option.
---
 gdb/NEWS            |  18 +++++++
 gdb/doc/gdb.texinfo | 121 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 2cc82e8656..2dc3fac4ee 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,18 @@ pipe -d DELIM COMMAND DELIM SHELL_COMMAND
   With no COMMAND, repeat the last executed command
   and send its output to SHELL_COMMAND.
 
+set leading-args COMMAND [= LEADING-ARGS...]
+show leading-args [COMMAND]
+set enable-leading-args [on|off]
+show enable-leading-args
+  GDB can now automatically prepend leading args to a command or alias.
+  This allows to set default arguments or options for the GDB commands
+  or define easier to use aliases.
+  For example, 'set leading-args backtrace = -full -frame-arguments all'
+  ensures that backtrace will automatically use the options -full
+  -frame-arguments all, without having to retype them for each backtrace
+  command.
+
 set may-call-functions [on|off]
 show may-call-functions
   This controls whether GDB will attempt to call functions in
@@ -102,6 +114,12 @@ apropos [-v] REGEXP
   of matching commands and to use the highlight style to mark
   the documentation parts matching REGEXP.
 
+alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]
+  The alias command can now directly define leading-args
+  to prepend to arguments provided by the user on the command line.
+  See 'set leading-args COMMAND [= LEADING-ARGS...]' for more
+  information about leading args concept.
+
 show style
   The "show style" and its subcommands are now styling
   a style name in their output using its own style, to help
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 55be2ef692..a8ae08ccca 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1563,6 +1563,7 @@ show you the alternatives available, if there is more than one possibility).
 * Command Syntax::              How to give commands to @value{GDBN}
 * Completion::                  Command completion
 * Command Options::             Command options
+* Command leading args::        Automatically prepend arguments to commands and aliases
 * Help::                        How to ask @value{GDBN} for help
 @end menu
 
@@ -1891,6 +1892,111 @@ uppercase.
 (For more on using the @code{print} command, see @ref{Data, ,Examining
 Data}.)
 
+@node Command leading args
+@section Automatically prepend arguments to commands and aliases
+
+You can tell @value{GDBN} to always add some default options or
+arguments to a command.
+
+@cindex command options, automatically prepend
+@cindex command, default arguments
+
+@table @code
+@kindex set leading-args
+@item set leading-args @var{command} [= @var{leading-args@dots{}}]
+
+If you repetitively use the same arguments or options for a command,
+you can tell @value{GDBN} to automatically prepend these arguments
+or options to the arguments you type explicitely.
+
+For example, if you always want to have the command @code{thread apply all}
+working on the threads in ascending order and to continue in case it
+encounters an error, you can tell @value{GDBN} to automatically preprend
+the @code{-ascending} and @code{-c} options by using:
+
+@smallexample
+(@value{GDBP}) set leading-args thread apply all = -ascending -c
+@end smallexample
+
+Once you have set these leading args, any time you type
+the @code{thread apply all} followed by @code{some arguments},
+@value{GDBN} will execute  @code{thread apply all -ascending -c some arguments}.
+
+As usual, unambiguous abbreviations can be used for @var{command} and @var{leading-args}.
+
+Commands and their aliases do not share their leading args.
+So, for example, you can configure the commands @code{bt}, @code{where},
+@code{backtrace} and @code{info stack} to output different levels
+of information and define a new alias @code{bt_ALL} showing all possible information
+using:
+@smallexample
+(@value{GDBP}) set leading-args bt = -entry-values no -frame-arguments none
+(@value{GDBP}) set leading-args where = -entry-values no -frame-argu scalars
+(@value{GDBP}) set leading-args backtrace = -entry-values no -frame-argu all
+(@value{GDBP}) set leading-args info stack = -entry-val both -fr all
+(@value{GDBP}) alias bt_ALL = backtrace
+(@value{GDBP}) set leading-args bt_ALL = -entry-values both -frame-arg all \
+-past-main -past-entry -full
+@end smallexample
+
+You can define an alias and specify its leading args in one command using the shorter to type:
+@smallexample
+(@value{GDBP}) alias bt_ALL = backtrace = -entry-values both -frame-arg all \
+-past-main -past-entry -full
+@end smallexample
+(For more on using the @code{alias} command, see @ref{Aliases}.)
+
+Leading args are not limited to the arguments and options of @var{command}, but can
+specify nested commands if @var{command} accepts such a nested command as argument.
+For example, the below defines @code{faalocalsoftype} that can be used to list
+the frames having locals of a certain type, together with the matching local vars:
+@smallexample
+(@value{GDBP}) alias faalocalsoftype = frame apply all = info locals -q -t
+(@value{GDBP}) faalocalsoftype int
+#1  0x55554f5e in sleeper_or_burner (v=0xdf50) at sleepers.c:86
+i = 0
+ret = 21845
+@end smallexample
+
+@c Note: the below is referencing the 'with' command, that has still to be pushed by Pedro.
+This is also very useful to define an alias for a set of nested @code{with} commands
+to have a particular combination of temporary settings.  For example, the below
+defines the alias @code{pp10} that pretty prints an expression argument,
+with a maximum of 10 elements if the expression is a string or an array:
+@smallexample
+(@value{GDBP}) alias pp10 = with = print pretty -- with print elem 10 -- print
+@end smallexample
+
+
+Use @code{set leading-args @var{command}} (without giving @var{= LEADING-ARGS}) to clear
+the leading args of @var{command}.
+
+@item show leading-args [@var{command}]
+
+Use @code{show leading-args @var{command}} to show the current values of the leading args
+for @var{command}.  For example:
+@smallexample
+(@value{GDBP}) show leading-args backtrace
+leading-args backtrace = -entry-values no -frame-arguments all
+(@value{GDBP}) show leading-args break
+leading-args break = <no leading args>
+@end smallexample
+
+To show all the commands and aliases that have some leading args configured, use the command
+@code{show leading-args} without giving a @var{command} argument.
+
+@item set enable-leading-args @r{[}on|off@r{]}
+@itemx show enable-leading-args
+By default, @value{GDBN} will use the configured leading args.  This can be disabled using
+@code{set enable-leading-args off}.  The leading args of all commands are not cleared, but
+will not be used till you do @code{set enable-leading-args on}.
+This can be useful in user defined commands to ensure only the specified set of options
+are used by a command launched by the user-defined command.
+You can also use this setting in the @code{with} command, to temporarily run a command
+without its possibly configured leading args.
+
+@end table
+
 @node Help
 @section Getting Help
 @cindex online documentation
@@ -26937,7 +27043,7 @@ You can define a new alias with the @samp{alias} command.
 @table @code
 
 @kindex alias
-@item alias [-a] [--] @var{ALIAS} = @var{COMMAND}
+@item alias [-a] [--] @var{ALIAS} = @var{COMMAND} [= LEADING-ARGS...]
 
 @end table
 
@@ -26955,6 +27061,19 @@ lists displayed by the @samp{help} command.
 The @samp{--} option specifies the end of options,
 and is useful when @var{ALIAS} begins with a dash.
 
+You can specify @var{leading-args} for your alias.
+These @var{leading-args} will be automatically added before the alias
+arguments typed explicitely on the command line.
+
+For example, the below defines an alias @code{btfullall} that shows all local
+variables and all frame arguments:
+@smallexample
+(@value{GDBP}) alias btfullall = backtrace = -full -frame-arguments all
+@end smallexample
+
+For more information about @var{leading-args}, see @ref{Command leading args,
+,Automatically prepend arguments to commands and aliases}
+
 Here is a simple example showing how to make an abbreviation
 of a command so that there is less to type.
 Suppose you were tired of typing @samp{disas}, the current
--
2.20.1

Reply | Threaded
Open this post in threaded view
|

Re: [RFA 3/3] NEWS and documentation for leading-args related concept and commands.

Eli Zaretskii
> From: Philippe Waroquiers <[hidden email]>
> Cc: Philippe Waroquiers <[hidden email]>
> Date: Tue, 25 Jun 2019 01:11:44 +0200
>
> +* Command leading args::        Automatically prepend arguments to commands and aliases

The name of the section sounds too long to me.  How about this
instead:

  * Leading Arguments::            Leading arguments to commands

> +@node Command leading args
> +@section Automatically prepend arguments to commands and aliases

Likewise here.  Also, the section name should have its words
capitalized.

> +If you repetitively use the same arguments or options for a command,
          ^^^^^^^^^^^^
"repeatedly"

> +you can tell @value{GDBN} to automatically prepend these arguments
> +or options to the arguments you type explicitely.
                                        ^^^^^^^^^^^
"explicitly"

> +@code{set enable-leading-args off}.  The leading args of all commands are not cleared, but
> +will not be used till you do @code{set enable-leading-args on}.
                             ^^
"type", not "do".  Also, please use @kbd instead of @code for commands
the user is supposed to type.

> +arguments typed explicitely on the command line.
                   ^^^^^^^^^^^
"explicitly"

Finally, please refill the text so that each line is shorter than 79
columns, otherwise it's hard to read the Texinfo source.

Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [RFA 3/3] NEWS and documentation for leading-args related concept and commands.

Philippe Waroquiers
Thanks for the review.

On Tue, 2019-06-25 at 19:33 +0300, Eli Zaretskii wrote:

> > From: Philippe Waroquiers <[hidden email]>
> > Cc: Philippe Waroquiers <[hidden email]>
> > Date: Tue, 25 Jun 2019 01:11:44 +0200
> >
> > +* Command leading args::        Automatically prepend arguments to commands and aliases
>
> The name of the section sounds too long to me.  How about this
> instead:
>
>   * Leading Arguments::            Leading arguments to commands
Effectively, it is very long.  However, it looks to me we should somehow
indicate that GDB is doing something automatically.
What about:
* Leading Arguments::            Default leading arguments to commands
?


I will fix all other comments in the next version.

Philippe


>
> > +@node Command leading args
> > +@section Automatically prepend arguments to commands and aliases
>
> Likewise here.  Also, the section name should have its words
> capitalized.
>
> > +If you repetitively use the same arguments or options for a command,
>
>           ^^^^^^^^^^^^
> "repeatedly"
>
> > +you can tell @value{GDBN} to automatically prepend these arguments
> > +or options to the arguments you type explicitely.
>
>                                         ^^^^^^^^^^^
> "explicitly"
>
> > +@code{set enable-leading-args off}.  The leading args of all commands are not cleared, but
> > +will not be used till you do @code{set enable-leading-args on}.
>
>                              ^^
> "type", not "do".  Also, please use @kbd instead of @code for commands
> the user is supposed to type.
>
> > +arguments typed explicitely on the command line.
>
>                    ^^^^^^^^^^^
> "explicitly"
>
> Finally, please refill the text so that each line is shorter than 79
> columns, otherwise it's hard to read the Texinfo source.
>
> Thanks.
Reply | Threaded
Open this post in threaded view
|

Re: [RFA 3/3] NEWS and documentation for leading-args related concept and commands.

Eli Zaretskii
> From: Philippe Waroquiers <[hidden email]>
> Cc: [hidden email]
> Date: Tue, 25 Jun 2019 20:22:07 +0200
>
> * Leading Arguments::            Default leading arguments to commands
> ?

Fine with me, thanks.
Reply | Threaded
Open this post in threaded view
|

PING Re: [RFA 0/3] Allow the user to define default leading args for commands and aliases

Philippe Waroquiers
In reply to this post by Philippe Waroquiers
ping ?

Thanks

Philippe

On Tue, 2019-06-25 at 01:11 +0200, Philippe Waroquiers wrote:

> Allow the user to define default leading args for commands and aliases.
>
> This patch series implements, tests and documents the following commands:
>
>   set leading-args COMMAND [= LEADING-ARGS...]
>   show leading-args [COMMAND]
>   set enable-leading-args [on|off]
>   show enable-leading-args
>
>
> It also changes the alias command to be:
>   alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]
>
>
> Using the above leading-args commands and arguments, you can
> define default arguments for commands or define powerful aliases.
>
> For example:
>
>   alias bt_ALL = backtrace = -entry-values both -frame-arg all -past-main -past-entry -full
>
> defines the alias bt_ALL that will give as much information as possible
> in a backtrace.
>
> Leading args can usefully be combined with the (soon to be pushed I hope)
> 'with' command, such as:
>
> Make "wLapPeu" an alias of 2 nested "with":
>   alias wLapPeu = with = language pascal -- with print elements unlimited --
>
> or have an alias pp10 to pretty print an expression with a maximum of
> 10 elements:
>
>   alias pp10 = with = print pretty -- with print elem 10 -- print
>
>
> This patch series also adds a completer for 'alias'.
>
>
> Note 1: a preliminary version of this idea (using a command called
> 'add-args' was discussed in
> https://sourceware.org/ml/gdb-patches/2019-06/msg00395.html
> where Tom suggested to make it more GDB like, using 'set' command.
>
> Note 2: I have made the '=' character mandatory in the 'set leading-args'
> command to be sure to unambiguously separate the COMMAND from the
> specified leading args.
>
> Also, an '=' character must be specified in the alias command before
> the LEADING-ARGS for consistency with set leading-args.
> This also ensures that the user cannot type a wrong command name
> that would be interpreted as leading args and/or cause 'mismatch'
> of length between ALIAS and COMMAND
> (see https://sourceware.org/ml/gdb-patches/2019-06/msg00459.html
> [RFA] Fix alias command not detecting non matching prefix & sometimes asserting.).
>
>
Reply | Threaded
Open this post in threaded view
|

Re: [RFA 0/3] Allow the user to define default leading args for commands and aliases

Tom Tromey-2
In reply to this post by Philippe Waroquiers
>>>>> "Philippe" == Philippe Waroquiers <[hidden email]> writes:

Philippe> Allow the user to define default leading args for commands and aliases.
Philippe> This patch series implements, tests and documents the following commands:

Thank you for the patches.

Philippe>   set leading-args COMMAND [= LEADING-ARGS...]
Philippe>   show leading-args [COMMAND]
Philippe>   set enable-leading-args [on|off]
Philippe>   show enable-leading-args

Philippe> It also changes the alias command to be:
Philippe>   alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]

I don't really like the "leading args" approach, but I've put off
responding to this because I wasn't sure how to articulate my
objections.

However, I never did come up with a really good way to talk about it.

Partly, I think, the feature seems obscure.  It's preferable, in my
view, to continue the approach gdb already takes; namely, adding "set"
commands to affect the behavior of commands when desirable.


On the related commands:

What is the rationale for "set enable-leading-args"?  This seems truly
unnecessary.

For "alias", I don't see why the second "=" is required.  "alias" would
be better if it just allowed arguments without special syntax.

On that topic you wrote:

Philippe> Also, an '=' character must be specified in the alias command before
Philippe> the LEADING-ARGS for consistency with set leading-args.
Philippe> This also ensures that the user cannot type a wrong command name
Philippe> that would be interpreted as leading args and/or cause 'mismatch'
Philippe> of length between ALIAS and COMMAND

I don't really see this as a big concern.  Presumably someone would
notice if their alias did not work properly.

thanks,
Tom
Reply | Threaded
Open this post in threaded view
|

Re: [RFA 0/3] Allow the user to define default leading args for commands and aliases

Philippe Waroquiers
On Wed, 2019-07-24 at 10:15 -0600, Tom Tromey wrote:

> > > > > > "Philippe" == Philippe Waroquiers <[hidden email]> writes:
>
> Philippe> Allow the user to define default leading args for commands and aliases.
> Philippe> This patch series implements, tests and documents the following commands:
>
> Thank you for the patches.
>
> Philippe>   set leading-args COMMAND [= LEADING-ARGS...]
> Philippe>   show leading-args [COMMAND]
> Philippe>   set enable-leading-args [on|off]
> Philippe>   show enable-leading-args
>
> Philippe> It also changes the alias command to be:
> Philippe>   alias [-a] [--] ALIAS = COMMAND [= LEADING-ARGS...]
>
> I don't really like the "leading args" approach, but I've put off
> responding to this because I wasn't sure how to articulate my
> objections.
>
> However, I never did come up with a really good way to talk about it.
>
> Partly, I think, the feature seems obscure.  It's preferable, in my
> view, to continue the approach gdb already takes; namely, adding "set"
> commands to affect the behavior of commands when desirable.
IMO, the "set <some setting>" commands and "set leading-args"
have 2 different objectives:
  * "set <some setting>" defines a specific setting that changes
    the behavior of a command.  Since Pedro's cli option framework,
    settings can have equivalent command args.
  * "set leading-args" allows to define default arguments for
     any command.
     It is not very clear to me how to do the second objective with
     the first.

>
>
> On the related commands:
>
> What is the rationale for "set enable-leading-args"?  This seems truly
> unnecessary.
'set leading-args' allows to define default arguments to the "standard"
gdb commands (such as "backtrace").

So, 'set enable-leading-args off' allows to go back to the default behavior
of such standard commands.
It typically would be used in the "with" command, e.g.:
   with enable-leading-args off -- backtrace

Now, this is only useful if we keep the functionality to define default
leading-args for standard GDB commands.

If "set leading-args" is really too obscure, we can just keep the
"alias" part of this patch.


>
> For "alias", I don't see why the second "=" is required.  "alias" would
> be better if it just allowed arguments without special syntax.
>
> On that topic you wrote:
>
> Philippe> Also, an '=' character must be specified in the alias command before
> Philippe> the LEADING-ARGS for consistency with set leading-args.
> Philippe> This also ensures that the user cannot type a wrong command name
> Philippe> that would be interpreted as leading args and/or cause 'mismatch'
> Philippe> of length between ALIAS and COMMAND
>
> I don't really see this as a big concern.  Presumably someone would
> notice if their alias did not work properly.
Ok, I will modify the patch to remove the need for this second "=".

If ever we see in the future that (sometimes) an "=" is needed to
avoid the confusion between a leading argument and a command name, we can
always modify the "alias" command to optionally accept an "=" to separate
the COMMAND from its arguments.

Philippe