From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28152 invoked by alias); 3 Aug 2012 11:22:27 -0000 Received: (qmail 27838 invoked by uid 22791); 3 Aug 2012 11:22:23 -0000 X-SWARE-Spam-Status: No, hits=-4.3 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP,TW_XS X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 03 Aug 2012 11:21:56 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1SxFx5-0004m6-T4 from Yao_Qi@mentor.com for gdb-patches@sourceware.org; Fri, 03 Aug 2012 04:21:55 -0700 Received: from SVR-ORW-FEM-05.mgc.mentorg.com ([147.34.97.43]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Fri, 3 Aug 2012 04:21:55 -0700 Received: from qiyao.dyndns.org.dyndns.org (147.34.91.1) by svr-orw-fem-05.mgc.mentorg.com (147.34.97.43) with Microsoft SMTP Server id 14.1.289.1; Fri, 3 Aug 2012 04:21:54 -0700 From: Yao Qi To: Subject: [PATCH 1/3] new observer command_param_changed. Date: Fri, 03 Aug 2012 11:22:00 -0000 Message-ID: <1343992904-9375-2-git-send-email-yao@codesourcery.com> In-Reply-To: <1343992904-9375-1-git-send-email-yao@codesourcery.com> References: <1343992904-9375-1-git-send-email-yao@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-08/txt/msg00101.txt.bz2 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 * 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) : 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 * 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" 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 #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