From 51ed89aa0dce3db46561235efdc4bbc0661bcf37 Mon Sep 17 00:00:00 2001 From: Sergio Durigan Junior Date: Wed, 28 Jun 2017 21:55:03 -0400 Subject: PR cli/21688: Fix multi-line/inline command differentiation This bug is a regression caused by the following commit: 604c4576fdcfc4e7c28f569b3748a1b6b4e0dbd4 is the first bad commit commit 604c4576fdcfc4e7c28f569b3748a1b6b4e0dbd4 Author: Jerome Guitton Date: Tue Jan 10 15:15:53 2017 +0100 The problem happens because, on cli/cli-script.c:process_next_line, GDB is not using the command line string to identify which command to run, but it instead using the 'struct cmd_list_element *' that is obtained by using the mentioned string. The problem with that is that the 'struct cmd_list_element *' doesn't have any information on whether the command issued by the user is a multi-line or inline one. A multi-line command is a command that will necessarily be composed of more than 1 line. For example: (gdb) if 1 >python >print ('hello') >end >end As can be seen in the example above, the 'python' command actually "opens" a new command line (represented by the change in the indentation) that will then be used to enter Python code. OTOH, an inline command is a command that is "self-contained" in a single line, for example: (gdb) if 1 >python print ('hello') >end This Python command is a one-liner, and therefore there is no other Python code that can be entered for this same block. There is also no change in the indentation. So, the fix is somewhat simple: we have to revert the change and use the full command line string passed to process_next_line in order to identify whether we're dealing with a multi-line or an inline command. This commit does just that. As can be seen, this regression also affects other languages, like guile or the compile framework. To make things clearer, I decided to create a new helper function responsible for identifying a non-inline command. Testcase is attached. gdb/ChangeLog: 2017-06-30 Sergio Durigan Junior PR cli/21688 * cli/cli-script.c (command_name_equals_not_inline): New function. (process_next_line): Adjust 'if' clauses for "python", "compile" and "guile" to use command_name_equals_not_inline. gdb/testsuite/ChangeLog: 2017-06-30 Sergio Durigan Junior PR cli/21688 * gdb.python/py-cmd.exp (test_python_inline_or_multiline): New procedure. Call it. --- gdb/cli/cli-script.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'gdb/cli/cli-script.c') diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index e0e27ef..72f316f 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -900,6 +900,20 @@ command_name_equals (struct cmd_list_element *cmd, const char *name) && strcmp (cmd->name, name) == 0); } +/* Return true if NAME is the only command between COMMAND_START and + COMMAND_END. This is useful when we want to know whether the + command is inline (i.e., has arguments like 'python command1') or + is the start of a multi-line command block. */ + +static bool +command_name_equals_not_inline (const char *command_start, + const char *command_end, + const char *name) +{ + return (command_end - command_start == strlen (name) + && startswith (command_start, name)); +} + /* Given an input line P, skip the command and return a pointer to the first argument. */ @@ -997,21 +1011,20 @@ process_next_line (char *p, struct command_line **command, int parse_commands, { *command = build_command_line (commands_control, line_first_arg (p)); } - else if (command_name_equals (cmd, "python")) + else if (command_name_equals_not_inline (p_start, p_end, "python")) { /* Note that we ignore the inline "python command" form here. */ *command = build_command_line (python_control, ""); } - else if (command_name_equals (cmd, "compile")) + else if (command_name_equals_not_inline (p_start, p_end, "compile")) { /* Note that we ignore the inline "compile command" form here. */ *command = build_command_line (compile_control, ""); (*command)->control_u.compile.scope = COMPILE_I_INVALID_SCOPE; } - - else if (command_name_equals (cmd, "guile")) + else if (command_name_equals_not_inline (p_start, p_end, "guile")) { /* Note that we ignore the inline "guile command" form here. */ *command = build_command_line (guile_control, ""); -- cgit v1.1