Message ID | 20190805205159.31689-2-philippe.waroquiers@skynet.be |
---|---|
State | New |
Headers | show |
Hi Philippe, Just a few comments below of things that I spotted on a quick initial skim. I'm not sure I'll have more time for review today. Design comment off hand: did you consider storing the default arguments on a separate map instead of recording them in the commands themselves? On 8/5/19 9:51 PM, Philippe Waroquiers wrote: > 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. preprend -> prepend > 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. > Nice, I like having completers. :-) > * 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. "directly accepts" -> "directly accept" > Note that the help alias assumes this patch will be pushed after the > 'with command' is pushed. You can remove this sentence now. > > (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'. > The main intended usage of this setting is to use it in the "with" > command: as set leading-args can add arguments to standard GDB commands, > it is useful (e.g. in user defined commands) to be able to go back > to the 'standard' behaviour of a command. > > gdb/ChangeLog > 2019-08-04 Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * 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, > make_alias_options_def_group): New functions. Tabs vs spaces. Also, when you need to break between multiple lines, close parens, and reopen on next line, like: * 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) (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 LEADING-ARGS... arguments. > Use option framework. > (_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. > (print_help_for_command): Show leading args. > * 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. Spurious extra space. > * 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. Spurious extra space. > (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 | 326 ++++++++++++++++++++++++++++++++++---- > gdb/cli/cli-decode.c | 95 +++++++++-- > 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, 446 insertions(+), 70 deletions(-) > > diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c > index 0b62622e88..b33527b360 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 "gdbsupport/pathstuff.h" > @@ -227,6 +228,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); > @@ -321,6 +323,149 @@ with_command_completer (struct cmd_list_element *ignore, > with_command_completer_1 ("set ", tracker, text); > } > > +/* 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); > + > + 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 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_leading_args (const char **text, > + struct cmd_list_element **prefix_cmd) > +{ > + const char *orig_text = *text; > + 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. */ > + lcmd = lookup_cmd (text, 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 "list of thread id" -> "list of thread ids" > + 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 the leading args character. */ "the the" -> "the" > + > + /* 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 > + (std::string (orig_text, *text - orig_text).c_str (), > + &alias, prefix_cmd, &cmd); We don't generally use "(void)" to "suppress" the return value. You'll only find it in really old code. > + 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 *leading_args = skip_spaces (arg); > + > + if (*leading_args == '\0') > + 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> "showing C name" -> "showing C's name" > + 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 ? ? goes on next line. > + "<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. "have have" -> "that have" > + 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) Declare the var in the loop, and might as well drop struct while at it: /* Walk through the commands. */ for (cmd_list_element *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) You can just write: if (skip_spaces (arg) != nullptr) since skip_spaces already handles nullptr. (Saw the same thing in other spots in the patch.) > + { > + 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 ? ? on next line. Or merge both lines into one assuming it fits. > + "" : prefix_cmd->prefixname, > + false); > + } > + else > + show_leading_args_command_1 (cmdlist, ""); > +} > + > > /* Provide documentation on command or list given by COMMAND. FROM_TTY > is ignored. */ > @@ -1536,7 +1681,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); > @@ -1568,6 +1713,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". */ > + int abbrev_flag = 0; > +}; > + > +static const gdb::option::option_def alias_option_defs[] = { > + > + gdb::option::flag_option_def<alias_opts> { > + "a", Given we accept abbreviations, should that be "abbrev" or "abbreviation" instead of "a" ? > + [] (alias_opts *opts) { return &opts->abbrev_flag; }, > + N_("Specify that ALIAS is an abbreviation of COMMAND.\n\ > +Abbreviations are not shown in command lists displayed by the 'help' command."), > + }, > + > +}; > + > +/* Create an option_def_group for the "alias" options, with > + IT_OPTS as context. */ IT_OPTS -> A_OPTS > + > +static inline 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 = strstr (text, "="); > + > + /* If we're past the "=" delimiter, complete the > + "alias ALIAS = COMMAND [LEADING-ARGS...]" as if the user is > + typing 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); > + 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. > @@ -1602,7 +1812,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; > @@ -1620,7 +1830,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...]")); For this alias use case, I wonder whether talking about "leading" is really useful. I'd find this totally natural and intuitive: error (_("Usage: alias [-a] [--] ALIAS = COMMAND [ARGS...]")); > } > > /* Make an alias of an existing command. */ > @@ -1628,8 +1838,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; > > @@ -1640,24 +1855,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 *leading_args = equals + 1; > + struct cmd_list_element *c_command_prefix; > + > + lookup_cmd_for_leading_args (&leading_args, &c_command_prefix); > + std::string command_argv_str (equals + 1, > + leading_args == nullptr ? > + strlen (equals + 1) > + : leading_args - equals - 1); (leading_args == nullptr ? strlen (equals + 1) : 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) > - { > - 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') > @@ -1692,6 +1901,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 > > @@ -1704,8 +1915,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 > { > @@ -1725,19 +1936,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, a_opts.abbrev_flag, > + c_command->prefixlist); > + } > + > + gdb_assert (alias_cmd); > + gdb_assert (alias_cmd->leading_args == nullptr); > + if (leading_args != nullptr) > + { > + leading_args = skip_spaces (leading_args); > + > + if (*leading_args != '\0') > + alias_cmd->leading_args = xstrdup (leading_args); > } > } > > @@ -2051,6 +2273,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\ "preprended" -> "prepended" > +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); > > @@ -2202,19 +2444,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 [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\ > +Options:\n\ > +%OPTIONS%\ > +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\ > + 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\ > diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c > index edea3ad021..cc93b9ac6c 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); Drop the (void). > + 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"); > @@ -1262,6 +1298,13 @@ print_help_for_command (struct cmd_list_element *c, const char *prefix, > fputs_filtered (" -- ", stream); > print_doc_line (stream, c->doc); > fputs_filtered ("\n", stream); > + if (c->leading_args != nullptr) > + { > + fputs_filtered (" leading-args ", stream); > + fprintf_styled (stream, title_style.style (), > + "%s%s", prefix, c->name); > + fprintf_filtered (stream, " = %s\n", c->leading_args); > + } > > if (recurse > && c->prefixlist != 0 > @@ -1409,8 +1452,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 +1484,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 +1526,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 +1543,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 +1581,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; > + */ Leftover? > return c; > } > } > @@ -1534,6 +1600,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 +1621,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 +1654,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 16a6ce9f66..52089022b5 100644 > --- a/gdb/cli/cli-decode.h > +++ b/gdb/cli/cli-decode.h > @@ -69,6 +69,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); > @@ -176,6 +178,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 4fc9c70259..e5f944f0bd 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 2c608048d5..1df4d7fb57 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 07facfb012..b88bdbdeca 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 0ad9b91677..cc711a524a 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 42c730e48f..249725a263 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 60f81b3bf8..7faac35cc7 100644 > --- a/gdb/top.c > +++ b/gdb/top.c > @@ -535,6 +535,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. */ > > @@ -563,6 +568,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; > @@ -570,15 +577,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); This statement seems unnecessary, since both branches below overwrite leading_args_and_arg again. > + 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; > + } Thanks, Pedro Alves
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 0b62622e88..b33527b360 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 "gdbsupport/pathstuff.h" @@ -227,6 +228,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); @@ -321,6 +323,149 @@ with_command_completer (struct cmd_list_element *ignore, with_command_completer_1 ("set ", tracker, text); } +/* 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); + + 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 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_leading_args (const char **text, + struct cmd_list_element **prefix_cmd) +{ + const char *orig_text = *text; + 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. */ + lcmd = lookup_cmd (text, 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 the leading 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. */ + (void) 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; +} + +/* 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 *leading_args = skip_spaces (arg); + + if (*leading_args == '\0') + 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. */ @@ -1536,7 +1681,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); @@ -1568,6 +1713,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". */ + int abbrev_flag = 0; +}; + +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 shown in command lists displayed by the 'help' command."), + }, + +}; + +/* Create an option_def_group for the "alias" options, with + IT_OPTS as context. */ + +static inline 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 = strstr (text, "="); + + /* If we're past the "=" delimiter, complete the + "alias ALIAS = COMMAND [LEADING-ARGS...]" as if the user is + typing 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); + 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. @@ -1602,7 +1812,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; @@ -1620,7 +1830,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. */ @@ -1628,8 +1838,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; @@ -1640,24 +1855,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 *leading_args = equals + 1; + struct cmd_list_element *c_command_prefix; + + lookup_cmd_for_leading_args (&leading_args, &c_command_prefix); + std::string command_argv_str (equals + 1, + leading_args == nullptr ? + strlen (equals + 1) + : 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) - { - 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') @@ -1692,6 +1901,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 @@ -1704,8 +1915,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 { @@ -1725,19 +1936,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, a_opts.abbrev_flag, + c_command->prefixlist); + } + + gdb_assert (alias_cmd); + gdb_assert (alias_cmd->leading_args == nullptr); + if (leading_args != nullptr) + { + leading_args = skip_spaces (leading_args); + + if (*leading_args != '\0') + alias_cmd->leading_args = xstrdup (leading_args); } } @@ -2051,6 +2273,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); @@ -2202,19 +2444,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 [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\ +Options:\n\ +%OPTIONS%\ +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\ + 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\ diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index edea3ad021..cc93b9ac6c 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"); @@ -1262,6 +1298,13 @@ print_help_for_command (struct cmd_list_element *c, const char *prefix, fputs_filtered (" -- ", stream); print_doc_line (stream, c->doc); fputs_filtered ("\n", stream); + if (c->leading_args != nullptr) + { + fputs_filtered (" leading-args ", stream); + fprintf_styled (stream, title_style.style (), + "%s%s", prefix, c->name); + fprintf_filtered (stream, " = %s\n", c->leading_args); + } if (recurse && c->prefixlist != 0 @@ -1409,8 +1452,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 +1484,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 +1526,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 +1543,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 +1581,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 +1600,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 +1621,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 +1654,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 16a6ce9f66..52089022b5 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -69,6 +69,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); @@ -176,6 +178,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 4fc9c70259..e5f944f0bd 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 2c608048d5..1df4d7fb57 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 07facfb012..b88bdbdeca 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 0ad9b91677..cc711a524a 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 42c730e48f..249725a263 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 60f81b3bf8..7faac35cc7 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -535,6 +535,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. */ @@ -563,6 +568,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; @@ -570,15 +577,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 @@ -1894,7 +1914,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) @@ -2124,6 +2144,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 075bd4c977..54a1f22336 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);