default-args: allow to define default arguments for aliases

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

This patch modifies the 'alias' command so that default args can
be provided.
    (gdb) h alias
    Define a new command that is an alias of an existing command.
    Usage: alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...]
    ALIAS is the name of the alias command to create.
    COMMAND is the command being aliased to.

    Options:
      -a
        Specify that ALIAS is an abbreviation of COMMAND.
        Abbreviations are not used in command completion..

    GDB will automatically prepend the provided DEFAULT-ARGS to the list
    of arguments explicitly provided when using ALIAS.
    Use "help aliases" to list all user defined aliases and their default 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 --
    (gdb)

The way 'default-args' is implemented makes it trivial to set default
args also for GDB commands (such as "backtrace") and for GDB pre-defined
aliases (such as "bt").  It was however deemed better to not allow to
define default arguments for pre-defined commands and aliases, to avoid
users believing that e.g. default args for "backtrace" would apply to "bt".

If needed, default-args could be allowed for GDB predefined commands
and aliases by adding a command
'set default-args GDB_COMMAND_OR_PREDEFINED_ALIAS [DEFAULT-ARGS...]'.

* '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.

* Help and apropos commands show the definitions of the aliases
  that have default arguments, e.g.
        (gdb) help backtrace
        backtrace, btf, where, bt
          alias btf = backtrace -full -past-entry -past-main
        Print backtrace of all stack frames, or innermost COUNT frames.
        Usage: backtrace [OPTION]... [QUALIFIER]... [COUNT | -COUNT]

        Options:
          -entry-values no|only|preferred|if-needed|both|compact|default
            Set printing of function arguments at function entry.
        ...

gdb/ChangeLog
2020-06-22  Philippe Waroquiers  <philippe.waroquiers@skynet.be>

	* cli/cli-cmds.c (lookup_cmd_for_default_args)
	(alias_command_completer)
	(make_alias_options_def_group): New functions.
	(alias_opts, alias_option_defs): New struct and array.
	(alias_usage_error): Update usage.
	(alias_command): Handles optional DEFAULT-ARGS... arguments.
	Use option framework.
	(_initialize_cli_cmds): Update alias command help.
	Update aliases command help.
	(show_user):
	Add NULL for new default_args lookup_cmd argument.
	(valid_command_p): Rename to validate_aliased_command.
	Add NULL for new default_args lookup_cmd argument.  Verify that the
	aliased_command has no default args.
	* cli/cli-decode.c (help_cmd): Show aliases definitions.
	(lookup_cmd_1, lookup_cmd): New argument default_args.
	(add_alias_cmd):
	Add NULL for new default_args lookup_cmd argument.
	(print_help_for_command): Show default args under the layout
	 alias some_alias = some_aliased_cmd some_alias_default_arg.
	* cli/cli-decode.h (struct cmd_list_element): New member default_args.
	xfree default_args in destructor.
	* cli/cli-script.c (process_next_line, do_define_command):
	Add NULL for new default_args lookup_cmd argument.
	* command.h: Declare new default_args argument in lookup_cmd
	and lookup_cmd_1.
	* completer.c (complete_line_internal_1):
	Add NULL for new default_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 (execute_command): Prepend default_args if command has some.
	(set_verbose):
	Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
	* tracepoint.c (validate_actionline, encode_actions_1):
	Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
This commit is contained in:
Philippe Waroquiers
2019-06-19 12:49:55 +02:00
parent e822f2cda9
commit cf00cd6faf
16 changed files with 379 additions and 95 deletions

View File

