This is the mail archive of the archer@sourceware.org mailing list for the Archer 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]

[python] FYI: reimplment python varobj support


I'm checking this in on the python branch.

This implements the new python varobj spec to the best of my
understanding.  There are a few oddities in here that I will explain in
a follow-up on the gdb list discussion about the spec.

Tom

b/gdb/ChangeLog:
2009-08-06  Tom Tromey  <tromey@redhat.com>

	* varobj.h (varobj_update_result_t) <new>: New field.
	(varobj_get_child_range): Update.
	(varobj_list_children): Update.  Rewrite documentation.
	(varobj_has_more): Declare.
	* varobj.c (struct varobj) <child_iter, saved_item>: New fields.
	(varobj_has_more): New function.
	(restrict_range, install_dynamic_child): Likewise.
	(update_dynamic_varobj_children): Change 'new_and_unchanged' to
	'new'.  Add 'update_children' and 'to' arguments.  Fix logic to
	conform to new spec.
	(varobj_get_num_children): Don't call
	update_dynamic_varobj_children.
	(varobj_list_children): Add from, to arguments.  Restrict result
	range.
	(install_visualizer): Clear child_iter field.
	(varobj_get_child_range): Remove 'children' argument.  Rewrite.
	(varobj_update): Set 'new' field on result object.  Fix logic to
	conform to new spec.
	(new_variable): Initialize new fields.
	(free_variable): Destroy new fields.
	(value_of_root): Copy from and to fields.
	* mi/mi-cmds.h (mi_cmd_var_set_update_range): Declare.
	* mi/mi-cmds.c (mi_cmds): Add var-set-update-range.
	* mi/mi-cmd-var.c (mi_cmd_var_list_children): Don't set child
	range.  Use varobj_has_more.
	(varobj_update_one): Emit new_num_children when the children
	changed.  Use varobj_has_more.  Emit the new_children list.
	(mi_cmd_var_set_update_range): New function.

b/gdb/doc/ChangeLog:
2009-08-06  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (GDB/MI Variable Objects): Document
	-var-set-update-range.

b/gdb/testsuite/ChangeLog:
2009-08-06  Tom Tromey  <tromey@redhat.com>

	* lib/mi-support.exp (mi_create_floating_varobj): Update.
	(mi_varobj_update_kv_helper): New proc.
	(mi_varobj_update_dynamic_helper): Likewise.
	(mi_varobj_update_dynamic): Rewrite.

	* gdb.python/python-prettyprint.c (main): Update container in "MI"
	mode.
	* gdb.python/python-mi.exp: Update.

projecttype:gdb
email:tromey@gcc.gnu.org
revision:97a2b241637c361bb7c7ab48b342c4341ab9f80e
configure:
make:
check:

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2b8fcc7..fd7c9ab 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23663,6 +23663,8 @@ access this functionality:
 @tab update the variable and its children
 @item @code{-var-set-frozen}
 @tab set frozeness attribute
+@item @code{-var-set-update-range}
+@tab set range of children to display on update
 @end multitable
 
 In the next subsection we describe each operation in detail and suggest
@@ -23836,9 +23838,7 @@ and unions.
 to report.  If @var{from} or @var{to} is less than zero, the range is
 reset and all children will be reported.  Otherwise, children starting
 at @var{from} (zero-based) and ending just before @var{to} will be
-reported.  The selected range is sticky; future calls to
-@code{-var-update} or @code{-var-list-children} will use any
-previously set range.
+reported.
 
 For each child the following results are returned:
 
@@ -23871,7 +23871,11 @@ Otherwise this result is not present.
 
 @item frozen
 If the variable object is frozen, this variable will be present with a value of 1.
+@end table
+
+The result may have its own attributes:
 
+@table @var
 @item has_more
 This is an integer attribute which is nonzero if there are children
 remaining after the end of the selected range.
@@ -24058,6 +24062,9 @@ With the @samp{*} parameter, if a variable object is bound to a
 currently running thread, it will not be updated, without any
 diagnostic.
 
+If @code{-var-set-update-range} was previously used on a varobj, then
+only the selected range of children will be reported.
+
 @subsubheading Example
 
 @smallexample
