[PATCH:MI] Return a subset of a variable object's children

Nick Roberts
2008-04-27T11:14:54Z

This patch allows -var-list-children to create just some of a variable object's
children. Following a discussion last year with Mark Khouzam, this is useful
for displaying large arrays (and structures) where it would take too long to
create all the children: it is only really necessary to create those that are
visible on the screen and update as further become visible. It also allows a
step size (stride) other than one.

ISTR that it was said a long time ago that mi_getopt won't take long options
but that doesn't seem to be the case. The difficulty is that
-var-list-children takes 0, 1 and 2 as options so I've had to separate the
logic to keep it backward compatible.

Use of these new options means that the elements might not be printed in order
but it is always preserved if only the old options are used.

Example of use (Note subsequent -var-list-children _adds_ to list):

n
&"n\n"
~~"151\t int i, n, m[10] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81};\n"
^done
(gdb)
n
&"n\n"
~"152\t int m1[2][3] = {{0, 1, 2}, {10, 11, 12}};\n"
^done
(gdb)
-var-create - * m
^done,name="var1",numchild="10",value="[10]",type="int [10]",thread-id="1"
(gdb)
-var-list-children -f 7 -n 2 --all-values var1
^done,numchild="2",children=[child={name="var1.7",exp="7",numchild="0",value="49",type="int",thread-id="1"},child={name="var1.8",exp="8",numchild="0",value="64",type="int",thread-id="1"}]
(gdb)
-var-list-children -f 4 -n 3 -s 2 --all-values var1
^done,numchild="4",children=[child={name="var1.7",exp="7",numchild="0",value="49",type="int",thread-id="1"},child={name="var1.8",exp="8",numchild="0",value="64",type="int",thread-id="1"},child={name="var1.4",exp="4",numchild="0",value="16",type="int",thread-id="1"},child={name="var1.6",exp="6",numchild="0",value="36",type="int",thread-id="1"}]
(gdb)

--
Nick http://www.inet.net.nz/~nickrob

2008-04-27 Nick Roberts <nickrob@snap.net.nz>

* mi/mi-cmd-var.c (mi_cmd_var_list_children): Add options to select
a subset of children.

* varobj.h (varobj_list_children): Declare new parameters.

* varobj.c (struct varobj): New member current_children.
(varobj_list_children): Create any new varobjs for children
specified by mi_cmd_var_list_children.
(create_child): Add parameter real_index. Use it.

*** mi-cmd-var.c 20 Apr 2008 10:20:39 +1200 1.50
--- mi-cmd-var.c 27 Apr 2008 21:34:58 +1200
*************** mi_cmd_var_list_children (char *command,
*** 374,397 ****
int numchild;
enum print_values print_values;
int ix;

! if (argc != 1 && argc != 2)
! error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));

! /* Get varobj handle, if a valid var obj name was specified */
! if (argc == 1)
! var = varobj_get_handle (argv[0]);
else
! var = varobj_get_handle (argv[1]);
! if (var == NULL)
! error (_("Variable object not found"));

! children = varobj_list_children (var);
ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
- if (argc == 2)
- print_values = mi_parse_values_option (argv[0]);
- else
- print_values = PRINT_NO_VALUES;

if (VEC_length (varobj_p, children) == 0)
return MI_CMD_DONE;
--- 374,462 ----
int numchild;
enum print_values print_values;
int ix;
+ int start, number, stride = 1;

! enum opt
! {
! NO_VALUES, SIMPLE_VALUES, ALL_VALUES, FROM_OPT, NUMBER_OPT, STRIDE_OPT
! };

! static struct mi_opt opts[] =
! {
! { "-no-values", NO_VALUES, 0 },
! { "-simple-values", SIMPLE_VALUES, 0 },
! { "-all-values", ALL_VALUES, 0 },
! { "f", FROM_OPT, 1 },
! { "n", NUMBER_OPT, 1 },
! { "s", STRIDE_OPT, 1 },
! { 0, 0, 0 }
! };
!
! if (argc == 1 || argc == 2)
! {
! /* Get varobj handle, if a valid var obj name was specified */
! if (argc == 1)
! var = varobj_get_handle (argv[0]);
! else
! var = varobj_get_handle (argv[1]);
! if (var == NULL)
! error (_("Variable object not found"));
!
! if (argc == 2)
! print_values = mi_parse_values_option (argv[0]);
! else
! print_values = PRINT_NO_VALUES;
!
! start = 0;
! number = varobj_get_num_children (var);
! }
else
! {
! int optind = 0;
! char *optarg;
! while (1)
! {
! int opt = mi_getopt ("mi_cmd_var_list_children",
! argc, argv, opts, &optind, &optarg);
! if (opt < 0)
! break;
! switch ((enum opt) opt)
! {
! case NO_VALUES:
! print_values = PRINT_NO_VALUES;
! break;
! case SIMPLE_VALUES:
! print_values = PRINT_SIMPLE_VALUES;
! break;
! case ALL_VALUES:
! print_values = PRINT_ALL_VALUES;
! break;
! case FROM_OPT:
! start = atol (optarg);
! if (start < 0)
! start = 0;
! break;
! case NUMBER_OPT:
! number = atol (optarg);
! break;
! case STRIDE_OPT:
! stride = atol (optarg);
! if (stride < 1)
! error (_("Positive stride values only"));
! break;
! }
! }
! if (optind >= argc)
! error (_("Missing VARNAME"));

! if (optind < argc - 1)
! error (_("Garbage at end of command"));
!
! var = varobj_get_handle (argv[optind]);
! }
!
! children = varobj_list_children (var, start, number, stride);
ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));

