This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/3] new observer command_param_changed.
Hi,
This patch is to teach GDB to check the change of command option,
and notify observer.
Compared with V2, V3 has following changes,
1. Move notifying 'command_option_changed' observer at the end of
do_set_command to make sure the command is correctly executed,
2. Add a field 'prefix' to track the prefix command in order to
get the whole command options in multi-word command.
3. Split do_setshow_command to do_set_command and do_show_command.
4. Don't call observer for command of class class_maintenance and
class_deprecated.
Note that in order to make patch easier to read, the indnetation is
not adjusted. Indentation is fixed in a separate patch.
gdb:
2012-08-03 Yao Qi <yao@codesourcery.com>
* cli/cli-setshow.c (notify_command_param_changed_p): New.
(add_setshow_auto_boolean_cmd): Move
auto_boolean_enums out. Remove 'static'.
(lookup_cmd_for_prefixlist): New.
(add_setshow_cmd_full): Set field 'prefix'.
* cli/cli-decode.h (struct cmd_list_element) <prefix>: New field.
Declare 'auto_boolean_enums'.
* cli/cli-setshow.c: Include "observer.h".
(do_setshow_command): Split it to ...
(do_set_command, do_show_command): ... them. New.
(do_set_command): Call observer_notify_command_param_changed if
notify_command_param_changed_p returns true.
(cmd_show_list): Caller update.
* auto-load.c (set_auto_load_cmd): Likewise.
* remote.c (show_remote_cmd): Likewise.
* cli/cli-setshow.h: Update declarations.
* top.c (execute_command): Call do_set_command and do_show_command.
gdb/doc:
2012-08-03 Yao Qi <yao@codesourcery.com>
* observer.texi: New observer command_param_changed.
---
gdb/auto-load.c | 2 +-
gdb/cli/cli-decode.c | 51 ++++++++++-
gdb/cli/cli-decode.h | 4 +
gdb/cli/cli-setshow.c | 260 +++++++++++++++++++++++++++++++++++++++++-------
gdb/cli/cli-setshow.h | 10 +-
gdb/doc/observer.texi | 8 ++
gdb/remote.c | 2 +-
gdb/top.c | 6 +-
8 files changed, 294 insertions(+), 49 deletions(-)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index 2cc52c6..03a7539 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -1022,7 +1022,7 @@ set_auto_load_cmd (char *args, int from_tty)
if (list->var_type == var_boolean)
{
gdb_assert (list->type == set_cmd);
- do_setshow_command (args, from_tty, list);
+ do_set_command (args, from_tty, list);
}
}
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index c337b43..a0f1017 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -52,6 +52,32 @@ static struct cmd_list_element *find_cmd (char *command,
static void help_all (struct ui_file *stream);
+/* Look up a command whose 'prefixlist' is KEY. Return the command if found,
+ otherwise return NULL. */
+
+static struct cmd_list_element *
+lookup_cmd_for_prefixlist (struct cmd_list_element **key,
+ struct cmd_list_element *list)
+{
+ struct cmd_list_element *p = NULL;
+
+ for (p = list; p != NULL; p = p->next)
+ {
+ struct cmd_list_element *q;
+
+ if (p->prefixlist == NULL)
+ continue;
+ else if (p->prefixlist == key)
+ return p;
+
+ q = lookup_cmd_for_prefixlist (key, *(p->prefixlist));
+ if (q != NULL)
+ return q;
+ }
+
+ return NULL;
+}
+
static void
print_help_for_command (struct cmd_list_element *c, char *prefix, int recurse,
struct ui_file *stream);
@@ -193,6 +219,7 @@ add_cmd (char *name, enum command_class class, void (*fun) (char *, int),
c->prefixlist = NULL;
c->prefixname = NULL;
c->allow_unknown = 0;
+ c->prefix = NULL;
c->abbrev_flag = 0;
set_cmd_completer (c, make_symbol_completion_list_fn);
c->destroyer = NULL;
@@ -392,6 +419,27 @@ add_setshow_cmd_full (char *name,
full_set_doc, set_list);
if (set_func != NULL)
set_cmd_sfunc (set, set_func);
+
+
+ {
+ struct cmd_list_element *p;
+ /* Check to see if *SET_LIST contains any element other than SET. */
+ for (p = *set_list; p != NULL; p = p->next)
+ if (p != set)
+ break;
+
+ if (p == NULL)
+ {
+ /* *SET_LIST only contains SET. */
+ p = lookup_cmd_for_prefixlist (set_list, setlist);
+
+ set->prefix = p ? (p->cmd_pointer ? p->cmd_pointer : p) : p;
+ }
+ else
+ set->prefix = p->prefix;
+ }
+
+
show = add_set_or_show_cmd (name, show_cmd, class, var_type, var,
full_show_doc, show_list);
show->show_value_func = show_func;
@@ -430,6 +478,8 @@ add_setshow_enum_cmd (char *name,
c->enums = enumlist;
}
+const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL };
+
/* Add an auto-boolean command named NAME to both the set and show
command list lists. CLASS is as in add_cmd. VAR is address of the
variable which will contain the value. DOC is the documentation
@@ -445,7 +495,6 @@ add_setshow_auto_boolean_cmd (char *name,
struct cmd_list_element **set_list,
struct cmd_list_element **show_list)
{
- static const char *auto_boolean_enums[] = { "on", "off", "auto", NULL };
struct cmd_list_element *c;
add_setshow_cmd_full (name, class, var_auto_boolean, var,
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index b5e0790..edae6e8 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -149,6 +149,9 @@ struct cmd_list_element
recognized; call the prefix's own function in that case. */
char allow_unknown;
+ /* The prefix command of this command. */
+ struct cmd_list_element *prefix;
+
/* Nonzero says this is an abbreviation, and should not
be mentioned in lists of commands.
This allows "br<tab>" to complete to "break", which it
@@ -232,5 +235,6 @@ extern void not_just_help_class_command (char *arg, int from_tty);
extern void print_doc_line (struct ui_file *, char *);
+extern const char * const auto_boolean_enums[];
#endif /* !defined (CLI_DECODE_H) */
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index 7ffb89e..64a447c 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -21,6 +21,7 @@
#include <ctype.h>
#include "gdb_string.h"
#include "arch-utils.h"
+#include "observer.h"
#include "ui-out.h"
@@ -32,6 +33,20 @@
static int parse_binary_operation (char *);
+/* Return true if the change of command parameter should be notified. */
+
+static int
+notify_command_param_changed_p (int param_changed, struct cmd_list_element *c)
+{
+ if (param_changed == 0)
+ return 0;
+
+ if (c->class == class_maintenance || c->class == class_deprecated)
+ return 0;
+
+ return 1;
+}
+
static enum auto_boolean
parse_auto_binary_operation (const char *arg)
@@ -116,18 +131,19 @@ deprecated_show_value_hack (struct ui_file *ignore_file,
}
}
-/* Do a "set" or "show" command. ARG is NULL if no argument, or the
+/* Do a "set" command. ARG is NULL if no argument, or the
text of the argument, and FROM_TTY is nonzero if this command is
being entered directly by the user (i.e. these are just like any
other command). C is the command list element for the command. */
void
-do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
+do_set_command (char *arg, int from_tty, struct cmd_list_element *c)
{
- struct ui_out *uiout = current_uiout;
+ /* A flag to indicate the option is changed or not. */
+ int option_changed = 0;
+
+ gdb_assert (c->type == set_cmd);
- if (c->type == set_cmd)
- {
switch (c->var_type)
{
case var_string:
@@ -170,50 +186,106 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
#endif
*q++ = '\0';
new = (char *) xrealloc (new, q - new);
- xfree (*(char **) c->var);
- *(char **) c->var = new;
+
+ if (*(char **) c->var == NULL
+ || strcmp (*(char **) c->var, new) != 0)
+ {
+ xfree (*(char **) c->var);
+ *(char **) c->var = new;
+
+ option_changed = 1;
+ }
+ else
+ xfree (new);
}
break;
case var_string_noescape:
if (arg == NULL)
arg = "";
- xfree (*(char **) c->var);
- *(char **) c->var = xstrdup (arg);
+
+ if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0)
+ {
+ xfree (*(char **) c->var);
+ *(char **) c->var = xstrdup (arg);
+
+ option_changed = 1;
+ }
break;
case var_filename:
if (arg == NULL)
error_no_arg (_("filename to set it to."));
/* FALLTHROUGH */
case var_optional_filename:
- xfree (*(char **) c->var);
+ {
+ char *val = NULL;
- if (arg != NULL)
- {
- /* Clear trailing whitespace of filename. */
- char *ptr = arg + strlen (arg) - 1;
+ if (arg != NULL)
+ {
+ /* Clear trailing whitespace of filename. */
+ char *ptr = arg + strlen (arg) - 1;
- while (ptr >= arg && (*ptr == ' ' || *ptr == '\t'))
- ptr--;
- *(ptr + 1) = '\0';
+ while (ptr >= arg && (*ptr == ' ' || *ptr == '\t'))
+ ptr--;
+ *(ptr + 1) = '\0';
- *(char **) c->var = tilde_expand (arg);
- }
- else
- *(char **) c->var = xstrdup ("");
+ val = tilde_expand (arg);
+ }
+ else
+ val = xstrdup ("");
+
+ if (*(char **) c->var == NULL
+ || strcmp (*(char **) c->var, val) != 0)
+ {
+ xfree (*(char **) c->var);
+ *(char **) c->var = val;
+
+ option_changed = 1;
+ }
+ else
+ xfree (val);
+ }
break;
case var_boolean:
- *(int *) c->var = parse_binary_operation (arg);
+ {
+ int val = parse_binary_operation (arg);
+
+ if (val != *(int *) c->var)
+ {
+ *(int *) c->var = val;
+
+ option_changed = 1;
+ }
+ }
break;
case var_auto_boolean:
- *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg);
+ {
+ enum auto_boolean val = parse_auto_binary_operation (arg);
+
+ if (*(enum auto_boolean *) c->var != val)
+ {
+ *(enum auto_boolean *) c->var = val;
+
+ option_changed = 1;
+ }
+ }
break;
case var_uinteger:
case var_zuinteger:
if (arg == NULL)
error_no_arg (_("integer to set it to."));
- *(unsigned int *) c->var = parse_and_eval_long (arg);
- if (c->var_type == var_uinteger && *(unsigned int *) c->var == 0)
- *(unsigned int *) c->var = UINT_MAX;
+ {
+ unsigned int val = parse_and_eval_long (arg);
+
+ if (c->var_type == var_uinteger && val == 0)
+ val = UINT_MAX;
+
+ if (*(unsigned int *) c->var != val)
+ {
+ *(unsigned int *) c->var = val;
+
+ option_changed = 1;
+ }
+ }
break;
case var_integer:
case var_zinteger:
@@ -224,11 +296,17 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
error_no_arg (_("integer to set it to."));
val = parse_and_eval_long (arg);
if (val == 0 && c->var_type == var_integer)
- *(int *) c->var = INT_MAX;
+ val = INT_MAX;
else if (val >= INT_MAX)
error (_("integer %u out of range"), val);
- else
- *(int *) c->var = val;
+
+
+ if (*(int *) c->var != val)
+ {
+ *(int *) c->var = val;
+
+ option_changed = 1;
+ }
break;
}
case var_enum:
@@ -293,15 +371,124 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
if (nmatches > 1)
error (_("Ambiguous item \"%s\"."), arg);
- *(const char **) c->var = match;
+ if (*(const char **) c->var != match)
+ {
+ *(const char **) c->var = match;
+
+ option_changed = 1;
+ }
}
break;
default:
error (_("gdb internal error: bad var_type in do_setshow_command"));
}
- }
- else if (c->type == show_cmd)
+ c->func (c, NULL, from_tty);
+ if (deprecated_set_hook)
+ deprecated_set_hook (c);
+
+ if (notify_command_param_changed_p (option_changed, c))
{
+ char name[64];
+
+ /* Compute the whole multi-word command options. If user types command
+ 'set foo bar baz on', c->name is 'baz', and GDB can't pass "bar" to
+ command option change notification, because it is confusing. We can
+ trace back through field 'prefix' to compute the whole options,
+ and pass "foo bar baz" to notification. */
+ {
+ /* Assume that the number of command option is less than 6. */
+ struct cmd_list_element *cmds[6];
+ struct cmd_list_element *p = c;
+ int i = 0;
+ int length = 0;
+ char *cp;
+
+ /* Track back through filed 'prefix' and cache them in CMDS. */
+ do
+ {
+ if (p == NULL)
+ break;
+
+ cmds[i++] = p;
+ length += strlen (p->name);
+ length++;
+
+ p = p->prefix;
+ }
+ while (i < (sizeof (cmds) / sizeof (struct cmd_list_element *)));
+
+ cp = name;
+ /* Traverse them in the reversed order, and copy their names into
+ NAME. */
+ for (i--; i >= 0; i--)
+ {
+ strcpy (cp, cmds[i]->name);
+ cp += strlen (cmds[i]->name);
+
+ cp[0] = ' ';
+ cp++;
+ }
+ cp--;
+ cp[0] = 0;
+ }
+
+ switch (c->var_type)
+ {
+ case var_string:
+ case var_string_noescape:
+ case var_filename:
+ case var_optional_filename:
+ case var_enum:
+ observer_notify_command_param_changed (name, *(char **) c->var);
+ break;
+ case var_boolean:
+ {
+ char *opt = *(int *) c->var ? "on" : "off";
+
+ observer_notify_command_param_changed (name, opt);
+ }
+ break;
+ case var_auto_boolean:
+ {
+ const char *s = auto_boolean_enums[*(enum auto_boolean *) c->var];
+
+ observer_notify_command_param_changed (name, s);
+ }
+ break;
+ case var_uinteger:
+ case var_zuinteger:
+ {
+ char s[64];
+
+ xsnprintf (s, sizeof s, "%u", *(unsigned int *) c->var);
+ observer_notify_command_param_changed (name, s);
+ }
+ break;
+ case var_integer:
+ case var_zinteger:
+ {
+ char s[64];
+
+ xsnprintf (s, sizeof s, "%d", *(int *) c->var);
+ observer_notify_command_param_changed (name, s);
+ }
+ break;
+ }
+ }
+}
+
+/* Do a "show" command. ARG is NULL if no argument, or the
+ text of the argument, and FROM_TTY is nonzero if this command is
+ being entered directly by the user (i.e. these are just like any
+ other command). C is the command list element for the command. */
+
+void
+do_show_command (char *arg, int from_tty, struct cmd_list_element *c)
+{
+ struct ui_out *uiout = current_uiout;
+
+ gdb_assert (c->type == show_cmd);
+ {
struct cleanup *old_chain;
struct ui_file *stb;
@@ -387,12 +574,9 @@ do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c)
deprecated_show_value_hack (gdb_stdout, from_tty, c, value);
}
do_cleanups (old_chain);
- }
- else
- error (_("gdb internal error: bad cmd_type in do_setshow_command"));
+
c->func (c, NULL, from_tty);
- if (c->type == set_cmd && deprecated_set_hook)
- deprecated_set_hook (c);
+ }
}
/* Show all the settings in a list of show commands. */
@@ -431,7 +615,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty, char *prefix)
ui_out_field_string (uiout, "name", list->name);
ui_out_text (uiout, ": ");
if (list->type == show_cmd)
- do_setshow_command ((char *) NULL, from_tty, list);
+ do_show_command ((char *) NULL, from_tty, list);
else
cmd_func (list, NULL, from_tty);
/* Close the tuple. */
diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h
index cb8d2c5..ffe9abd 100644
--- a/gdb/cli/cli-setshow.h
+++ b/gdb/cli/cli-setshow.h
@@ -21,12 +21,10 @@ struct cmd_list_element;
/* Exported to cli/cli-cmds.c and gdb/top.c */
-/* Do a "set" or "show" command. ARG is NULL if no argument, or the
- text of the argument, and FROM_TTY is nonzero if this command is
- being entered directly by the user (i.e. these are just like any
- other command). C is the command list element for the command. */
-extern void do_setshow_command (char *arg, int from_tty,
- struct cmd_list_element *c);
+extern void do_set_command (char *arg, int from_tty,
+ struct cmd_list_element *c);
+extern void do_show_command (char *arg, int from_tty,
+ struct cmd_list_element *c);
/* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index 14d4ac3..bf84820 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -234,6 +234,14 @@ the current top-level prompt.
Variable gdb_datadir has been set. The value may not necessarily change.
@end deftypefun
+@deftypefun void command_param_changed (const char *@var{param}, const char *@var{value})
+The parameter of some @code{set} commands in console are changed. This
+method is called after a command @code{set @var{param} @var{value}}.
+@var{param} is the parameter of @code{set} command, and @var{value}
+is the value of changed parameter.
+
+@end deftypefun
+
@deftypefun void test_notification (int @var{somearg})
This observer is used for internal testing. Do not use.
See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/remote.c b/gdb/remote.c
index fa514dc..87b8921 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11270,7 +11270,7 @@ show_remote_cmd (char *args, int from_tty)
ui_out_field_string (uiout, "name", list->name);
ui_out_text (uiout, ": ");
if (list->type == show_cmd)
- do_setshow_command ((char *) NULL, from_tty, list);
+ do_show_command ((char *) NULL, from_tty, list);
else
cmd_func (list, NULL, from_tty);
/* Close the tuple. */
diff --git a/gdb/top.c b/gdb/top.c
index 213c68c..8251d1b 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -474,8 +474,10 @@ execute_command (char *p, int from_tty)
/* c->user_commands would be NULL in the case of a python command. */
if (c->class == class_user && c->user_commands)
execute_user_command (c, arg);
- else if (c->type == set_cmd || c->type == show_cmd)
- do_setshow_command (arg, from_tty, c);
+ else if (c->type == set_cmd)
+ do_set_command (arg, from_tty, c);
+ else if (c->type == show_cmd)
+ do_show_command (arg, from_tty, c);
else if (!cmd_func_p (c))
error (_("That is not a command, just a help topic."));
else if (deprecated_call_command_hook)
--
1.7.7.6