@@ -24125,6 +24132,32 @@ Unfreezing a variable does not update it, only subsequent
 (gdb)
 @end smallexample
 
+@subheading The @code{-var-set-update-range} command
+@findex -var-set-update-range
+@anchor{-var-set-update-range}
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-set-update-range @var{name} @var{from} @var{to}
+@end smallexample
+
+Set the range of children to be returned by future invocations of
+@code{-var-update}.
+
+@var{from} and @var{to} indicate the range of children to report.  If
+@var{from} or @var{to} is less than zero, the range is reset and all
+children will be reported.  Otherwise, children starting at @var{from}
+(zero-based) and ending just before @var{to} will be reported.
+
+@subsubheading Example
+
+@smallexample
+(gdb)
+-var-set-update-range V 1 2
+^done
+@end smallexample
+
 @subheading The @code{-var-set-visualizer} command
 @findex -var-set-visualizer
 @anchor{-var-set-visualizer}
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 82f7220..e5f237d 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -388,20 +388,20 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
     {
       from = atoi (argv[argc - 2]);
       to = atoi (argv[argc - 1]);
-      varobj_set_child_range (var, from, to);
+    }
+  else
+    {
+      from = -1;
+      to = -1;
     }
 
-  children = varobj_list_children (var);
+  children = varobj_list_children (var, &from, &to);
   ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
   if (argc == 2 || argc == 4)
     print_values = mi_parse_values_option (argv[0]);
   else
     print_values = PRINT_NO_VALUES;
 
-  /* Re-fetch the child range, because varobj_get_child_range computes
-     the real start and end indices for us.  */
-  varobj_get_child_range (var, children, &from, &to);
-
   display_hint = varobj_get_display_hint (var);
   if (display_hint)
     {
@@ -430,8 +430,7 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
       do_cleanups (cleanup_children);
     }
 
-  ui_out_field_int (uiout, "has_more",
-		    VEC_length (varobj_p, children) > to);
+  ui_out_field_int (uiout, "has_more", varobj_has_more (var, to));
 }
 
 void
@@ -698,11 +697,11 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
 	}
 
       if (r->type_changed)
-	{
-          ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj));
-          ui_out_field_int (uiout, "new_num_children", 
-			    varobj_get_num_children (r->varobj));
-	}
+	ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj));
+
+      if (r->type_changed || r->children_changed)
+	ui_out_field_int (uiout, "new_num_children", 
+			  varobj_get_num_children (r->varobj));
 
       display_hint = varobj_get_display_hint (var);
       if (display_hint)
@@ -713,30 +712,32 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
 
       if (r->children_changed)
 	{
-	  int ix, from, to;
-	  struct varobj *child;
-	  struct cleanup *cleanup =
-	    make_cleanup_ui_out_list_begin_end (uiout, "children");
+	  int from, to;
+	  varobj_get_child_range (r->varobj, &from, &to);
+	  ui_out_field_int (uiout, "has_more",
+			    varobj_has_more (r->varobj, to));
+	}
 
-	  VEC (varobj_p)* children = varobj_list_children (r->varobj);
-	  varobj_get_child_range (r->varobj, children, &from, &to);
+      if (r->new)
+	{
+	  int j;
+	  varobj_p child;
+	  struct cleanup *cleanup;
 
-	  for (ix = from;
-	       ix < to && VEC_iterate (varobj_p, children, ix, child);
-	       ++ix)
+	  cleanup = make_cleanup_ui_out_list_begin_end (uiout, "new_children");
+	  for (j = 0; VEC_iterate (varobj_p, r->new, j, child); ++j)
 	    {
 	      struct cleanup *cleanup_child;
 	      cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-	      print_varobj (child, print_values, 1 /* print expression */);
+	      print_varobj (child, print_values, 1 /* print_expression */);
 	      do_cleanups (cleanup_child);
 	    }
 
 	  do_cleanups (cleanup);
-
-	  ui_out_field_int (uiout, "has_more",
-			    VEC_length (varobj_p, children) > to);
+	  VEC_free (varobj_p, r->new);
+	  r->new = NULL;	/* Paranoia.  */
 	}
-  
+
       if (mi_version (uiout) > 1)
 	do_cleanups (cleanup);
     }
