From patchwork Thu Jan 12 10:05:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Guitton X-Patchwork-Id: 18862 Received: (qmail 22352 invoked by alias); 12 Jan 2017 10:05:20 -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 22340 invoked by uid 89); 12 Jan 2017 10:05:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=harm, again!, last_line, pointee X-HELO: smtp.eu.adacore.com Received: from mel.act-europe.fr (HELO smtp.eu.adacore.com) (194.98.77.210) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 12 Jan 2017 10:05:09 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id C4E1B83BD0; Thu, 12 Jan 2017 11:05:06 +0100 (CET) Received: from smtp.eu.adacore.com ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UplSZTlYX72L; Thu, 12 Jan 2017 11:05:06 +0100 (CET) Received: from chelles.act-europe.fr (chelles.act-europe.fr [10.10.0.160]) by smtp.eu.adacore.com (Postfix) with ESMTP id AF01B83BB6; Thu, 12 Jan 2017 11:05:06 +0100 (CET) Received: by chelles.act-europe.fr (Postfix, from userid 560) id AB40A1EA0067; Thu, 12 Jan 2017 11:05:06 +0100 (CET) Date: Thu, 12 Jan 2017 11:05:06 +0100 From: Jerome Guitton To: Simon Marchi Cc: gdb-patches@sourceware.org Subject: Re: [RFA] completion in command definition Message-ID: <20170112100506.GK27546@adacore.com> References: <1484058481-6378-1-git-send-email-guitton@adacore.com> <81874bfd1c99e89162b98d18fa8cb385@polymtl.ca> <20170111160518.GH27546@adacore.com> <677c2a720f77b21fd672c24efc41c878@polymtl.ca> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <677c2a720f77b21fd672c24efc41c878@polymtl.ca> User-Agent: Mutt/1.5.21 (2010-09-15) Simon Marchi (simon.marchi@polymtl.ca): > Actually, I think you are confusing pointer and pointee. > lookup_cmd_1 checks if result_list is NULL, not if *result_list is > NULL. So with your version, since result_list is not NULL > (&last_line is not NULL, it's the address of the variable) > lookup_cmd_1 will set the last_line variable. There's no harm, but > since we don't care about that value it's not useful either. I > think what you want is: > > cmd = lookup_cmd_1 (&cmd_name, cmdlist, NULL, 1); You are absolutely right; I got confused by lookup_cmd_1's doc somehow. New patch in attachment. Thanks again! commit 05bd4353619a49e8506bc6f8cd428b6a0961b28f Author: Jerome Guitton Date: Tue Jan 10 15:15:53 2017 +0100 [RFA] completion in command definition When defining a new macro, "command" is not recognized as an aliased for "commands": (gdb) define breakmain Type commands for definition of "breakmain". End with a line saying just "end". >break main >command >echo "IN MAIN\n" >end (gdb) There is a special case for while-stepping, where 'ws' and 'stepping' are recognized explicitely. We could add "command" to the list as well. I'd rather use cli-decode though. Patch in attachment, with a test, tested in x86-linux. OK to apply? gdb/ChangeLog: * cli/cli-decode.c (find_command_name_length): Make it global. * cli/cli-decode.h (find_command_name_length): Declare. * cli/cli-script.c (command_name_equals, line_first_arg): New functions. (process_next_line): Use cli-decode to parse command names gdb/testsuite/ChangeLog: * gdb.base/define.exp: Add test for completion in command definition. diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index dbd874e..b71f6f6 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -1255,7 +1255,7 @@ find_cmd (const char *command, int len, struct cmd_list_element *clist, return found; } -static int +int find_command_name_length (const char *text) { const char *p = text; diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index e5ab839..66159fd 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -253,4 +253,6 @@ extern const char * const auto_boolean_enums[]; extern int cli_user_command_p (struct cmd_list_element *); +extern int find_command_name_length (const char *); + #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 6f44d52..f19df9e 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -143,7 +143,7 @@ multi_line_command_p (enum command_control_type type) control commands (if/while). */ static struct command_line * -build_command_line (enum command_control_type type, char *args) +build_command_line (enum command_control_type type, const char *args) { struct command_line *cmd; @@ -904,6 +904,30 @@ read_next_line (void) return command_line_input (prompt_ptr, from_tty, "commands"); } +/* Return non-zero if CMD's name is NAME. */ + +static bool +command_name_equals (struct cmd_list_element *cmd, const char *name) +{ + return cmd != NULL + && cmd != CMD_LIST_AMBIGUOUS + && strcmp (cmd->name, name) == 0; +} + +/* Given an input line P, skip the command and return a pointer to the + first argument. */ + +static const char * +line_first_arg (const char *p) +{ + const char *first_arg = p + find_command_name_length (p); + + while (first_arg != '\0' && isspace (*first_arg)) + first_arg++; + + return first_arg; +} + /* Process one input line. If the command is an "end", return such an indication to the caller. If PARSE_COMMANDS is true, strip leading whitespace (trailing whitespace is always stripped) in the line, @@ -919,6 +943,8 @@ process_next_line (char *p, struct command_line **command, int parse_commands, char *p_end; char *p_start; int not_handled = 0; + const char *cmd_name = p; + struct cmd_list_element *cmd; /* Not sure what to do here. */ if (p == NULL) @@ -938,9 +964,11 @@ process_next_line (char *p, struct command_line **command, int parse_commands, We also permit whitespace before end and after. */ if (p_end - p_start == 3 && startswith (p_start, "end")) return end_command; - + if (parse_commands) { + cmd = lookup_cmd_1 (&cmd_name, cmdlist, NULL, 1); + /* If commands are parsed, we skip initial spaces. Otherwise, which is the case for Python commands and documentation (see the 'document' command), spaces are preserved. */ @@ -958,9 +986,7 @@ process_next_line (char *p, struct command_line **command, int parse_commands, /* Check for while, if, break, continue, etc and build a new command line structure for them. */ - if ((p_end - p >= 14 && startswith (p, "while-stepping")) - || (p_end - p >= 8 && startswith (p, "stepping")) - || (p_end - p >= 2 && startswith (p, "ws"))) + if (command_name_equals (cmd, "while-stepping")) { /* Because validate_actionline and encode_action lookup command's line as command, we need the line to @@ -975,40 +1001,25 @@ process_next_line (char *p, struct command_line **command, int parse_commands, not. */ *command = build_command_line (while_stepping_control, p); } - else if (p_end - p > 5 && startswith (p, "while")) + else if (command_name_equals (cmd, "while")) { - char *first_arg; - - first_arg = p + 5; - while (first_arg < p_end && isspace (*first_arg)) - first_arg++; - *command = build_command_line (while_control, first_arg); + *command = build_command_line (while_control, line_first_arg (p)); } - else if (p_end - p > 2 && startswith (p, "if")) + else if (command_name_equals (cmd, "if")) { - char *first_arg; - - first_arg = p + 2; - while (first_arg < p_end && isspace (*first_arg)) - first_arg++; - *command = build_command_line (if_control, first_arg); + *command = build_command_line (if_control, line_first_arg (p)); } - else if (p_end - p >= 8 && startswith (p, "commands")) + else if (command_name_equals (cmd, "commands")) { - char *first_arg; - - first_arg = p + 8; - while (first_arg < p_end && isspace (*first_arg)) - first_arg++; - *command = build_command_line (commands_control, first_arg); + *command = build_command_line (commands_control, line_first_arg (p)); } - else if (p_end - p == 6 && startswith (p, "python")) + else if (command_name_equals (cmd, "python")) { /* Note that we ignore the inline "python command" form here. */ *command = build_command_line (python_control, ""); } - else if (p_end - p == 6 && startswith (p, "compile")) + else if (command_name_equals (cmd, "compile")) { /* Note that we ignore the inline "compile command" form here. */ @@ -1016,7 +1027,7 @@ process_next_line (char *p, struct command_line **command, int parse_commands, (*command)->control_u.compile.scope = COMPILE_I_INVALID_SCOPE; } - else if (p_end - p == 5 && startswith (p, "guile")) + else if (command_name_equals (cmd, "guile")) { /* Note that we ignore the inline "guile command" form here. */ *command = build_command_line (guile_control, ""); diff --git a/gdb/testsuite/gdb.base/define.exp b/gdb/testsuite/gdb.base/define.exp index 59203ec..b57b068 100644 --- a/gdb/testsuite/gdb.base/define.exp +++ b/gdb/testsuite/gdb.base/define.exp @@ -147,6 +147,30 @@ gdb_test_multiple "define ifnospace" "define user command: ifnospace" \ gdb_test "ifnospace" ".*hi there.*" "test ifnospace is parsed correctly" +# Verify that the command parser properly handle completion. +set test "define use command: breakmain" +gdb_test_multiple "define breakmain" "$test" \ +{ + -re "Type commands for definition of \"breakmain\".\r\nEnd with a line saying just \"end\".\r\n>$" \ + { + pass "$test" + + set test "send body of breakmain" + gdb_test_multiple "break main\ncommand\necho\nend\nend" "$test" \ + { + -re "$gdb_prompt $"\ + {pass "$test"} + } + } +} + +gdb_test "breakmain" ".*Breakpoint 2.*" "test command completion in define" + +gdb_test "info break 2" \ + "Num Type\[ \]+Disp Enb Address\[ \]+What.* +\[0-9\]+\[\t \]+breakpoint keep y.* in main at .* +\[\t \]+echo.*" + # Verify that the command parser doesn't require a space after an 'while' # command in a user defined function. #