if (VEC_length (varobj_p, children) == 0)
return MI_CMD_DONE;

*** varobj.h 10 Apr 2008 08:41:40 +1200 1.18
--- varobj.h 27 Apr 2008 15:14:51 +1200
*************** extern int varobj_get_num_children (stru
*** 99,105 ****

/* 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);

extern char *varobj_get_type (struct varobj *var);

--- 99,106 ----

/* 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, int start,
! int number, int stride);

extern char *varobj_get_type (struct varobj *var);

*** varobj.c 20 Apr 2008 10:20:39 +1200 1.111
--- varobj.c 27 Apr 2008 22:58:28 +1200
*************** struct varobj
*** 131,136 ****
--- 131,140 ----
/* The number of (immediate) children this variable has */
int num_children;

+ /* The number of (immediate) children this variable that exist as varobjs.
+ current_children < num_children */
+ int current_children;
+
/* If this object is a child, this points to its immediate parent. */
struct varobj *parent;

*************** static int install_variable (struct varo
*** 187,193 ****

static void uninstall_variable (struct varobj *);

! static struct varobj *create_child (struct varobj *, int, char *);

/* Utility routines */

--- 191,197 ----

static void uninstall_variable (struct varobj *);

! static struct varobj *create_child (struct varobj *, int, int, char *);

/* Utility routines */

*************** varobj_get_num_children (struct varobj *
*** 752,762 ****
the return code is the number of such children or -1 on error */

VEC (varobj_p)*
! varobj_list_children (struct varobj *var)
{
struct varobj *child;
char *name;
! int i;

if (var->num_children == -1)
var->num_children = number_of_children (var);
--- 756,767 ----
the return code is the number of such children or -1 on error */

VEC (varobj_p)*
! varobj_list_children (struct varobj *var, int start, int number, int stride)
{
struct varobj *child;
char *name;
! int i, j, new_children = 0;
! varobj_p varchild;

if (var->num_children == -1)
var->num_children = number_of_children (var);
*************** varobj_list_children (struct varobj *var
*** 765,790 ****
if (var->num_children == -1)
return var->children;

! /* If we're called when the list of children is not yet initialized,
! allocate enough elements in it. */
! while (VEC_length (varobj_p, var->children) < var->num_children)
! VEC_safe_push (varobj_p, var->children, NULL);
!
! for (i = 0; i < var->num_children; i++)
! {
! varobj_p existing = VEC_index (varobj_p, var->children, i);
!
! if (existing == NULL)
! {
! /* Either it's the first call to varobj_list_children for
! this variable object, and the child was never created,
! or it was explicitly deleted by the client. */
! name = name_of_child (var, i);
! existing = create_child (var, i, name);
! VEC_replace (varobj_p, var->children, i, existing);
}
}

return var->children;
}

--- 770,800 ----
if (var->num_children == -1)
return var->children;

! for (j = 0; j < number; j++)
! {
! int real_index = start + j * stride;
! if (real_index >= var->num_children)
! break;
! name = name_of_child (var, real_index);
!
! for (i = 0; i < var->current_children; i++)
! {
! varchild = VEC_index (varobj_p, var->children, i);
!
! /* Child already exists */
! if (strcmp (varchild->name, name) == 0)
! break;
! }
! /* No child found */
! if (i == var->current_children)
! {
! varchild = create_child (var, i + new_children, real_index, name);
! VEC_safe_push (varobj_p, var->children, varchild);
! new_children++;
}
}

+ var->current_children += new_children;
return var->children;
}

*************** uninstall_variable (struct varobj *var)
*** 1442,1448 ****

/* Create and install a child of the parent of the given name */
static struct varobj *
! create_child (struct varobj *parent, int index, char *name)
{
struct varobj *child;
char *childs_name;
--- 1452,1458 ----

/* Create and install a child of the parent of the given name */
static struct varobj *
! create_child (struct varobj *parent, int index, int real_index, char *name)
{
struct varobj *child;
char *childs_name;
*************** create_child (struct varobj *parent, int
*** 1453,1459 ****
/* name is allocated by name_of_child */
child->name = name;
child->index = index;
! value = value_of_child (parent, index);
child->parent = parent;
child->root = parent->root;
childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
--- 1463,1469 ----
/* name is allocated by name_of_child */
child->name = name;
child->index = index;
! value = value_of_child (parent, real_index);
child->parent = parent;
child->root = parent->root;
childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
*************** new_variable (void)
*** 1494,1499 ****
--- 1504,1510 ----
var->type = NULL;
var->value = NULL;
var->num_children = -1;
+ var->current_children = 0;
var->parent = NULL;
var->children = NULL;
var->format = 0;