diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4b7e506697..d123622a42 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2019-11-30 Philippe Waroquiers + + * cli/cli-script.c (do_define_command): Ensure a redefined + prefix command is kept as a prefix command. + (define_prefix_command): New function. + (show_user_1): Report user defined prefixes. + (_initialize_cli_script): Create the new 'define-prefix' command. + Add completers for 'define' and 'document'. + * top.c (execute_command): If command is a user-defined prefix only + command, report the list of commands for this prefix command. + 2019-11-29 Tankut Baris Aktemur * valops.c (find_oload_champ): Improve debug output. diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 06cdcd6bfe..55dcb3435b 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -29,6 +29,7 @@ #include "cli/cli-cmds.h" #include "cli/cli-decode.h" #include "cli/cli-script.h" +#include "cli/cli-style.h" #include "extension.h" #include "interps.h" @@ -1395,7 +1396,17 @@ do_define_command (const char *comname, int from_tty, int q; if (c->theclass == class_user || c->theclass == class_alias) - q = query (_("Redefine command \"%s\"? "), c->name); + { + /* if C is a prefix command that was previously defined, + tell the user its subcommands will be kept, and ask + if ok to redefine the command. */ + if (c->prefixlist != nullptr) + q = (c->user_commands.get () == nullptr + || query (_("Keeping subcommands of prefix command \"%s\".\n" + "Redefine command \"%s\"? "), c->name, c->name)); + else + q = query (_("Redefine command \"%s\"? "), c->name); + } else q = query (_("Really redefine built-in command \"%s\"? "), c->name); if (!q) @@ -1416,7 +1427,7 @@ do_define_command (const char *comname, int from_tty, hook_type = CMD_POST_HOOK; hook_name_size = HOOK_POST_LEN; } - + if (hook_type != CMD_NO_HOOK) { /* Look up cmd it hooks, and verify that we got an exact match. */ @@ -1446,10 +1457,27 @@ do_define_command (const char *comname, int from_tty, else cmds = *commands; - newc = add_cmd (comname, class_user, user_defined_command, - (c && c->theclass == class_user) - ? c->doc : xstrdup ("User-defined."), list); - newc->user_commands = std::move (cmds); + { + struct cmd_list_element **c_prefixlist + = c == nullptr ? nullptr : c->prefixlist; + const char *c_prefixname = c == nullptr ? nullptr : c->prefixname; + + newc = add_cmd (comname, class_user, user_defined_command, + (c != nullptr && c->theclass == class_user) + ? c->doc : xstrdup ("User-defined."), list); + newc->user_commands = std::move (cmds); + + /* If we define or re-define a command that was previously defined + as a prefix, keep the prefix information. */ + if (c_prefixlist != nullptr) + { + newc->prefixlist = c_prefixlist; + newc->prefixname = c_prefixname; + /* allow_unknown: see explanation in equivalent logic in + define_prefix_command (). */ + newc->allow_unknown = newc->user_commands.get () != nullptr; + } + } /* If this new command is a hook, then mark both commands as being tied. */ @@ -1524,6 +1552,54 @@ document_command (const char *comname, int from_tty) c->doc = doc; } } + +/* Implementation of the "define-prefix" command. */ + +static void +define_prefix_command (const char *comname, int from_tty) +{ + struct cmd_list_element *c, **list; + const char *tem; + const char *comfull; + + comfull = comname; + list = validate_comname (&comname); + + /* Look it up, and verify that we got an exact match. */ + tem = comname; + c = lookup_cmd (&tem, *list, "", -1, 1); + if (c != nullptr && strcmp (comname, c->name) != 0) + c = nullptr; + + if (c != nullptr && c->theclass != class_user) + error (_("Command \"%s\" is built-in."), comfull); + + if (c != nullptr && c->prefixlist != nullptr) + { + /* c is already a user defined prefix command. */ + return; + } + + /* If the command does not exist at all, create it. */ + if (c == nullptr) + { + comname = xstrdup (comname); + c = add_cmd (comname, class_user, user_defined_command, + xstrdup ("User-defined."), list); + } + + /* Allocate the c->prefixlist, which marks the command as a prefix + command. */ + c->prefixlist = new struct cmd_list_element*; + *(c->prefixlist) = nullptr; + c->prefixname = xstrprintf ("%s ", comfull); + /* If the prefix command C is not a command, then it must be followed + by known subcommands. Otherwise, if C is also a normal command, + it can be followed by C args that must not cause a 'subcommand' + not recognised error, and thus we must allow unknown. */ + c->allow_unknown = c->user_commands.get () != nullptr; +} + /* Used to implement source_command. */ @@ -1564,7 +1640,21 @@ void show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, struct ui_file *stream) { - struct command_line *cmdlines; + if (cli_user_command_p (c)) + { + struct command_line *cmdlines = c->user_commands.get (); + + fprintf_filtered (stream, "User %scommand \"", + c->prefixlist == NULL ? "" : "prefix "); + fprintf_styled (stream, title_style.style (), "%s%s", + prefix, name); + fprintf_filtered (stream, "\":\n"); + if (cmdlines) + { + print_command_lines (current_uiout, cmdlines, 1); + fputs_filtered ("\n", stream); + } + } if (c->prefixlist != NULL) { @@ -1573,25 +1663,23 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, for (c = *c->prefixlist; c != NULL; c = c->next) if (c->theclass == class_user || c->prefixlist != NULL) show_user_1 (c, prefixname, c->name, gdb_stdout); - return; } - cmdlines = c->user_commands.get (); - fprintf_filtered (stream, "User command \"%s%s\":\n", prefix, name); - - if (!cmdlines) - return; - print_command_lines (current_uiout, cmdlines, 1); - fputs_filtered ("\n", stream); } void _initialize_cli_script (void) { - add_com ("document", class_support, document_command, _("\ + struct cmd_list_element *c; + + /* "document", "define" and "define-prefix" use command_completer, + as this helps the user to either type the command name and/or + its prefixes. */ + c = add_com ("document", class_support, document_command, _("\ Document a user-defined command.\n\ Give command name as argument. Give documentation on following lines.\n\ End with a line of just \"end\".")); + set_cmd_completer (c, command_completer); define_cmd_element = add_com ("define", class_support, define_command, _("\ Define a new command name. Command name is argument.\n\ Definition appears on following lines, one command per line.\n\ @@ -1600,6 +1688,14 @@ Use the \"document\" command to give documentation for the new command.\n\ Commands defined in this way may accept an unlimited number of arguments\n\ accessed via $arg0 .. $argN. $argc tells how many arguments have\n\ been passed.")); + set_cmd_completer (define_cmd_element, command_completer); + c = add_com ("define-prefix", class_support, define_prefix_command, + _("\ +Define or mark a command as a user-defined prefix command.\n\ +User defined prefix commands can be used as prefix commands for\n\ +other user defined commands.\n\ +If the command already exists, it is changed to a prefix command.")); + set_cmd_completer (c, command_completer); while_cmd_element = add_com ("while", class_support, while_command, _("\ Execute nested commands WHILE the conditional expression is non zero.\n\ diff --git a/gdb/top.c b/gdb/top.c index 2953eac819..e8ed3b2747 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -627,6 +627,18 @@ execute_command (const char *p, int from_tty) /* c->user_commands would be NULL in the case of a python command. */ if (c->theclass == class_user && c->user_commands) execute_user_command (c, arg); + else if (c->theclass == class_user + && c->prefixlist && !c->allow_unknown) + /* If this is a user defined prefix that does not allow unknown + (in other words, C is a prefix command and not a command + that can be followed by its args), report the list of + subcommands. */ + { + printf_unfiltered + ("\"%.*s\" must be followed by the name of a subcommand.\n", + (int) strlen (c->prefixname) - 1, c->prefixname); + help_list (*c->prefixlist, c->prefixname, all_commands, gdb_stdout); + } else if (c->type == set_cmd) do_set_command (arg, from_tty, c); else if (c->type == show_cmd)