@ -1,3 +1,47 @@
2020-06-22 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* cli/cli-cmds.c (lookup_cmd_for_default_args)
(alias_command_completer)
(make_alias_options_def_group): New functions.
(alias_opts, alias_option_defs): New struct and array.
(alias_usage_error): Update usage.
(alias_command): Handles optional DEFAULT-ARGS... arguments.
Use option framework.
(_initialize_cli_cmds): Update alias command help.
Update aliases command help.
(show_user):
Add NULL for new default_args lookup_cmd argument.
(valid_command_p): Rename to validate_aliased_command.
Add NULL for new default_args lookup_cmd argument. Verify that the
aliased_command has no default args.
* cli/cli-decode.c (help_cmd): Show aliases definitions.
(lookup_cmd_1, lookup_cmd): New argument default_args.
(add_alias_cmd):
Add NULL for new default_args lookup_cmd argument.
(print_help_for_command): Show default args under the layout
alias some_alias = some_aliased_cmd some_alias_default_arg.
* cli/cli-decode.h (struct cmd_list_element): New member default_args.
xfree default_args in destructor.
* cli/cli-script.c (process_next_line, do_define_command):
Add NULL for new default_args lookup_cmd argument.
* command.h: Declare new default_args argument in lookup_cmd
and lookup_cmd_1.
* completer.c (complete_line_internal_1):
Add NULL for new default_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 (execute_command): Prepend default_args if command has some.
(set_verbose):
Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
* tracepoint.c (validate_actionline, encode_actions_1):
Add NULL for new default_args lookup_cmd or lookup_cmd_1 argument.
2020-06-22 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* jit.c (jit_read_descriptor): Use bool as the return type.

View File