@@ -750,3 +751,19 @@ mi_cmd_enable_pretty_printing (char *command, char **argv, int argc)
     error (_("mi_cmd_enable_pretty_printing: no arguments allowed"));
   varobj_enable_pretty_printing ();
 }
+
+void
+mi_cmd_var_set_update_range (char *command, char **argv, int argc)
+{
+  struct varobj *var;
+  int from, to;
+
+  if (argc != 3)
+    error (_("mi_cmd_var_set_update_range: Usage: VAROBJ FROM TO"));
+  
+  var = varobj_get_handle (argv[0]);
+  from = atoi (argv[1]);
+  to = atoi (argv[2]);
+
+  varobj_set_child_range (var, from, to);
+}
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 772566e..ef25cba 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -112,6 +112,7 @@ struct mi_cmd mi_cmds[] =
   { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children},
   { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format},
   { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen},
+  { "var-set-update-range", { NULL, 0 }, mi_cmd_var_set_update_range },
   { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer},
   { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes},
   { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format},
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 79798ef..b0d68ed 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -99,6 +99,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;
 extern mi_cmd_argv_ftype mi_cmd_var_show_format;
 extern mi_cmd_argv_ftype mi_cmd_var_update;
 extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing;
+extern mi_cmd_argv_ftype mi_cmd_var_set_update_range;
 
 /* Description of a single command. */
 
diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp
index e7bfe54..095ee78 100644
--- a/gdb/testsuite/gdb.python/python-mi.exp
+++ b/gdb/testsuite/gdb.python/python-mi.exp
@@ -69,16 +69,21 @@ mi_list_varobj_children container {
 
 mi_next "next over update 1"
 
-mi_varobj_update_dynamic container {
-    { {container.\[0\]} {\[0\]} 0 int }
-} "varobj update 1"
+mi_varobj_update_dynamic container "varobj update 1" {
+    type_changed false new_num_children 1 has_more 0
+} {
+} {
+    { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 }
+}
 
 mi_next "next over update 2"
 
-mi_varobj_update_dynamic container {
-    { {container.\[0\]} {\[0\]} 0 int }
-    { {container.\[1\]} {\[1\]} 0 int }
-} "varobj update 2"
+mi_varobj_update_dynamic container "varobj update 2" {
+    type_changed false new_num_children 2 has_more 0
+} {
+} {
+    { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+}
 
 mi_gdb_test "-var-set-visualizer container None" \
   "\\^done" \
@@ -92,19 +97,26 @@ mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \
   "\\^done" \
   "choose default visualizer"
 
-mi_varobj_update_dynamic container {
-    { {container.\[0\]} {\[0\]} 0 int }
-    { {container.\[1\]} {\[1\]} 0 int }
-} "varobj update after choosing default"
+mi_varobj_update_dynamic container "varobj update after choosing default" {
+    type_changed false new_num_children 2 has_more 0
+} {
+} {
+    { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 }
+    { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+}
 
 mi_gdb_test "-var-set-visualizer container ContainerPrinter" \
   "\\^done" \
   "choose visualizer using expression"
 
-mi_varobj_update_dynamic container {
-    { {container.\[0\]} {\[0\]} 0 int }
-    { {container.\[1\]} {\[1\]} 0 int }
-} "varobj update after choosing via expression"
+mi_varobj_update_dynamic container \
+  "varobj update after choosing via expression" {
+      type_changed false new_num_children 2 has_more 0
+  } {
+  } {
+      { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 }
+      { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+  }
 
 mi_list_varobj_children_range container 1 2 2 {
     { {container.\[1\]} {\[1\]} 0 int }
@@ -115,6 +127,39 @@ mi_list_varobj_children_range container -1 -1 2 {
     { {container.\[1\]} {\[1\]} 0 int }
 } "list varobj children after resetting child range"
 
+mi_next "next over update 3"
+
+mi_gdb_test "-var-set-update-range container 0 1" \
+  "\\^done" \
+  "set update range"
+
+# This should truncate the list.
+mi_list_varobj_children container {
+    { {container.\[0\]} {\[0\]} 0 int }
+} "list children after setting update range"
+
+# This should return just the items in [1,2).
+mi_list_varobj_children_range container 1 2 2 {
+    { {container.\[1\]} {\[1\]} 0 int }
+} "list selected children after setting range"
+
+# This should not be affected by the previous list-children request.
+mi_list_varobj_children container {
+    { {container.\[0\]} {\[0\]} 0 int }
+} "list children after listing selected range"
+
+mi_next "next over update 4"
+
+# This should only show the first child, because the update range has
+# been set.
+mi_varobj_update_dynamic container \
+  "update after next with restricted range" {
+      type_changed false new_num_children 1 has_more 1
+  } {
+      { name {container.\[0\]} in_scope true type_changed false }
+  } {
+  }
+
 mi_continue_to_line \
     [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \
     "step to second breakpoint"
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
index 5cc35be..6bbbf1d 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.c
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -203,6 +203,9 @@ main ()
   add_item (&c, 72);
 
 #ifdef MI
+  add_item (&c, 1011);
+  c.elements[0] = 1023;
+
   do_nothing ();
 #endif
 
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 33f277a..f6b62e2 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1200,7 +1200,7 @@ proc mi_create_varobj { name expression testname } {
 
 proc mi_create_floating_varobj { name expression testname } {
     mi_gdb_test "-var-create $name @ $expression" \
-        "\\^done,name=\"$name\",numchild=\"\[0-9\]+\",value=\".*\",type=.*" \
+        "\\^done,name=\"$name\",numchild=\"\(-1\|\[0-9\]+\)\",value=\".*\",type=.*" \
         $testname
 }
 
@@ -1249,16 +1249,64 @@ proc mi_varobj_update_with_type_change { name new_type new_children testname } {
     mi_gdb_test "-var-update $name" $er $testname
 }
 
-# Update a dynamic varobj named NAME.  CHILDREN is a list of children,
-# in the same form as mi_list_varobj_children.  TESTNAME is the name
-# of the test.
-proc mi_varobj_update_dynamic {name children testname} {
-    set children_exp_j [mi_child_regexp $children 0]
+# A helper that turns a key/value list into a regular expression
+# matching some MI output.
+proc mi_varobj_update_kv_helper {list} {
+    set first 1
+    set rx ""
+    foreach {key value} $list {
+	if {!$first} {
+	    append rx ,
+	}
+	set first 0
+	if {$key == "new_children"} {
+	    append rx "$key=\\\[$value\\\]"
+	} else {
+	    append rx "$key=\"$value\""
+	}
+    }
+    return $rx
+}
+
+# A helper for mi_varobj_update_dynamic that computes a match
+# expression given a child list.
+proc mi_varobj_update_dynamic_helper {children} {
+    set crx ""
 
-    set er "\\^done,changelist=\\\["
+    set first 1
+    foreach child $children {
+	if {!$first} {
+	    append crx ,
+	}
+	set first 0
+	append crx "{"
+	append crx [mi_varobj_update_kv_helper $child]
+	append crx "}"
+    }
+
+    return $crx
+}
 
-    append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\""
-    append er ",children=\\\[$children_exp_j.*\\\],has_more=\".\"}\\\]"
+# Update a dynamic varobj named NAME.  CHILDREN is a list of children
+# that have been updated; NEW_CHILDREN is a list of children that were
+# added to the primary varobj.  Each child is a list of key/value
+# pairs that are expected.  SELF is a key/value list holding
+# information about the varobj itself.  TESTNAME is the name of the
+# test.
+proc mi_varobj_update_dynamic {name testname self children new_children} {
+    if {[llength $new_children]} {
+	set newrx [mi_varobj_update_dynamic_helper $new_children]
+	lappend self new_children $newrx
+    }
+    set selfrx [mi_varobj_update_kv_helper $self]
+    set crx [mi_varobj_update_dynamic_helper $children]
+
+    set er "\\^done,changelist=\\\[\{name=\"$name\",in_scope=\"true\""
+    append er ",$selfrx\}"
+    if {"$crx" != ""} {
+	append er ",$crx"
+    }
+    append er "\\\]"
 
     verbose -log "Expecting: $er"
     mi_gdb_test "-var-update $name" $er $testname
diff --git a/gdb/varobj.c b/gdb/varobj.c
index a3938d0..2a0d317 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -197,6 +197,17 @@ struct varobj
   /* The pretty-printer that has been constructed.  If NULL, then a
      new printer object is needed, and one will be constructed.  */
   PyObject *pretty_printer;
+
+  /* The iterator returned by the printer's 'children' method, or NULL
+     if not available.  */
+  PyObject *child_iter;
+
+  /* We request one extra item from the iterator, so that we can
+     report to the caller whether there are more items than we have
+     already reported.  However, we don't want to install this value
+     when we read it, because that will mess up future updates.  So,
+     we stash it here instead.  */
+  PyObject *saved_item;
 };
 
 struct cpstack
@@ -815,6 +826,17 @@ varobj_get_display_hint (struct varobj *var)
   return result;
 }
 
+/* Return true if the varobj has items after TO, false otherwise.  */
+
+int
+varobj_has_more (struct varobj *var, int to)
+{
+  if (VEC_length (varobj_p, var->children) > to)
+    return 1;
+  return (VEC_length (varobj_p, var->children) == to
+	  && var->saved_item != NULL);
+}
+
 /* If the variable object is bound to a specific thread, that
    is its evaluation can always be done in context of a frame
    inside that thread, returns GDB id of the thread -- which
@@ -847,22 +869,73 @@ varobj_get_frozen (struct varobj *var)
   return var->frozen;
 }
 
+/* A helper function that restricts a range to what is actually
+   available in a VEC.  This follows the usual rules for the meaning
+   of FROM and TO -- if either is negative, the entire range is
+   used.  */
+
+static void
+restrict_range (VEC (varobj_p) *children, int *from, int *to)
+{
+  if (*from < 0 || *to < 0)
+    {
+      *from = 0;
+      *to = VEC_length (varobj_p, children);
+    }
+  else
+    {
+      if (*from > VEC_length (varobj_p, children))
+	*from = VEC_length (varobj_p, children);
+      if (*to > VEC_length (varobj_p, children))
+	*to = VEC_length (varobj_p, children);
+      if (*from > *to)
+	*from = *to;
+    }
+}
+
+/* A helper for update_dynamic_varobj_children that installs a new
+   child when needed.  */
+
+static void
+install_dynamic_child (struct varobj *var,
+		       VEC (varobj_p) **changed,
+		       VEC (varobj_p) **new,
+		       int *cchanged,
+		       int index,
+		       const char *name,
+		       struct value *value)
+{
+  if (VEC_length (varobj_p, var->children) < index + 1)
+    {
+      /* There's no child yet.  */
+      struct varobj *child = varobj_add_child (var, name, value);
+      if (new)
+	VEC_safe_push (varobj_p, *new, child);
+      *cchanged = 1;
+    }
+  else 
+    {
+      varobj_p existing = VEC_index (varobj_p, var->children, index);
+      if (install_new_value (existing, value, 0))
+	{
+	  if (changed)
+	    VEC_safe_push (varobj_p, *changed, existing);
+	}
+    }
+}
+
 static int
 update_dynamic_varobj_children (struct varobj *var,
 				VEC (varobj_p) **changed,
-				VEC (varobj_p) **new_and_unchanged,
-				int *cchanged)
-
+				VEC (varobj_p) **new,
+				int *cchanged,
+				int update_children,
+				int to)
 {
 #if HAVE_PYTHON
-  /* FIXME: we *might* want to provide this functionality as
-     a standalone function, so that other interested parties
-     than varobj code can benefit for this.  */
   struct cleanup *back_to;
   PyObject *children;
-  PyObject *iterator;
   int i;
-  int children_changed = 0;
   PyObject *printer = var->pretty_printer;
 
   back_to = varobj_ensure_python_env (var);
@@ -874,89 +947,103 @@ update_dynamic_varobj_children (struct varobj *var,
       return 0;
     }
 
-  children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
-					 NULL);
-
-  if (!children)
+  if (update_children || !var->child_iter)
     {
-      gdbpy_print_stack ();
-      error (_("Null value returned for children"));
-    }
+      children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+					     NULL);
 
-  make_cleanup_py_decref (children);
+      if (!children)
+	{
+	  gdbpy_print_stack ();
+	  error (_("Null value returned for children"));
+	}
 
-  if (!PyIter_Check (children))
-    error (_("Returned value is not iterable"));
+      make_cleanup_py_decref (children);
 
-  iterator = PyObject_GetIter (children);
-  if (!iterator)
-    {
-      gdbpy_print_stack ();
-      error (_("Could not get children iterator"));
+      if (!PyIter_Check (children))
+	error (_("Returned value is not iterable"));
+
+      Py_XDECREF (var->child_iter);
+      var->child_iter = PyObject_GetIter (children);
+      if (!var->child_iter)
+	{
+	  gdbpy_print_stack ();
+	  error (_("Could not get children iterator"));
+	}
+
+      Py_XDECREF (var->saved_item);
+      var->saved_item = NULL;
+
+      i = 0;
     }
-  make_cleanup_py_decref (iterator);
+  else
+    i = VEC_length (varobj_p, var->children);
 
   /* We ask for one extra child, so that MI can report whether there
      are more children.  */
-  for (i = 0; var->to < 0 || i < var->to + 1; ++i)
+  for (; to < 0 || i < to + 1; ++i)
     {
-      PyObject *item = PyIter_Next (iterator);
-      PyObject *py_v;
-      struct value *v;
-      char *name;
-      struct cleanup *inner;
-      
+      PyObject *item;
+
+      /* See if there was a leftover from last time.  */
+      if (var->saved_item)
+	{
+	  item = var->saved_item;
+	  var->saved_item = NULL;
+	}
+      else
+	item = PyIter_Next (var->child_iter);
+
       if (!item)
 	break;
-      inner = make_cleanup_py_decref (item);
 
-      if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
-	error (_("Invalid item from the child list"));
-      
-      v = convert_value_from_python (py_v);
+      /* We don't want to push the extra child on any report list.  */
+      if (to < 0 || i < to)
+	{
+	  PyObject *py_v;
+	  char *name;
+	  struct value *v;
+	  struct cleanup *inner;
 
-      /* TODO: This assume the name of the i-th child never changes.  */
+	  inner = make_cleanup_py_decref (item);
 
-      /* Now see what to do here.  */
-      if (VEC_length (varobj_p, var->children) < i + 1)
-	{
-	  /* There's no child yet.  */
-	  struct varobj *child = varobj_add_child (var, name, v);
-	  if (new_and_unchanged)
-	    VEC_safe_push (varobj_p, *new_and_unchanged, child);
-	  children_changed = 1;
+	  if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+	    error (_("Invalid item from the child list"));
+
+	  v = convert_value_from_python (py_v);
+	  install_dynamic_child (var, changed, new,
+				 cchanged, i, name, v);
+	  do_cleanups (inner);
 	}
-      else 
+      else
 	{
-	  varobj_p existing = VEC_index (varobj_p, var->children, i);
-	  if (install_new_value (existing, v, 0) && changed)
-	    {
-	      if (changed)
-		VEC_safe_push (varobj_p, *changed, existing);
-	    }
-	  else
-	    {
-	      if (new_and_unchanged)
-		VEC_safe_push (varobj_p, *new_and_unchanged, existing);
-	    }
-	}
+	  Py_XDECREF (var->saved_item);
+	  var->saved_item = item;
 
-      do_cleanups (inner);
+	  /* We want to truncate the child list just before this
+	     element.  */
+	  break;
+	}
     }
 
   if (i < VEC_length (varobj_p, var->children))
     {
-      int i;
-      children_changed = 1;
-      for (i = 0; i < VEC_length (varobj_p, var->children); ++i)
-	varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0);
+      int j;
+      *cchanged = 1;
+      for (j = i; j < VEC_length (varobj_p, var->children); ++j)
+	varobj_delete (VEC_index (varobj_p, var->children, j), NULL, 0);
+      VEC_truncate (varobj_p, var->children, i);
     }
-  VEC_truncate (varobj_p, var->children, i);
+
+  /* If there are fewer children than requested, note that the list of
+     children changed.  */
+  if (to >= 0 && VEC_length (varobj_p, var->children) < to)
+    *cchanged = 1;
+
   var->num_children = VEC_length (varobj_p, var->children);
  
   do_cleanups (back_to);
 
-  *cchanged = children_changed;
   return 1;
 #else
   gdb_assert (0 && "should never be called if Python is not enabled");
@@ -969,8 +1056,7 @@ varobj_get_num_children (struct varobj *var)
   if (var->num_children == -1)
     {
       int changed;
-      if (!var->pretty_printer
-	  || !update_dynamic_varobj_children (var, NULL, NULL, &changed))
+      if (!var->pretty_printer)
 	var->num_children = number_of_children (var);
     }
 
@@ -981,7 +1067,7 @@ varobj_get_num_children (struct varobj *var)
    the return code is the number of such children or -1 on error */
 
 VEC (varobj_p)*
-varobj_list_children (struct varobj *var)
+varobj_list_children (struct varobj *var, int *from, int *to)
 {
   struct varobj *child;
   char *name;
@@ -993,8 +1079,12 @@ varobj_list_children (struct varobj *var)
       /* This, in theory, can result in the number of children changing without
 	 frontend noticing.  But well, calling -var-list-children on the same
 	 varobj twice is not something a sane frontend would do.  */
-      && update_dynamic_varobj_children (var, NULL, NULL, &children_changed))
-    return var->children;
+      && update_dynamic_varobj_children (var, NULL, NULL, &children_changed,
+					 0, *to))
+    {
+      restrict_range (var->children, from, to);
+      return var->children;
+    }
 
   if (var->num_children == -1)
     var->num_children = number_of_children (var);
@@ -1023,6 +1113,7 @@ varobj_list_children (struct varobj *var)
 	}
     }
 
+  restrict_range (var->children, from, to);
   return var->children;
 }
 
