From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5569 invoked by alias); 6 Aug 2012 15:44:56 -0000 Received: (qmail 5554 invoked by uid 22791); 6 Aug 2012 15:44:53 -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_MD,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; Mon, 06 Aug 2012 15:44:38 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1SyPTx-0004Hj-B2 from Yao_Qi@mentor.com ; Mon, 06 Aug 2012 08:44:37 -0700 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Mon, 6 Aug 2012 08:44:37 -0700 Received: from qiyao.dyndns.org (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Mon, 6 Aug 2012 08:44:35 -0700 From: Yao Qi To: CC: Tom Tromey Subject: Re: [PATCH 1/3] new observer command_param_changed. Date: Mon, 06 Aug 2012 15:44:00 -0000 Message-ID: <1445113.LnrSLk2Yru@qiyao.dyndns.org> User-Agent: KMail/4.8.3 (Linux/3.3.7-1.fc16.i686; KDE/4.8.3; i686; ; ) In-Reply-To: <87zk6bnakg.fsf@fleche.redhat.com> References: <1343992904-9375-1-git-send-email-yao@codesourcery.com> <1343992904-9375-2-git-send-email-yao@codesourcery.com> <87zk6bnakg.fsf@fleche.redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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/msg00181.txt.bz2 On Friday, August 03, 2012 11:34:55 AM Tom Tromey wrote: > It seems to me that this function relies on add_prefix_cmd being invoked > before any of the sub-commands are added. >=20 > But, I think this is not guaranteed by gdb's order-agnostic > initialization approach. This, IIUC, is why the prefix list variables > are global rather than being stored in the prefix command itself. Yes, I go through the GDB source, and find there are some prefix_cmds are registered later than their sub-commands, maint_cplus_cmd_list unsetlist maintenancelist setlist in printcmd.c cmdpy_init in python/py-cmd.c thread_cmd_list setprintlist although most of prefix_cmds are registered before their sub-commands. >=20 > If that is correct, then I think a different approach is needed. >=20 We can't get correct the chain of 'c->prefix' if the command c is registered before its prefix cmd. However, this problem can be fixed by the following code added in add_prefix_cmd, + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p =3D *prefixlist; p !=3D NULL; p =3D p->next) + p->prefix =3D c; This is the major change in this version. > Yao> + if (notify_command_param_changed_p (option_changed, c)) > Yao> { > Yao> + char name[64]; >=20 > It is better not to have a statically-sized buffer. > This can easily be overrun by making new parameters from Python. >=20 > Yao> + /* Assume that the number of command option is less than 6. */ > Yao> + struct cmd_list_element *cmds[6]; >=20 > Likewise. They are switched to dynamic array. --=20 Yao (=E9=BD=90=E5=B0=A7) gdb: 2012-08-06 Yao Qi * cli/cli-decode.c (set_cmd_prefix): New. (lookup_cmd_for_prefixlist): New. (add_prefix_cmd): Call set_cmd_prefix and update field 'prefix' of each cmd_list_element in *prefixlist. (add_setshow_cmd_full): set_cmd_prefix. (add_alias_cmd): Likewise. * cli/cli-decode.h (struct cmd_list_element) : New field. Declare 'auto_boolean_enums'. * cli/cli-setshow.c: Include "observer.h". (notify_command_param_changed_p): New. (add_setshow_auto_boolean_cmd): Move auto_boolean_enums out. Remove 'static'. (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-06 Yao Qi * observer.texi: New observer command_param_changed. --- gdb/auto-load.c | 2 +- gdb/cli/cli-decode.c | 67 ++++++++++++- gdb/cli/cli-decode.h | 4 + gdb/cli/cli-setshow.c | 270 ++++++++++++++++++++++++++++++++++++++++++---= ---- gdb/cli/cli-setshow.h | 10 +- gdb/doc/observer.texi | 8 ++ gdb/remote.c | 2 +- gdb/top.c | 6 +- 8 files changed, 320 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 =3D=3D var_boolean) { gdb_assert (list->type =3D=3D set_cmd); - do_setshow_command (args, from_tty, list); + do_set_command (args, from_tty, list); } } =20 diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index c337b43..3c2e152 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -52,6 +52,53 @@ static struct cmd_list_element *find_cmd (char *command, =20 static void help_all (struct ui_file *stream); =20 +/* Look up a command whose 'prefixlist' is KEY. Return the command if fou= nd, + 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 =3D NULL; + + for (p =3D list; p !=3D NULL; p =3D p->next) + { + struct cmd_list_element *q; + + if (p->prefixlist =3D=3D NULL) + continue; + else if (p->prefixlist =3D=3D key) + return p; + + q =3D lookup_cmd_for_prefixlist (key, *(p->prefixlist)); + if (q !=3D NULL) + return q; + } + + return NULL; +} + +static void +set_cmd_prefix (struct cmd_list_element *c, struct cmd_list_element **list) +{ + struct cmd_list_element *p; + + /* Check to see if *LIST contains any element other than C. */ + for (p =3D *list; p !=3D NULL; p =3D p->next) + if (p !=3D c) + break; + + if (p =3D=3D NULL) + { + /* *SET_LIST only contains SET. */ + p =3D lookup_cmd_for_prefixlist (list, setlist); + + c->prefix =3D p ? (p->cmd_pointer ? p->cmd_pointer : p) : p; + } + else + c->prefix =3D p->prefix; +} + static void print_help_for_command (struct cmd_list_element *c, char *prefix, int recu= rse, struct ui_file *stream); @@ -193,6 +240,7 @@ add_cmd (char *name, enum command_class class, void (*f= un) (char *, int), c->prefixlist =3D NULL; c->prefixname =3D NULL; c->allow_unknown =3D 0; + c->prefix =3D NULL; c->abbrev_flag =3D 0; set_cmd_completer (c, make_symbol_completion_list_fn); c->destroyer =3D NULL; @@ -268,6 +316,8 @@ add_alias_cmd (char *name, char *oldname, enum command_= class class, c->cmd_pointer =3D old; c->alias_chain =3D old->aliases; old->aliases =3D c; + + set_cmd_prefix (c, list); return c; } =20 @@ -284,10 +334,21 @@ add_prefix_cmd (char *name, enum command_class class, struct cmd_list_element **list) { struct cmd_list_element *c =3D add_cmd (name, class, fun, doc, list); + struct cmd_list_element *p; =20 c->prefixlist =3D prefixlist; c->prefixname =3D prefixname; c->allow_unknown =3D allow_unknown; + + if (list =3D=3D &cmdlist) + c->prefix =3D NULL; + else + set_cmd_prefix (c, list); + + /* Update the field 'prefix' of each cmd_list_element in *PREFIXLIST. */ + for (p =3D *prefixlist; p !=3D NULL; p =3D p->next) + p->prefix =3D c; + return c; } =20 @@ -392,6 +453,9 @@ add_setshow_cmd_full (char *name, full_set_doc, set_list); if (set_func !=3D NULL) set_cmd_sfunc (set, set_func); + + set_cmd_prefix (set, set_list); + show =3D add_set_or_show_cmd (name, show_cmd, class, var_type, var, full_show_doc, show_list); show->show_value_func =3D show_func; @@ -430,6 +494,8 @@ add_setshow_enum_cmd (char *name, c->enums =3D enumlist; } =20 +const char * const auto_boolean_enums[] =3D { "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 +511,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[] =3D { "on", "off", "auto", NULL = }; struct cmd_list_element *c; =20 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; =20 + /* 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); =20 extern void print_doc_line (struct ui_file *, char *); =20 +extern const char * const auto_boolean_enums[]; =20 #endif /* !defined (CLI_DECODE_H) */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..19172c2 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" =20 #include "ui-out.h" =20 @@ -32,6 +33,21 @@ =20 static int parse_binary_operation (char *); =20 +/* 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 =3D=3D 0) + return 0; + + if (c->class =3D=3D class_maintenance || c->class =3D=3D class_deprecated + || c->class =3D=3D class_obscure) + return 0; + + return 1; +} + =0C static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,18 +132,19 @@ deprecated_show_value_hack (struct ui_file *ignore_fi= le, } } =20 -/* 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. */ =20 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 =3D current_uiout; + /* A flag to indicate the option is changed or not. */ + int option_changed =3D 0; + + gdb_assert (c->type =3D=3D set_cmd); =20 - if (c->type =3D=3D set_cmd) - { switch (c->var_type) { case var_string: @@ -170,50 +187,106 @@ do_setshow_command (char *arg, int from_tty, struct = cmd_list_element *c) #endif *q++ =3D '\0'; new =3D (char *) xrealloc (new, q - new); - xfree (*(char **) c->var); - *(char **) c->var =3D new; + + if (*(char **) c->var =3D=3D NULL + || strcmp (*(char **) c->var, new) !=3D 0) + { + xfree (*(char **) c->var); + *(char **) c->var =3D new; + + option_changed =3D 1; + } + else + xfree (new); } break; case var_string_noescape: if (arg =3D=3D NULL) arg =3D ""; - xfree (*(char **) c->var); - *(char **) c->var =3D xstrdup (arg); + + if (*(char **) c->var =3D=3D NULL || strcmp (*(char **) c->var, arg) != =3D 0) + { + xfree (*(char **) c->var); + *(char **) c->var =3D xstrdup (arg); + + option_changed =3D 1; + } break; case var_filename: if (arg =3D=3D NULL) error_no_arg (_("filename to set it to.")); /* FALLTHROUGH */ case var_optional_filename: - xfree (*(char **) c->var); + { + char *val =3D NULL; =20 - if (arg !=3D NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr =3D arg + strlen (arg) - 1; + if (arg !=3D NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr =3D arg + strlen (arg) - 1; =20 - while (ptr >=3D arg && (*ptr =3D=3D ' ' || *ptr =3D=3D '\t')) - ptr--; - *(ptr + 1) =3D '\0'; + while (ptr >=3D arg && (*ptr =3D=3D ' ' || *ptr =3D=3D '\t')) + ptr--; + *(ptr + 1) =3D '\0'; =20 - *(char **) c->var =3D tilde_expand (arg); - } - else - *(char **) c->var =3D xstrdup (""); + val =3D tilde_expand (arg); + } + else + val =3D xstrdup (""); + + if (*(char **) c->var =3D=3D NULL + || strcmp (*(char **) c->var, val) !=3D 0) + { + xfree (*(char **) c->var); + *(char **) c->var =3D val; + + option_changed =3D 1; + } + else + xfree (val); + } break; case var_boolean: - *(int *) c->var =3D parse_binary_operation (arg); + { + int val =3D parse_binary_operation (arg); + + if (val !=3D *(int *) c->var) + { + *(int *) c->var =3D val; + + option_changed =3D 1; + } + } break; case var_auto_boolean: - *(enum auto_boolean *) c->var =3D parse_auto_binary_operation (arg); + { + enum auto_boolean val =3D parse_auto_binary_operation (arg); + + if (*(enum auto_boolean *) c->var !=3D val) + { + *(enum auto_boolean *) c->var =3D val; + + option_changed =3D 1; + } + } break; case var_uinteger: case var_zuinteger: if (arg =3D=3D NULL) error_no_arg (_("integer to set it to.")); - *(unsigned int *) c->var =3D parse_and_eval_long (arg); - if (c->var_type =3D=3D var_uinteger && *(unsigned int *) c->var =3D=3D = 0) - *(unsigned int *) c->var =3D UINT_MAX; + { + unsigned int val =3D parse_and_eval_long (arg); + + if (c->var_type =3D=3D var_uinteger && val =3D=3D 0) + val =3D UINT_MAX; + + if (*(unsigned int *) c->var !=3D val) + { + *(unsigned int *) c->var =3D val; + + option_changed =3D 1; + } + } break; case var_integer: case var_zinteger: @@ -224,11 +297,17 @@ do_setshow_command (char *arg, int from_tty, struct c= md_list_element *c) error_no_arg (_("integer to set it to.")); val =3D parse_and_eval_long (arg); if (val =3D=3D 0 && c->var_type =3D=3D var_integer) - *(int *) c->var =3D INT_MAX; + val =3D INT_MAX; else if (val >=3D INT_MAX) error (_("integer %u out of range"), val); - else - *(int *) c->var =3D val; + + + if (*(int *) c->var !=3D val) + { + *(int *) c->var =3D val; + + option_changed =3D 1; + } break; } case var_enum: @@ -293,15 +372,133 @@ do_setshow_command (char *arg, int from_tty, struct = cmd_list_element *c) if (nmatches > 1) error (_("Ambiguous item \"%s\"."), arg); =20 - *(const char **) c->var =3D match; + if (*(const char **) c->var !=3D match) + { + *(const char **) c->var =3D match; + + option_changed =3D 1; + } } break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } - } - else if (c->type =3D=3D 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; + + /* Compute the whole multi-word command options. If user types comm= and + '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. */ + { + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length =3D 0; + char *cp; + + for (i =3D 0, p =3D c; p !=3D NULL; i++) + { + length +=3D strlen (p->name); + length++; + + p =3D p->prefix; + } + cp =3D name =3D xmalloc (length); + cmds =3D xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i =3D 0, p =3D c; p !=3D NULL; i++) + { + cmds[i] =3D p; + p =3D p->prefix; + } + + /* Skip the command 'set' in CMDS. */ + i--; + gdb_assert (cmds[i]->prefixlist =3D=3D &setlist); + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >=3D 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp +=3D strlen (cmds[i]->name); + + if (i !=3D 0) + { + cp[0] =3D ' '; + cp++; + } + } + cp[0] =3D 0; + + xfree (cmds); + } + + 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 =3D *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } + break; + case var_auto_boolean: + { + const char *s =3D 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; + } + xfree (name); + } +} + +/* 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 =3D current_uiout; + + gdb_assert (c->type =3D=3D show_cmd); + { struct cleanup *old_chain; struct ui_file *stb; =20 @@ -387,12 +584,9 @@ do_setshow_command (char *arg, int from_tty, struct cm= d_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 =3D=3D set_cmd && deprecated_set_hook) - deprecated_set_hook (c); + } } =20 /* Show all the settings in a list of show commands. */ @@ -431,7 +625,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 =3D=3D 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; =20 /* Exported to cli/cli-cmds.c and gdb/top.c */ =20 -/* 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); =20 /* Exported to cli/cli-cmds.c and gdb/top.c, language.c and valprint.c */ =20 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 =20 +@deftypefun void command_param_changed (const char *@var{param}, const cha= r *@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.=20=20 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 =3D=3D 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 =3D=3D class_user && c->user_commands) execute_user_command (c, arg); - else if (c->type =3D=3D set_cmd || c->type =3D=3D show_cmd) - do_setshow_command (arg, from_tty, c); + else if (c->type =3D=3D set_cmd) + do_set_command (arg, from_tty, c); + else if (c->type =3D=3D 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) --=20 1.7.7.6