@ -50,6 +50,7 @@
#include "cli/cli-cmds.h"
#include "cli/cli-style.h"
#include "cli/cli-utils.h"
#include "cli/cli-style.h"
#include "extension.h"
#include "gdbsupport/pathstuff.h"
@ -221,6 +222,7 @@ with_command_1 (const char *set_cmd_prefix,
nested_cmd = repeat_previous ();
cmd_list_element *set_cmd = lookup_cmd (&args, setlist, set_cmd_prefix,
nullptr,
/*allow_unknown=*/ 0,
/*ignore_help_classes=*/ 1);
gdb_assert (set_cmd != nullptr);
@ -315,7 +317,54 @@ with_command_completer (struct cmd_list_element *ignore,
with_command_completer_1 ("set ", tracker, text);
}
/* Look up the contents of TEXT as a command usable with default args.
Throws an error if no such command is found.
Return the found command and advances TEXT past 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_default_args (const char **text,
struct cmd_list_element **prefix_cmd)
{
const char *orig_text = *text;
struct cmd_list_element *lcmd;
if (*text == nullptr || skip_spaces (*text) == nullptr)
error (_("ALIAS missing."));
/* We first use lookup_cmd to verify TEXT unambiguously identifies
a command. */
lcmd = lookup_cmd (text, cmdlist, "", NULL,
/*allow_unknown=*/ 0,
/*ignore_help_classes=*/ 1);
/* Note that we accept default 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 ids, and is also the prefix command for
thread apply all. */
/* We have an unambiguous command for which default args
can be specified. What remains after having found LCMD
is either spaces, or the default args character. */
/* We then use lookup_cmd_composition to detect if the user
has specified an alias, and find the possible prefix_cmd
of cmd. */
struct cmd_list_element *alias, *cmd;
lookup_cmd_composition
(std::string (orig_text, *text - orig_text).c_str (),
&alias, prefix_cmd, &cmd);
gdb_assert (cmd != nullptr);
gdb_assert (cmd == lcmd);
if (alias != nullptr)
cmd = alias;
return cmd;
}
/* Provide documentation on command or list given by COMMAND. FROM_TTY
is ignored. */
@ -1541,7 +1590,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);
@ -1573,6 +1622,71 @@ apropos_command (const char *arg, int from_tty)
apropos_cmd (gdb_stdout, cmdlist, verbose, pattern, "");
}
/* The options for the "alias" command. */
struct alias_opts
{
/* For "-a". */
bool abbrev_flag = false;
};
static const gdb::option::option_def alias_option_defs[] = {
gdb::option::flag_option_def<alias_opts> {
"a",
[] (alias_opts *opts) { return &opts->abbrev_flag; },
N_("Specify that ALIAS is an abbreviation of COMMAND.\n\
Abbreviations are not used in command completion."),
},
};
/* Create an option_def_group for the "alias" options, with
A_OPTS as context. */
static gdb::option::option_def_group
make_alias_options_def_group (alias_opts *a_opts)
{
return {{alias_option_defs}, a_opts};
}
/* Completer for the "alias_command". */
static void
alias_command_completer (struct cmd_list_element *ignore,
completion_tracker &tracker,
const char *text, const char *word)
{
const auto grp = make_alias_options_def_group (nullptr);
tracker.set_use_custom_word_point (true);
if (gdb::option::complete_options
(tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp))
return;
const char *delim = strchr (text, '=');
/* If we're past the "=" delimiter, complete the
"alias ALIAS = COMMAND [DEFAULT-ARGS...]" as if the user is
typing COMMAND DEFAULT-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);
complete_nested_command_line (tracker, new_text.c_str ());
return;
}
/* We're not yet past the "=" delimiter. Complete a command, as
the user might type an alias following a prefix command. */
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.
@ -1600,24 +1714,29 @@ argv_to_string (char **argv, int n)
}
/* Subroutine of alias_command to simplify it.
Return true if COMMAND exists, unambiguously. Otherwise false. */
Verifies that COMMAND can have an alias:
COMMAND must exist.
COMMAND must not have default args.
This last condition is to avoid the following:
alias aaa = backtrace -full
alias bbb = aaa -past-main
as (at least currently), alias default args are not cumulative
and the user would expect bbb to execute 'backtrace -full -past-main'
while it will execute 'backtrace -past-main'. */
static bool
valid_command_p (const char *command)
static void
validate_aliased_command (const char *command)
{
struct cmd_list_element *c;
std::string default_args;
c = lookup_cmd_1 (& command, cmdlist, NULL, 1);
c = lookup_cmd_1 (& command, cmdlist, NULL, &default_args, 1);
if (c == NULL || c == (struct cmd_list_element *) -1)
return false;
error (_("Invalid command to alias to: %s"), command);
/* This is the slightly tricky part.
lookup_cmd_1 will return a pointer to the last part of COMMAND
to match, leaving COMMAND pointing at the remainder. */
while (*command == ' ' || *command == '\t')
++command;
return *command == '\0';
if (!default_args.empty ())
error (_("Cannot define an alias of an alias that has default args"));
}
/* Called when "alias" was incorrectly used. */
@ -1625,7 +1744,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 [DEFAULT-ARGS...]"));
}
/* Make an alias of an existing command. */
@ -1633,8 +1752,13 @@ alias_usage_error (void)
static void
alias_command (const char *args, int from_tty)
{
alias_opts a_opts;
auto grp = make_alias_options_def_group (&a_opts);
gdb::option::process_options
(&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp);
int i, alias_argc, command_argc;
int abbrev_flag = 0;
const char *equals;
const char *alias, *command;
@ -1645,24 +1769,18 @@ 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 *default_args = equals + 1;
struct cmd_list_element *c_command_prefix;
lookup_cmd_for_default_args (&default_args, &c_command_prefix);
std::string command_argv_str (equals + 1,
default_args == nullptr
? strlen (equals + 1)
: default_args - equals - 1);
gdb_argv command_argv (command_argv_str.c_str ());
char **alias_argv = built_alias_argv.get ();
while (alias_argv[0] != NULL)
{
if (strcmp (alias_argv[0], "-a") == 0)
{
++alias_argv;
abbrev_flag = 1;
}
else if (strcmp (alias_argv[0], "--") == 0)
{
++alias_argv;
break;
}
else
break;
}
if (alias_argv[0] == NULL || command_argv[0] == NULL
|| *alias_argv[0] == '\0' || *command_argv[0] == '\0')
@ -1682,14 +1800,13 @@ alias_command (const char *args, int from_tty)
alias_argc = countargv (alias_argv);
command_argc = command_argv.count ();
/* COMMAND must exist.
/* COMMAND must exist, and cannot have default args.
Reconstruct the command to remove any extraneous spaces,
for better error messages. */
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);
validate_aliased_command (command);
/* ALIAS must not exist. */
std::string alias_string (argv_to_string (alias_argv, alias_argc));
@ -1718,6 +1835,8 @@ alias_command (const char *args, int from_tty)
}
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
@ -1730,8 +1849,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,
a_opts.abbrev_flag);
}
else
{
@ -1751,19 +1870,29 @@ 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]),
alias_cmd = add_alias_cmd (xstrdup (alias_argv[alias_argc - 1]),
command_argv[command_argc - 1],
class_alias, abbrev_flag, c_command->prefixlist);
class_alias, a_opts.abbrev_flag,
c_command->prefixlist);
}
gdb_assert (alias_cmd != nullptr);
gdb_assert (alias_cmd->default_args.empty ());
if (default_args != nullptr)
{
default_args = skip_spaces (default_args);
alias_cmd->default_args = default_args;
}
}
@ -1938,7 +2067,7 @@ setting_cmd (const char *fnname, struct cmd_list_element *showlist,
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);
cmd_list_element *cmd = lookup_cmd (&a0, showlist, "", NULL, -1, 0);
if (cmd == nullptr || cmd_type (cmd) != show_cmd)
error (_("First argument of %s must be a "
@ -2128,7 +2257,7 @@ well documented as user commands."),
&cmdlist);
add_cmd ("obscure", class_obscure, _("Obscure features."), &cmdlist);
add_cmd ("aliases", class_alias,
_("Aliases of other commands."), &cmdlist);
_("User-defined aliases of other commands."), &cmdlist);
add_cmd ("user-defined", class_user, _("\
User-defined commands.\n\
The commands in this class are those defined by the user.\n\
@ -2454,19 +2583,37 @@ When 'on', each command is displayed as it is executed."),
NULL,
&setlist, &showlist);
c = add_com ("alias", class_support, alias_command, _("\
const auto alias_opts = make_alias_options_def_group (nullptr);
static std::string alias_help
= gdb::option::build_help (_("\
Define a new command that is an alias of an existing command.\n\
Usage: alias [-a] [--] ALIAS = COMMAND\n\
Usage: alias [-a] [--] ALIAS = COMMAND [DEFAULT-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 be used in command completion.\n\
\n\
Options:\n\
%OPTIONS%\n\
\n\
GDB will automatically prepend the provided DEFAULT-ARGS to the list\n\
of arguments explicitly provided when using ALIAS.\n\
Use \"help aliases\" to list all user defined aliases and their default args.\n\
\n\
Examples:\n\
Make \"spe\" an alias of \"set print elements\":\n\
alias spe = 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 --"),
alias_opts);
c = add_com ("alias", class_support, alias_command,
alias_help.c_str ());
set_cmd_completer_handle_brkchars (c, alias_command_completer);
const char *source_help_text = xstrprintf (_("\
Read commands from a file named FILE.\n\

View File

@ -337,7 +337,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);
}
@ -1040,6 +1040,40 @@ fput_command_name_styled (struct cmd_list_element *c, struct ui_file *stream)
fprintf_styled (stream, title_style.style (), "%s%s", prefixname, c->name);
}
/* Print the definition of alias C using title style for alias
and aliased command. */
static void
fput_alias_definition_styled (struct cmd_list_element *c,
struct ui_file *stream)
{
gdb_assert (c->cmd_pointer != nullptr);
fputs_filtered (" alias ", stream);
fput_command_name_styled (c, stream);
fprintf_filtered (stream, " = ");
fput_command_name_styled (c->cmd_pointer, stream);
fprintf_filtered (stream, " %s\n", c->default_args.c_str ());
}
/* Print the definition of the aliases of CMD that have default args. */
static void
fput_aliases_definition_styled (struct cmd_list_element *cmd,
struct ui_file *stream)
{
if (cmd->aliases != nullptr)
{
for (cmd_list_element *iter = cmd->aliases;
iter;
iter = iter->alias_chain)
{
if (!iter->default_args.empty ())
fput_alias_definition_styled (iter, stream);
}
}
}
/* If C has one or more aliases, style print the name of C and
the name of its aliases, separated by commas.
If ALWAYS_FPUT_C_NAME, print the name of C even if it has no aliases.
@ -1081,12 +1115,21 @@ print_doc_of_command (struct cmd_list_element *c, const char *prefix,
if (verbose)
fputs_filtered ("\n", stream);
fput_command_names_styled (c, true, " -- ", stream);
fput_command_names_styled (c, true,
verbose ? "" : " -- ", stream);
if (verbose)
{
fputs_filtered ("\n", stream);
fput_aliases_definition_styled (c, stream);
fputs_highlighted (c->doc, highlight, stream);
fputs_filtered ("\n", stream);
}
else
{
print_doc_line (stream, c->doc, false);
fputs_filtered ("\n", stream);
fput_aliases_definition_styled (c, stream);
}
}
/* Recursively walk the commandlist structures, and print out the
@ -1183,7 +1226,7 @@ help_cmd (const char *command, struct ui_file *stream)
}
const char *orig_command = command;
c = lookup_cmd (&command, cmdlist, "", 0, 0);
c = lookup_cmd (&command, cmdlist, "", NULL, 0, 0);
if (c == 0)
return;
@ -1205,6 +1248,7 @@ help_cmd (const char *command, struct ui_file *stream)
/* If the user asked 'help somecommand' and there is no alias,
the false indicates to not output the (single) command name. */
fput_command_names_styled (c, false, "\n", stream);
fput_aliases_definition_styled (c, stream);
fputs_filtered (c->doc, stream);
fputs_filtered ("\n", stream);
@ -1341,7 +1385,7 @@ help_all (struct ui_file *stream)
fprintf_filtered (stream, "\nUnclassified commands\n\n");
seen_unclassified = 1;
}
print_help_for_command (c, 1, stream);
print_help_for_command (c, true, stream);
}
}
@ -1399,6 +1443,9 @@ print_help_for_command (struct cmd_list_element *c,
fput_command_names_styled (c, true, " -- ", stream);
print_doc_line (stream, c->doc, false);
fputs_filtered ("\n", stream);
if (!c->default_args.empty ())
fput_alias_definition_styled (c, stream);
fput_aliases_definition_styled (c, stream);
if (recurse
&& c->prefixlist != 0
@ -1582,8 +1629,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 DEFAULT_ARGS is not null, *DEFAULT_ARGS is set to the found command
default args (possibly empty).
If the located command was an abbreviation, this routine returns the base
command of the abbreviation.
command of the abbreviation. Note that *DEFAULT_ARGS will contain the
default args defined for the alias.
It does no error reporting whatsoever; control will always return
to the superior routine.
@ -1610,11 +1661,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, std::string *default_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')
@ -1646,10 +1699,12 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
if (nfound > 1)
{
if (result_list != NULL)
if (result_list != nullptr)
/* Will be modified in calling routine
if we know what the prefix command is. */
*result_list = 0;
if (default_args != nullptr)
*default_args = std::string ();
return CMD_LIST_AMBIGUOUS; /* Ambiguous. */
}
@ -1668,19 +1723,27 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
if (found->deprecated_warn_user)
deprecated_cmd_warning (line);
/* Return the default_args of the alias, not the default_args
of the command it is pointing to. */
if (default_args != nullptr)
*default_args = found->default_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);
default_args, ignore_help_classes);
if (!c)
{
/* Didn't find anything; this is as far as we got. */
if (result_list != NULL)
if (result_list != nullptr)
*result_list = clist;
if (!found_alias && default_args != nullptr)
*default_args = found->default_args;
return found;
}
else if (c == CMD_LIST_AMBIGUOUS)
@ -1688,13 +1751,16 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
/* We've gotten this far properly, but the next step is
ambiguous. We need to set the result list to the best
we've found (if an inferior hasn't already set it). */
if (result_list != NULL)
if (result_list != nullptr)
if (!*result_list)
/* This used to say *result_list = *found->prefixlist.
If that was correct, need to modify the documentation
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 default_args args. */
if (default_args != nullptr)
*default_args = std::string ();
return c;
}
else
@ -1705,8 +1771,10 @@ lookup_cmd_1 (const char **text, struct cmd_list_element *clist,
}
else
{
if (result_list != NULL)
if (result_list != nullptr)
*result_list = clist;
if (!found_alias && default_args != nullptr)
*default_args = found->default_args;
return found;
}
}
@ -1726,8 +1794,13 @@ 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 *DEFAULT_ARGS (if DEFAULT_ARGS is not null) to the default
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 default 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,
@ -1741,6 +1814,7 @@ undef_cmd_error (const char *cmdtype, const char *q)
struct cmd_list_element *
lookup_cmd (const char **line, struct cmd_list_element *list,
const char *cmdtype,
std::string *default_args,
int allow_unknown, int ignore_help_classes)
{
struct cmd_list_element *last_list = 0;
@ -1752,7 +1826,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, default_args, ignore_help_classes);
if (!c)
{

View File

@ -183,6 +183,10 @@ struct cmd_list_element
/* Hook for another command to be executed after this command. */
struct cmd_list_element *hook_post = nullptr;
/* Default arguments to automatically prepend to the user
provided arguments when running this command or alias. */
std::string default_args;
/* Nonzero identifies a prefix command. For them, the address
of the variable containing the list of subcommands. */
struct cmd_list_element **prefixlist = nullptr;

View File

@ -974,7 +974,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';
@ -1331,7 +1331,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 ());
@ -1387,7 +1387,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;
@ -1432,7 +1432,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)
@ -1518,7 +1518,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);
@ -1566,7 +1566,7 @@ define_prefix_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 != nullptr && strcmp (comname, c->name) != 0)
c = nullptr;