@@ -1216,6 +1307,9 @@ install_visualizer (struct varobj *var, PyObject *constructor,
 
   Py_XDECREF (var->pretty_printer);
   var->pretty_printer = visualizer;
+
+  Py_XDECREF (var->child_iter);
+  var->child_iter = NULL;
 }
 
 /* Install the default visualizer for VAR.  */
@@ -1475,30 +1569,15 @@ install_new_value (struct varobj *var, struct value *value, int initial)
   return changed;
 }
 
-/* Return the effective requested range for a varobj.  VAR is the
-   varobj.  CHILDREN is the computed list of children.  FROM and TO
-   are out parameters.  If VAR has no bounds selected, *FROM and *TO
-   will be set to the full range of CHILDREN.  Otherwise, *FROM and
-   *TO will be set to the selected sub-range of VAR, clipped to be in
-   range of CHILDREN.  */
+/* Return the requested range for a varobj.  VAR is the varobj.  FROM
+   and TO are out parameters; *FROM and *TO will be set to the
+   selected sub-range of VAR.  If no range was selected using
+   -var-set-update-range, then both will be -1.  */
 void
-varobj_get_child_range (struct varobj *var, VEC (varobj_p) *children,
-			int *from, int *to)
+varobj_get_child_range (struct varobj *var, int *from, int *to)
 {
-  if (var->from < 0 || var->to < 0)
-    {
-      *from = 0;
-      *to = VEC_length (varobj_p, children);
-    }
-  else
-    {
-      *from = var->from;
-      if (*from > VEC_length (varobj_p, children))
-	*from = VEC_length (varobj_p, children);
-      *to = var->to;
-      if (*to > VEC_length (varobj_p, children))
-	*to = VEC_length (varobj_p, children);
-    }
+  *from = var->from;
+  *to = var->to;
 }
 
 /* Set the selected sub-range of children of VAR to start at index
@@ -1653,7 +1732,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
 	 UI, so we need not bother getting it.  */
       if (v->pretty_printer)
 	{
-	  VEC (varobj_p) *changed = 0, *new_and_unchanged = 0;
+	  VEC (varobj_p) *changed = 0, *new = 0;
 	  int i, children_changed;
 	  varobj_p tmp;
 
@@ -1665,28 +1744,28 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
 
 	  /* If update_dynamic_varobj_children returns 0, then we have
 	     a non-conforming pretty-printer, so we skip it.  */
-	  if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged,
-					      &children_changed))
+	  if (update_dynamic_varobj_children (v, &changed, &new,
+					      &children_changed, 1, v->to))
 	    {
-	      if (children_changed)
-		r.children_changed = 1;
-	      for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
+	      if (children_changed || new)
 		{
-		  varobj_update_result r = {tmp};
-		  r.changed = 1;
-		  r.value_installed = 1;
-		  VEC_safe_push (varobj_update_result, stack, &r);
+		  r.children_changed = 1;
+		  r.new = new;
 		}
-	      for (i = 0;
-		   VEC_iterate (varobj_p, new_and_unchanged, i, tmp);
-		   ++i)
+	      for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
 		{
 		  varobj_update_result r = {tmp};
+		  r.changed = 1;
 		  r.value_installed = 1;
 		  VEC_safe_push (varobj_update_result, stack, &r);
 		}
 	      if (r.changed || r.children_changed)
 		VEC_safe_push (varobj_update_result, result, &r);
+
+	      /* Free CHANGED, but not NEW, because NEW has been put
+		 into the result vector.  */
+	      VEC_free (varobj_p, changed);
+
 	      continue;
 	    }
 	}
