RE: [Patch] -var-evaluate-expression NAME [FORMAT]

Marc Khouzam
2008-02-01T19:23:59Z

Sorry for the delay.

Thanks for the comments.

> We replace leading eight space sequences with tabs, and
> parameters should line up.

I have fixed this and fixed a couple of other spots that were
not following that rule in the two or three files I affected.

> The grammar for MI commands says options always come first. They're
> optional, anyway, so how about -var-evaluate-expression [-f
> @var{format-spec}] @var{name}?

Yes, I like that better too.
I have updated the code, the tests and the doc to follow this format.
Maybe Eli wants to re-approve?

> Yes, we do live in the distant past. If you add a #include, you have
> to manually update gdb/Makefile.in.

Good you noticed.
Fixed.

Here is the revised patch.
I rebuilt (not the doc) and ran regression.

Marc

===
### Eclipse Workspace Patch 1.0
#P src
Index: gdb/testsuite/gdb.mi/mi-var-display.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.mi/mi-var-display.exp,v
retrieving revision 1.21
diff -u -r1.21 mi-var-display.exp
--- gdb/testsuite/gdb.mi/mi-var-display.exp 23 Jan 2008 06:20:57 -0000 1.21
+++ gdb/testsuite/gdb.mi/mi-var-display.exp 1 Feb 2008 19:12:01 -0000
@@ -171,6 +171,49 @@
mi_gdb_test "-var-evaluate-expression foo" \
"\\^done,value=\"3\"" \
"eval variable foo"
+
+# Test: c_variable-6.19
+# Desc: check optional format parameter of var-evaluate-expression
+# and check that current format is not changed
+mi_gdb_test "-var-evaluate-expression -f hex foo" \
+ "\\^done,value=\"0x3\"" \
+ "eval variable foo in hex"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in hex"
+
+mi_gdb_test "-var-evaluate-expression -f octal foo" \
+ "\\^done,value=\"03\"" \
+ "eval variable foo in octal"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in octal"
+
+mi_gdb_test "-var-evaluate-expression -f decimal foo" \
+ "\\^done,value=\"3\"" \
+ "eval variable foo in decimal"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in decimal"
+
+mi_gdb_test "-var-evaluate-expression -f nat foo" \
+ "\\^done,value=\"0x3\"" \
+ "eval variable foo in natural"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in natural"
+
+mi_gdb_test "-var-evaluate-expression -f bin foo" \
+ "\\^done,value=\"11\"" \
+ "eval variable foo in binary"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in binary"

mi_gdb_test "-var-delete foo" \
"\\^done,ndeleted=\"1\"" \
Index: gdb/testsuite/gdb.mi/mi2-var-display.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.mi/mi2-var-display.exp,v
retrieving revision 1.14
diff -u -r1.14 mi2-var-display.exp
--- gdb/testsuite/gdb.mi/mi2-var-display.exp 23 Jan 2008 21:05:16 -0000 1.14
+++ gdb/testsuite/gdb.mi/mi2-var-display.exp 1 Feb 2008 19:12:01 -0000
@@ -171,6 +171,49 @@
mi_gdb_test "-var-evaluate-expression foo" \
"\\^done,value=\"3\"" \
"eval variable foo"
+
+# Test: c_variable-6.19
+# Desc: check optional format parameter of var-evaluate-expression
+# and check that current format is not changed
+mi_gdb_test "-var-evaluate-expression -f hex foo" \
+ "\\^done,value=\"0x3\"" \
+ "eval variable foo in hex"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in hex"
+
+mi_gdb_test "-var-evaluate-expression -f octal foo" \
+ "\\^done,value=\"03\"" \
+ "eval variable foo in octal"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in octal"
+
+mi_gdb_test "-var-evaluate-expression -f decimal foo" \
+ "\\^done,value=\"3\"" \
+ "eval variable foo in decimal"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in decimal"
+
+mi_gdb_test "-var-evaluate-expression -f nat foo" \
+ "\\^done,value=\"0x3\"" \
+ "eval variable foo in natural"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in natural"
+
+mi_gdb_test "-var-evaluate-expression -f bin foo" \
+ "\\^done,value=\"11\"" \
+ "eval variable foo in binary"
+
+mi_gdb_test "-var-show-format foo" \
+ "\\^done,format=\"decimal\"" \
+ "show format variable foo after eval in binary"

mi_gdb_test "-var-delete foo" \
"\\^done,ndeleted=\"1\"" \
Index: gdb/varobj.h
===================================================================
RCS file: /cvs/src/src/gdb/varobj.h,v
retrieving revision 1.15
diff -u -r1.15 varobj.h
--- gdb/varobj.h 30 Jan 2008 07:17:31 -0000 1.15
+++ gdb/varobj.h 1 Feb 2008 19:11:56 -0000
@@ -109,6 +109,9 @@

