This is the mail archive of the gdb-patches@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]

Re: Fix python indented multi-line commands


Hi Eli,

Thanks for the review.

On Wed, 2008-08-13 at 21:21 +0300, Eli Zaretskii wrote:
> >  /* Read one line from the input stream.  If the command is an "else" or
> > -   "end", return such an indication to the caller.  */
> > +   "end", return such an indication to the caller.  If SPECIAL_PROCESSING
> > +   is true, strip leading and trailing whitespace in the line and attempt
> > +   to recognize GDB control commands.  Otherwise, only "end" is
> > +   recognized.  */
> >  
> >  static enum misc_command_type
> > -read_next_line (struct command_line **command)
> > +read_next_line (struct command_line **command, int special_processing)
> 
> Please don't call variables by mysterious names such as
> "special_processing".  Please give that variable a meaningful name
> that would explain the purpose of this flag even without reading the
> code of the callers of this function.

I agree. The argument has two effects though (stripping of leading
whitespace, and recognizing GDB control commands), so I had some
difficulty in finding a meaningful name for it. That's why I left it
with that one. It is now called parse_input, what do you think?

This patch also adds the testcase asked by Daniel.

I also moved the check for commented and blank lines into the
parse_input if block. That's because it will otherwise change the line
numbering of scripts passed to the python interpreter. This makes python
error messages confusing as their line numbers won't match the user's
script.

Retested, introduces no regression to the testsuite.

Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

gdb/
2008-08-13  Vladimir Prus  <vladimir@codesourcery.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* cli-script.c (read_next_line): Add parse_input argument.
	(recurse_read_control_structure): Adapt to new read_next_line
	signature.
	(read_command_lines): Add parse_input argument.
	(define_command): Adapt to new read_command_lines signature.
	(document_command): Likewise.
	* breakpoint.c (commands_command): Likewise.
	* defs.h (read_command_lines): Adjust function prototype.

testsuite/
2008-08-13  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* gdb.base/define.exp: Test indented command documentation.
	* gdb.python/python.exp: Test indented multi-line command.

Index: gdb.git/gdb/breakpoint.c
===================================================================
--- gdb.git.orig/gdb/breakpoint.c	2008-08-13 23:10:26.000000000 -0300
+++ gdb.git/gdb/breakpoint.c	2008-08-13 23:10:27.000000000 -0300
@@ -675,7 +675,7 @@ commands_command (char *arg, int from_tt
 	char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.", 
 				 bnum);
 	struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
-	l = read_command_lines (tmpbuf, from_tty);
+	l = read_command_lines (tmpbuf, from_tty, 1);
 	do_cleanups (cleanups);
 	free_command_lines (&b->commands);
 	b->commands = l;
Index: gdb.git/gdb/cli/cli-script.c
===================================================================
--- gdb.git.orig/gdb/cli/cli-script.c	2008-08-13 23:10:26.000000000 -0300
+++ gdb.git/gdb/cli/cli-script.c	2008-08-13 23:44:40.000000000 -0300
@@ -839,14 +839,19 @@ realloc_body_list (struct command_line *
   command->body_count = new_length;
 }
 
-/* Read one line from the input stream.  If the command is an "else" or
-   "end", return such an indication to the caller.  */
+/* Read one line from the input stream.  If the command is an "end",
+   return such an indication to the caller.  If PARSE_INPUT is true,
+   strip leading whitespace (trailing whitespace is always stripped)
+   in the line, attempt to recognize GDB control commands, and also
+   return an indication if the command is an "else" or a nop.
+   Otherwise, only "end" is recognized.  */
 
 static enum misc_command_type