@@ -1980,6 +2059,8 @@ new_variable (void)
   var->to = -1;
   var->constructor = 0;
   var->pretty_printer = 0;
+  var->child_iter = 0;
+  var->saved_item = 0;
 
   return var;
 }
@@ -2009,7 +2090,10 @@ free_variable (struct varobj *var)
   if (var->pretty_printer)
     {
       struct cleanup *cleanup = varobj_ensure_python_env (var);
-      Py_DECREF (var->pretty_printer);
+      Py_XDECREF (var->constructor);
+      Py_XDECREF (var->pretty_printer);
+      Py_XDECREF (var->child_iter);
+      Py_XDECREF (var->saved_item);
       do_cleanups (cleanup);
     }
 #endif
@@ -2256,6 +2340,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
       else
 	{
 	  tmp_var->obj_name = xstrdup (var->obj_name);
+	  tmp_var->from = var->from;
+	  tmp_var->to = var->to;
 	  varobj_delete (var, NULL, 0);
 
 	  install_variable (tmp_var);
diff --git a/gdb/varobj.h b/gdb/varobj.h
index 35053f8..635acf9 100644
--- a/gdb/varobj.h
+++ b/gdb/varobj.h
@@ -78,6 +78,12 @@ typedef struct varobj_update_result_t
      new value of varobj is already computed and installed, or has to
      be yet installed.  Don't use this outside varobj.c */
   int value_installed;  
+
+  /* This will be non-NULL when new children were added to the varobj.
+     It lists the new children (which must necessarily come at the end
+     of the child list) added during an update.  The caller is
+     responsible for freeing this vector.  */
+  VEC (varobj_p) *new;
 } varobj_update_result;
 
 DEF_VEC_O (varobj_update_result);