extern int varobj_get_attributes (struct varobj *var);

+extern char *varobj_get_formatted_value (struct varobj *var,
+ enum varobj_display_formats format);
+
extern char *varobj_get_value (struct varobj *var);

extern int varobj_set_value (struct varobj *var, char *expression);
Index: gdb/varobj.c
===================================================================
RCS file: /cvs/src/src/gdb/varobj.c,v
retrieving revision 1.101
diff -u -r1.101 varobj.c
--- gdb/varobj.c 30 Jan 2008 07:17:31 -0000 1.101
+++ gdb/varobj.c 1 Feb 2008 19:11:56 -0000
@@ -188,6 +188,9 @@

static struct cleanup *make_cleanup_free_variable (struct varobj *var);

+static struct cleanup *make_cleanup_set_format (struct varobj *var,
+ enum varobj_display_formats format);
+
static struct type *get_type (struct varobj *var);

static struct type *get_value_type (struct varobj *var);
@@ -831,6 +834,24 @@
return my_value_of_variable (var);
}

+char *
+varobj_get_formatted_value (struct varobj *var,
+ enum varobj_display_formats format)
+{
+ enum varobj_display_formats oldformat;
+ struct cleanup *old_chain;
+ char* value;
+
+ oldformat = var->format;
+ old_chain = make_cleanup_set_format (var, oldformat);
+
+ var->format = format;
+ value = my_value_of_variable (var);
+
+ do_cleanups (old_chain);
+ return value;
+}
+
/* Set the value of an object variable (if it is editable) to the
value of the given expression */
/* Note: Invokes functions that can call error() */
@@ -1034,7 +1055,7 @@
value. */
changed = 1;
}
- else if (var->value == NULL && value == NULL)
+ else if (var->value == NULL && value == NULL)
/* Equal. */
;
else if (var->value == NULL || value == NULL)
@@ -1144,7 +1165,7 @@
if (type_changed)
VEC_safe_push (varobj_p, result, *varp);

- if (install_new_value ((*varp), new, type_changed))
+ if (install_new_value ((*varp), new, type_changed))
{
/* If type_changed is 1, install_new_value will never return
non-zero, so we'll never report the same variable twice. */
@@ -1520,6 +1541,36 @@
return make_cleanup (do_free_variable_cleanup, var);
}

+struct cleanup_set_format_struct
+{
+ struct varobj *var;
+ enum varobj_display_formats format;
+};
+
+static void
+do_set_format_cleanup (void *cleanup_set_format)
+{
+ struct cleanup_set_format_struct *cleanup_struct = cleanup_set_format;
+
+ varobj_set_display_format (cleanup_struct->var,
+ cleanup_struct->format);
+
+ xfree (cleanup_struct);
+}
+
+static struct cleanup *
+make_cleanup_set_format (struct varobj *var,
+ enum varobj_display_formats format)
+{
+ struct cleanup_set_format_struct *cleanup_struct;
+
+ cleanup_struct = XMALLOC (struct cleanup_set_format_struct);
+ cleanup_struct->var = var;
+ cleanup_struct->format = format;
+
+ return make_cleanup (do_set_format_cleanup, cleanup_struct);
+}
+
/* This returns the type of the variable. It also skips past typedefs
to return the real type of the variable.

@@ -2693,26 +2744,26 @@
while (*varp != NULL)
{
/* global var must be re-evaluated. */
- if ((*varp)->root->valid_block == NULL)
- {
- struct varobj *tmp_var;
-
- /* Try to create a varobj with same expression. If we succeed replace
- the old varobj, otherwise invalidate it. */
- tmp_var = varobj_create (NULL, (*varp)->name, (CORE_ADDR) 0, USE_CURRENT_FRAME);
- if (tmp_var != NULL)
- {
- tmp_var->obj_name = xstrdup ((*varp)->obj_name);
- varobj_delete (*varp, NULL, 0);
- install_variable (tmp_var);
- }
- else
- (*varp)->root->is_valid = 0;
- }
- else /* locals must be invalidated. */
- (*varp)->root->is_valid = 0;
+ if ((*varp)->root->valid_block == NULL)
+ {
+ struct varobj *tmp_var;
+
+ /* Try to create a varobj with same expression. If we succeed replace
+ the old varobj, otherwise invalidate it. */
+ tmp_var = varobj_create (NULL, (*varp)->name, (CORE_ADDR) 0, USE_CURRENT_FRAME);
+ if (tmp_var != NULL)
+ {
+ tmp_var->obj_name = xstrdup ((*varp)->obj_name);
+ varobj_delete (*varp, NULL, 0);
+ install_variable (tmp_var);
+ }
+ else
+ (*varp)->root->is_valid = 0;
+ }
+ else /* locals must be invalidated. */
+ (*varp)->root->is_valid = 0;