-read_next_line (struct command_line **command)
+read_next_line (struct command_line **command, int parse_input)
 {
   char *p, *p1, *prompt_ptr, control_prompt[256];
   int i = 0;
+  int not_handled = 0;
 
   if (control_level >= 254)
     error (_("Control nesting too deep!"));
@@ -869,81 +874,91 @@ read_next_line (struct command_line **co
   if (p == NULL)
     return end_command;
 
-  /* Strip leading and trailing whitespace.  */
-  while (*p == ' ' || *p == '\t')
-    p++;
+  if (parse_input)
+    {
+      /* Strip leading whitespace.  */
+      while (*p == ' ' || *p == '\t')
+	p++;
+    }
 
+  /* Strip trailing whitespace.  */
   p1 = p + strlen (p);
   while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t'))
     p1--;
 
-  /* Blanks and comments don't really do anything, but we need to
-     distinguish them from else, end and other commands which can be
-     executed.  */
-  if (p1 == p || p[0] == '#')
-    return nop_command;
-
   /* Is this the end of a simple, while, or if control structure?  */
   if (p1 - p == 3 && !strncmp (p, "end", 3))
     return end_command;
 
-  /* Is the else clause of an if control structure?  */
-  if (p1 - p == 4 && !strncmp (p, "else", 4))
-    return else_command;
-
-  /* Check for while, if, break, continue, etc and build a new command
-     line structure for them.  */
-  if (p1 - p > 5 && !strncmp (p, "while", 5))
-    {
-      char *first_arg;
-      first_arg = p + 5;
-      while (first_arg < p1 && isspace (*first_arg))
-        first_arg++;
-      *command = build_command_line (while_control, first_arg);
-    }
-  else if (p1 - p > 2 && !strncmp (p, "if", 2))
-    {
-      char *first_arg;
-      first_arg = p + 2;
-      while (first_arg < p1 && isspace (*first_arg))
-        first_arg++;
-      *command = build_command_line (if_control, first_arg);
-    }
-  else if (p1 - p >= 8 && !strncmp (p, "commands", 8))
-    {
-      char *first_arg;
-      first_arg = p + 8;
-      while (first_arg < p1 && isspace (*first_arg))
-        first_arg++;
-      *command = build_command_line (commands_control, first_arg);
-    }
-  else if (p1 - p == 6 && !strncmp (p, "python", 6))
-    {
-      /* Note that we ignore the inline "python command" form
-	 here.  */
-      *command = build_command_line (python_control, "");
-    }
-  else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
-    {
-      *command = (struct command_line *)
-	xmalloc (sizeof (struct command_line));
-      (*command)->next = NULL;
-      (*command)->line = NULL;
-      (*command)->control_type = break_control;
-      (*command)->body_count = 0;
-      (*command)->body_list = NULL;
-    }
-  else if (p1 - p == 13 && !strncmp (p, "loop_continue", 13))
+  if (parse_input)
     {
-      *command = (struct command_line *)
-	xmalloc (sizeof (struct command_line));
-      (*command)->next = NULL;
-      (*command)->line = NULL;
-      (*command)->control_type = continue_control;
-      (*command)->body_count = 0;
-      (*command)->body_list = NULL;
+      /* Blanks and comments don't really do anything, but we need to
+	 distinguish them from else, end and other commands which can be
+	 executed.  */
+      if (p1 == p || p[0] == '#')
+	return nop_command;
+
+      /* Is the else clause of an if control structure?  */
+      if (p1 - p == 4 && !strncmp (p, "else", 4))
+	return else_command;
+
+      /* Check for while, if, break, continue, etc and build a new command
+	 line structure for them.  */
+      if (p1 - p > 5 && !strncmp (p, "while", 5))
+	{
+	  char *first_arg;
+	  first_arg = p + 5;
+	  while (first_arg < p1 && isspace (*first_arg))
+	    first_arg++;
+	  *command = build_command_line (while_control, first_arg);
+	}
+      else if (p1 - p > 2 && !strncmp (p, "if", 2))
+	{
+	  char *first_arg;
+	  first_arg = p + 2;
+	  while (first_arg < p1 && isspace (*first_arg))
+	    first_arg++;
+	  *command = build_command_line (if_control, first_arg);
+	}
+      else if (p1 - p >= 8 && !strncmp (p, "commands", 8))
+	{
+	  char *first_arg;
+	  first_arg = p + 8;
+	  while (first_arg < p1 && isspace (*first_arg))
+	    first_arg++;
+	  *command = build_command_line (commands_control, first_arg);
+	}
+      else if (p1 - p == 6 && !strncmp (p, "python", 6))
+	{
+	  /* Note that we ignore the inline "python command" form
+	     here.  */
+	  *command = build_command_line (python_control, "");
+	}
+      else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
+	{
+	  *command = (struct command_line *)
+	    xmalloc (sizeof (struct command_line));
+	  (*command)->next = NULL;
+	  (*command)->line = NULL;
+	  (*command)->control_type = break_control;
+	  (*command)->body_count = 0;
+	  (*command)->body_list = NULL;
+	}
+      else if (p1 - p == 13 && !strncmp (p, "loop_continue", 13))
+	{
+	  *command = (struct command_line *)
+	    xmalloc (sizeof (struct command_line));
+	  (*command)->next = NULL;
+	  (*command)->line = NULL;
+	  (*command)->control_type = continue_control;
+	  (*command)->body_count = 0;
+	  (*command)->body_list = NULL;
+	}
+      else
+	not_handled = 1;
     }
-  else
+
+  if (!parse_input || not_handled)
     {
       /* A normal command.  */
       *command = (struct command_line *)
@@ -989,7 +1004,7 @@ recurse_read_control_structure (struct c
       dont_repeat ();
 
       next = NULL;
-      val = read_next_line (&next);
+      val = read_next_line (&next, current_cmd->control_type != python_control);
 
       /* Just skip blanks and comments.  */
       if (val == nop_command)
@@ -1071,12 +1086,16 @@ recurse_read_control_structure (struct c
 /* Read lines from the input stream and accumulate them in a chain of
    struct command_line's, which is then returned.  For input from a
    terminal, the special command "end" is used to mark the end of the
-   input, and is not included in the returned chain of commands. */
+   input, and is not included in the returned chain of commands.
+
+   If PARSE_INPUT is true, strip leading whitespace (trailing whitespace
+   is always stripped) in the line and attempt to recognize GDB control
+   commands.  Otherwise, only "end" is recognized.  */
 
 #define END_MESSAGE "End with a line saying just \"end\"."
 
 struct command_line *
-read_command_lines (char *prompt_arg, int from_tty)
+read_command_lines (char *prompt_arg, int from_tty, int parse_input)
 {
   struct command_line *head, *tail, *next;
   struct cleanup *old_chain;
@@ -1105,7 +1124,7 @@ read_command_lines (char *prompt_arg, in
   while (1)
     {
       dont_repeat ();
-      val = read_next_line (&next);
+      val = read_next_line (&next, parse_input);
 
       /* Ignore blank lines or comments.  */
       if (val == nop_command)
@@ -1339,7 +1358,7 @@ define_command (char *comname, int from_
       *tem = tolower (*tem);
 
   sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname);
-  cmds = read_command_lines (tmpbuf, from_tty);
+  cmds = read_command_lines (tmpbuf, from_tty, 1);
 
   if (c && c->class == class_user)
     free_command_lines (&c->user_commands);
@@ -1386,7 +1405,7 @@ document_command (char *comname, int fro
     error (_("Command \"%s\" is built-in."), comname);
 
   sprintf (tmpbuf, "Type documentation for \"%s\".", comname);
-  doclines = read_command_lines (tmpbuf, from_tty);
+  doclines = read_command_lines (tmpbuf, from_tty, 0);
 
   if (c->doc)
     xfree (c->doc);
Index: gdb.git/gdb/defs.h
===================================================================
--- gdb.git.orig/gdb/defs.h	2008-08-13 23:10:26.000000000 -0300
+++ gdb.git/gdb/defs.h	2008-08-13 23:10:27.000000000 -0300
@@ -668,7 +668,7 @@ struct command_line
     struct command_line **body_list;
   };
 
-extern struct command_line *read_command_lines (char *, int);
+extern struct command_line *read_command_lines (char *, int, int);
 
 extern void free_command_lines (struct command_line **);
 
Index: gdb.git/gdb/testsuite/gdb.python/python.exp
===================================================================
--- gdb.git.orig/gdb/testsuite/gdb.python/python.exp	2008-08-13 23:10:26.000000000 -0300
+++ gdb.git/gdb/testsuite/gdb.python/python.exp	2008-08-13 23:10:27.000000000 -0300
@@ -64,3 +64,10 @@ gdb_py_test_multiple "show python comman
   "end" "" \
   "end" "" \
   "show user zzq" "User command zzq:.*  python.*print 23.*  end"
+
+gdb_py_test_multiple "indented multi-line python command" \
+  "python" "" \
+  "def foo ():" "" \
+  "  print 'hello, world!'" "" \
+  "foo ()" "" \
+  "end" "hello, world!"
Index: gdb.git/gdb/testsuite/gdb.base/define.exp
===================================================================
--- gdb.git.orig/gdb/testsuite/gdb.base/define.exp	2008-08-13 23:10:26.000000000 -0300
+++ gdb.git/gdb/testsuite/gdb.base/define.exp	2008-08-13 23:10:27.000000000 -0300
@@ -200,6 +200,31 @@ gdb_expect {
   timeout {fail "(timeout) help user command: nextwhere"}
 }
 
+# Verify that the document command preserves whitespace in the beginning of the line.
+#
+send_gdb "document nextwhere\n"
+gdb_expect {
+  -re "Type documentation for \"nextwhere\".\r\nEnd with a line saying just \"end\".\r\n>$"\
+          {send_gdb "   A next command that first shows you where you're stepping from.\nend\n"
+           gdb_expect {
+             -re "$gdb_prompt $" {}
+             timeout {fail "(timeout) preserve whitespace in help string"}
+           }
+          }
+  -re "$gdb_prompt $"\
+          {fail "preserve whitespace in help string"}
+  timeout {fail "(timeout) preserve whitespace in help string"}
+}
+
+send_gdb "help nextwhere\n"
+gdb_expect {
+  -re "   A next command that first shows you where you're stepping from.\r\n$gdb_prompt $"\
+          {pass "preserve whitespace in help string"}
+  -re "$gdb_prompt $"\
+          {fail "preserve whitespace in help string"}
+  timeout {fail "(timeout) preserve whitespace in help string"}
+}
+
 # Verify that the command parser doesn't require a space after an 'if'
 # command in a user defined function.
 #



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