@@ -112,9 +118,7 @@ extern void varobj_set_frozen (struct varobj *var, int frozen);
 
 extern int varobj_get_frozen (struct varobj *var);
 
-extern void varobj_get_child_range (struct varobj *var,
-				    VEC (varobj_p) *children,
-				    int *from, int *to);
+extern void varobj_get_child_range (struct varobj *var, int *from, int *to);
 
 extern void varobj_set_child_range (struct varobj *var, int from, int to);
 
@@ -122,9 +126,16 @@ extern char *varobj_get_display_hint (struct varobj *var);
 
 extern int varobj_get_num_children (struct varobj *var);
 
-/* Return the list of children of VAR.  The returned vector
-   should not be modified in any way.  */
-extern VEC (varobj_p)* varobj_list_children (struct varobj *var);
+/* Return the list of children of VAR.  The returned vector should not
+   be modified in any way.  FROM and TO are in/out parameters
+   indicating the range of children to return.  If either *FROM or *TO
+   is less than zero on entry, then all children will be returned.  On
+   return, *FROM and *TO will be updated to indicate the real range
+   that was returned.  The resulting VEC will contain at least the
+   children from *FROM to just before *TO; it might contain more
+   children, depending on whether any more were available.  */
+extern VEC (varobj_p)* varobj_list_children (struct varobj *var,
+					     int *from, int *to);
 
 extern char *varobj_get_type (struct varobj *var);
 
@@ -159,4 +170,6 @@ varobj_set_visualizer (struct varobj *var, const char *visualizer);
 
 extern void varobj_enable_pretty_printing (void);
 
+extern int varobj_has_more (struct varobj *var, int to);
+
 #endif /* VAROBJ_H */


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