View File

@ -291,11 +291,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 *,
std::string *,
int, int);
extern struct cmd_list_element *lookup_cmd_1 (const char **,
struct cmd_list_element *,
struct cmd_list_element **,
std::string *,
int);
extern struct cmd_list_element *deprecate_cmd (struct cmd_list_element *,

View File

@ -1385,7 +1385,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. */

View File

@ -512,7 +512,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);

View File

@ -466,13 +466,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;
@ -969,7 +969,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;

View File

@ -3052,7 +3052,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_run, 0, &cmdlist);
@ -3065,7 +3065,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);
@ -3084,7 +3084,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);

View File

@ -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,

View File

@ -390,7 +390,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."),

View File

@ -569,12 +569,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);
}

View File

@ -14424,10 +14424,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,

View File

@ -579,6 +579,8 @@ execute_command (const char *p, int from_tty)
{
const char *cmd = p;
const char *arg;
std::string default_args;
std::string default_args_and_arg;
int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
line = p;
@ -586,15 +588,26 @@ 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, "", &default_args, 0, 1);
p = cmd;
scoped_restore save_repeat_args
= make_scoped_restore (&repeat_arguments, nullptr);
const char *args_pointer = p;
if (!default_args.empty ())
{
if (*p != '\0')
default_args_and_arg = default_args + ' ' + p;
else
default_args_and_arg = default_args;
arg = default_args_and_arg.c_str ();
}
else
{
/* Pass null arg rather than an empty one. */
arg = *p ? p : 0;
arg = *p == '\0' ? nullptr : p;
}
/* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy
while the is_complete_command(cfunc) test is just plain
@ -1957,7 +1970,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)

View File

@ -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);
@ -1303,7 +1303,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);
@ -2673,7 +2673,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);