This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] PR cli/21688: Fix multi-line/inline command differentiation


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=51ed89aa0dce3db46561235efdc4bbc0661bcf37

commit 51ed89aa0dce3db46561235efdc4bbc0661bcf37
Author: Sergio Durigan Junior <sergiodj@redhat.com>
Date:   Wed Jun 28 21:55:03 2017 -0400

    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 <guitton@adacore.com>
      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  <sergiodj@redhat.com>
    
    	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  <sergiodj@redhat.com>
    
    	PR cli/21688
    	* gdb.python/py-cmd.exp (test_python_inline_or_multiline): New
    	procedure.  Call it.

Diff:
---
 gdb/ChangeLog                       |  7 +++++++
 gdb/cli/cli-script.c                | 21 +++++++++++++++++----
 gdb/testsuite/ChangeLog             |  6 ++++++
 gdb/testsuite/gdb.python/py-cmd.exp | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b47226bc..4cd7aad 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2017-06-30  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	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.
+
 2017-06-29  Pedro Alves  <palves@redhat.com>
 
 	* completer.c (expression_completer): Call
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, "");
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 41c5434..06bf5a4 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2017-06-30  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+	PR cli/21688
+	* gdb.python/py-cmd.exp (test_python_inline_or_multiline): New
+	procedure.  Call it.
+
 2017-06-29  Pedro Alves  <palves@redhat.com>
 
 	* gdb.base/printcmds.exp: Add tests.
diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp
index 2dbf23ce..39bb785 100644
--- a/gdb/testsuite/gdb.python/py-cmd.exp
+++ b/gdb/testsuite/gdb.python/py-cmd.exp
@@ -181,6 +181,38 @@ gdb_test "complete expr_test bar\." \
     "expr_test bar\.bc.*expr_test bar\.ij.*" \
     "test completion through complete command"
 
+# Test that the "python" command is correctly recognized as
+# inline/multi-line when entering a sequence of commands.
+#
+# This proc tests PR cli/21688.  The PR is not language-specific, but
+# the easiest way is just to test with Python.
+proc test_python_inline_or_multiline { } {
+    set define_cmd_not_inline {
+	{ "if 1"                 " >$"            "multi-line if 1" }
+	{ "python"               " >$"            "multi-line python command" }
+	{ "print ('hello')"      "  >$"           "multi-line print" }
+	{ "end"                  " >$"            "multi-line first end" }
+	{ "end"                  "hello\r\n"      "multi-line last end" } }
+
+    set define_cmd_inline {
+	{ "if 1"                      " >$"          "inline if 1" }
+	{ "python print ('hello')"    " >$"          "inline python command" }
+	{ "end"                       "hello\r\n"    "inline end" } }
+
+    foreach t [list $define_cmd_not_inline $define_cmd_inline] {
+	foreach l $t {
+	    lassign $l command regex testmsg
+	    gdb_test_multiple "$command" "$testmsg" {
+		-re "$regex" {
+		    pass "$testmsg"
+		}
+	    }
+	}
+    }
+}
+
+test_python_inline_or_multiline
+
 if { [readline_is_used] } {
     set test "complete 'expr_test bar.i'"
     send_gdb "expr_test bar\.i\t\t"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]