From patchwork Sun Sep 29 20:54:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philippe Waroquiers X-Patchwork-Id: 34715 Received: (qmail 98156 invoked by alias); 29 Sep 2019 20:54:42 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 98077 invoked by uid 89); 29 Sep 2019 20:54:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mailsec114.isp.belgacom.be Received: from mailsec114.isp.belgacom.be (HELO mailsec114.isp.belgacom.be) (195.238.20.110) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 29 Sep 2019 20:54:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=skynet.be; i=@skynet.be; q=dns/txt; s=securemail; t=1569790478; x=1601326478; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iI3ZoD8LJiYIvdSpc3D5Zq6v5aWM/mx/hUR0mcjIWEY=; b=nogEFnw0Gx05dsTjxY/y3ejoRvfKZe1S/AcAt1GkvkyuixrwYu9d30U3 yEhi+2qeJrgn9y6OqbdfEifDm8cEzw==; Received: from 255.38-242-81.adsl-dyn.isp.belgacom.be (HELO md.home) ([81.242.38.255]) by relay.skynet.be with ESMTP/TLS/DHE-RSA-AES128-GCM-SHA256; 29 Sep 2019 22:54:32 +0200 From: Philippe Waroquiers To: gdb-patches@sourceware.org Cc: Philippe Waroquiers Subject: [RFA 1/4] Implement user defined prefix. Date: Sun, 29 Sep 2019 22:54:24 +0200 Message-Id: <20190929205427.1319-2-philippe.waroquiers@skynet.be> In-Reply-To: <20190929205427.1319-1-philippe.waroquiers@skynet.be> References: <20190929205427.1319-1-philippe.waroquiers@skynet.be> MIME-Version: 1.0 X-IsSubscribed: yes This patch adds the new 'prefix-define' command that creates (or mark an existing user defined command) as a prefix command. This approach was preferred compared to add a -prefix option to 'define' command : with prefix-define, a command can be defined and afterwards marked as a prefix. Also, it is easier to define a 'prefix' only command in one operation. This patch also adds completers for the 'define' and 'document' commands. This makes it easier for the user to type the prefixes for 'define' and type the documented command name for 'document'. gdb/ChangeLog YYYY-MM-DD Philippe Waroquiers * cli/cli-script.c (do_define_command): Ensure a redefined prefix command is kept as a prefix command. (prefix_define_command): New function. (show_user_1): Report user defined prefixes. (_initialize_cli_script): Create the new 'prefix-define' 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. --- gdb/cli/cli-script.c | 107 +++++++++++++++++++++++++++++++++++++------ gdb/top.c | 10 ++++ 2 files changed, 103 insertions(+), 14 deletions(-) diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 4fc9c70259..c70c0e4fb3 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" @@ -1444,10 +1445,22 @@ 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 ? c->prefixlist : nullptr; + const char *c_prefixname = c ? c->prefixname : nullptr; + + 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); + + if (c_prefixlist != nullptr) + { + newc->prefixlist = c_prefixlist; + newc->prefixname = c_prefixname; + newc->allow_unknown = newc->user_commands.get () != nullptr; + } + } /* If this new command is a hook, then mark both commands as being tied. */ @@ -1522,6 +1535,52 @@ document_command (const char *comname, int from_tty) c->doc = doc; } } + +/* Implementation of the "prefix-define" command. */ + +static void +prefix_define_command (const char *comname, int from_tty) +{ + struct cmd_list_element *c, **list; + const char *tem; + const char *comfull; + char *prefixname; + + 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 && strcmp (comname, c->name) != 0) + c = nullptr; + + if (c && c->theclass != class_user) + error (_("Command \"%s\" is built-in."), comfull); + + if (c && c->prefixlist != nullptr) + { + /* c is already a user defined prefix command. */ + return; + } + + if (c == nullptr) + { + comname = xstrdup (comname); + c = add_cmd (comname, class_user, user_defined_command, + xstrdup ("User-defined."), list); + } + + c->prefixlist = new struct cmd_list_element*; + *(c->prefixlist) = nullptr; + prefixname = (char *) xmalloc (strlen (comfull) + 2); + prefixname[0] = 0; + strcat (prefixname, comfull); + strcat (prefixname, " "); + c->prefixname = prefixname; + c->allow_unknown = c->user_commands.get () != nullptr; +} + /* Used to implement source_command. */ @@ -1562,7 +1621,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) { @@ -1571,25 +1644,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 "prefix-define" 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\ @@ -1598,6 +1669,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 ("prefix-define", class_support, prefix_define_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 a1a08e0b99..abd07bd6fe 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -615,6 +615,16 @@ 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, + report the list of subcommands. */ + { + printf_unfiltered + ("\"%.*s\" must be followed by the name of an %s command.\n", + (int) strlen (c->prefixname) - 1, c->prefixname, c->name); + 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)