- varp++;
+ varp++;
}
xfree (all_rootvarobj);
}
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.978
diff -u -r1.978 Makefile.in
--- gdb/Makefile.in 30 Jan 2008 07:17:31 -0000 1.978
+++ gdb/Makefile.in 1 Feb 2008 19:11:55 -0000
@@ -3208,7 +3208,7 @@
$(mi_getopt_h) $(remote_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-cmd-target.c
mi-cmd-var.o: $(srcdir)/mi/mi-cmd-var.c $(defs_h) $(mi_cmds_h) $(ui_out_h) \
- $(mi_out_h) $(varobj_h) $(value_h) $(gdb_string_h)
+ $(mi_out_h) $(varobj_h) $(value_h) $(gdb_string_h) $(mi_getopt_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-cmd-var.c
mi-console.o: $(srcdir)/mi/mi-console.c $(defs_h) $(mi_console_h) \
$(gdb_string_h)
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.466
diff -u -r1.466 gdb.texinfo
--- gdb/doc/gdb.texinfo 31 Jan 2008 13:38:49 -0000 1.466
+++ gdb/doc/gdb.texinfo 1 Feb 2008 19:12:00 -0000
@@ -20095,12 +20095,16 @@
@subsubheading Synopsis

@smallexample
- -var-evaluate-expression @var{name}
+ -var-evaluate-expression [-f @var{format-spec}] @var{name}
@end smallexample

Evaluates the expression that is represented by the specified variable
-object and returns its value as a string. The format of the
-string can be changed using the @code{-var-set-format} command.
+object and returns its value as a string. The format of the string
+can be specified with the @samp{-f} option. The possible values of
+this option are the same as for @code{-var-set-format}
+(@pxref{-var-set-format}). If the @samp{-f} option is not specified,
+the current display format will be used. The current display format
+can be changed using the @code{-var-set-format} command.

@smallexample
value=@var{value}
@@ -20153,7 +20157,7 @@
object names, all existing variable objects are updated, except
for frozen ones (@pxref{-var-set-frozen}). The option
@var{print-values} determines whether both names and values, or just
-names are printed. The possible values of this options are the same
+names are printed. The possible values of this option are the same
as for @code{-var-list-children} (@pxref{-var-list-children}). It is
recommended to use the @samp{--all-values} option, to reduce the
number of MI commands needed on each program stop.
Index: gdb/mi/mi-cmd-var.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmd-var.c,v
retrieving revision 1.45
diff -u -r1.45 mi-cmd-var.c
--- gdb/mi/mi-cmd-var.c 30 Jan 2008 07:17:31 -0000 1.45
+++ gdb/mi/mi-cmd-var.c 1 Feb 2008 19:12:01 -0000
@@ -28,6 +28,7 @@
#include "value.h"
#include <ctype.h>
#include "gdb_string.h"
+#include "mi-getopt.h"

const char mi_no_values[] = "--no-values";
const char mi_simple_values[] = "--simple-values";
@@ -190,11 +191,33 @@
return MI_CMD_DONE;
}

+/* Parse a string argument into a format value. */
+
+static enum varobj_display_formats
+mi_parse_format (const char *arg)
+{
+ int len;
+
+ len = strlen (arg);
+
+ if (strncmp (arg, "natural", len) == 0)
+ return FORMAT_NATURAL;
+ else if (strncmp (arg, "binary", len) == 0)
+ return FORMAT_BINARY;
+ else if (strncmp (arg, "decimal", len) == 0)
+ return FORMAT_DECIMAL;
+ else if (strncmp (arg, "hexadecimal", len) == 0)
+ return FORMAT_HEXADECIMAL;
+ else if (strncmp (arg, "octal", len) == 0)
+ return FORMAT_OCTAL;
+ else
+ error (_("Unknown display format: must be: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\""));
+}
+
enum mi_cmd_result
mi_cmd_var_set_format (char *command, char **argv, int argc)
{
enum varobj_display_formats format;
- int len;
struct varobj *var;
char *formspec;

@@ -211,21 +234,8 @@
if (formspec == NULL)
error (_("mi_cmd_var_set_format: Must specify the format as: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\""));

- len = strlen (formspec);
-
- if (strncmp (formspec, "natural", len) == 0)
- format = FORMAT_NATURAL;
- else if (strncmp (formspec, "binary", len) == 0)
- format = FORMAT_BINARY;
- else if (strncmp (formspec, "decimal", len) == 0)
- format = FORMAT_DECIMAL;
- else if (strncmp (formspec, "hexadecimal", len) == 0)
- format = FORMAT_HEXADECIMAL;
- else if (strncmp (formspec, "octal", len) == 0)
- format = FORMAT_OCTAL;
- else
- error (_("mi_cmd_var_set_format: Unknown display format: must be: \"natural\", \"binary\", \"decimal\", \"hexadecimal\", or \"octal\""));
-
+ format = mi_parse_format (formspec);
+
/* Set the format of VAR to given format */
varobj_set_display_format (var, format);

@@ -487,16 +497,58 @@
mi_cmd_var_evaluate_expression (char *command, char **argv, int argc)
{
struct varobj *var;
+ enum varobj_display_formats format;
+ int formatFound;
+ int optind;
+ char *optarg;
+
+ enum opt
+ {
+ OP_FORMAT
+ };
+ static struct mi_opt opts[] =
+ {
+ {"f", OP_FORMAT, 1},
+ { 0, 0, 0 }
+ };
+
+ /* Parse arguments */
+ format = FORMAT_NATURAL;
+ formatFound = 0;
+ optind = 0;
+ while (1)
+ {
+ int opt = mi_getopt ("mi_cmd_var_evaluate_expression", argc, argv, opts, &optind, &optarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case OP_FORMAT:
+ if (formatFound)
+ error (_("mi_cmd_var_evaluate_expression: cannot specify format more than once"));

- if (argc != 1)
- error (_("mi_cmd_var_evaluate_expression: Usage: NAME."));
+ format = mi_parse_format (optarg);
+ formatFound = 1;
+ break;
+ }
+ }
+
+ if (optind >= argc)
+ error (_("mi_cmd_var_evaluate_expression: Usage: [-f FORMAT] NAME"));

+ if (optind < argc - 1)
+ error (_("mi_cmd_var_evaluate_expression: Garbage at end of command"));
+
/* Get varobj handle, if a valid var obj name was specified */
- var = varobj_get_handle (argv[0]);
+ var = varobj_get_handle (argv[optind]);
if (var == NULL)
error (_("mi_cmd_var_evaluate_expression: Variable object not found"));

- ui_out_field_string (uiout, "value", varobj_get_value (var));
+ if (formatFound)
+ ui_out_field_string (uiout, "value", varobj_get_formatted_value (var, format));
+ else
+ ui_out_field_string (uiout, "value", varobj_get_value (var));
+
return MI_CMD_DONE;
}

@@ -558,9 +610,9 @@
nv = varobj_list (&rootlist);
cleanup = make_cleanup (xfree, rootlist);
if (mi_version (uiout) <= 1)
- make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
+ make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
else
- make_cleanup_ui_out_list_begin_end (uiout, "changelist");
+ make_cleanup_ui_out_list_begin_end (uiout, "changelist");
if (nv <= 0)
{
do_cleanups (cleanup);
@@ -582,9 +634,9 @@
error (_("mi_cmd_var_update: Variable object not found"));

if (mi_version (uiout) <= 1)
- cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "changelist");
else
- cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist");
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changelist");
varobj_update_one (var, print_values, 1 /* explicit */);
do_cleanups (cleanup);
}
@@ -613,26 +665,26 @@
else if (nc < 0)
{
if (mi_version (uiout) > 1)
- cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+ cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_string (uiout, "name", varobj_get_objname(var));

switch (nc)
{
- case NOT_IN_SCOPE:
- ui_out_field_string (uiout, "in_scope", "false");
+ case NOT_IN_SCOPE:
+ ui_out_field_string (uiout, "in_scope", "false");
+ break;
+ case INVALID:
+ ui_out_field_string (uiout, "in_scope", "invalid");
break;
- case INVALID:
- ui_out_field_string (uiout, "in_scope", "invalid");
- break;
- case TYPE_CHANGED:
+ case TYPE_CHANGED:
ui_out_field_string (uiout, "in_scope", "true");
- ui_out_field_string (uiout, "new_type", varobj_get_type(var));
- ui_out_field_int (uiout, "new_num_children",
+ ui_out_field_string (uiout, "new_type", varobj_get_type(var));
+ ui_out_field_int (uiout, "new_num_children",
varobj_get_num_children(var));
break;
}
if (mi_version (uiout) > 1)
- do_cleanups (cleanup);
+ do_cleanups (cleanup);
}
else
{