diff options
author | Yao Qi <yao@codesourcery.com> | 2012-08-09 12:53:46 +0000 |
---|---|---|
committer | Yao Qi <yao@codesourcery.com> | 2012-08-09 12:53:46 +0000 |
commit | 5b9afe8a3531f45255ee97465b52d2769a9a8ab5 (patch) | |
tree | 7d475e24cb1da1640836ae4b9ed9840f07291ef8 /gdb/cli/cli-setshow.c | |
parent | d21911eaddba472db273e212ae6047186974f394 (diff) | |
download | gdb-5b9afe8a3531f45255ee97465b52d2769a9a8ab5.zip gdb-5b9afe8a3531f45255ee97465b52d2769a9a8ab5.tar.gz gdb-5b9afe8a3531f45255ee97465b52d2769a9a8ab5.tar.bz2 |
gdb/
* 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) <prefix>: 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.
* NEWS: Mention new MI notification.
* mi/mi-interp.c: Declare mi_command_param_changed.
(mi_interpreter_init): Attach mi_command_param_changed to
observer command_param_changed.
(mi_command_param_changed): New.
Remove mi_suppress_breakpoint_notifications.
Define global variable mi_suppress_notification.
(mi_breakpoint_created): Update.
(mi_breakpoint_deleted): Likewise.
(mi_breakpoint_modified): Likewise.
* mi/mi-main.c (mi_cmd_execute): Likewise. Check command
'gdb-set' and set mi_suppress_notification.
* mi/mi-main.h: (mi_suppress_notification): New struct.
gdb/doc/
* observer.texi: New observer command_param_changed.
* gdb.texinfo (GDB/MI Async Records): Doc for '=cmd-param-changed'.
gdb/testsuite/
* gdb.mi/mi-cmd-param-changed.exp: New.
* gdb.mi/mi-cli.exp: Update for MI notification "=cmd-param-changed".
* gdb.mi/mi-var-rtti.exp, gdb.mi/mi2-cli.exp: Likewise.
* gdb.mi/mi2-prompt.exp: Likewise.
Diffstat (limited to 'gdb/cli/cli-setshow.c')
-rw-r--r-- | gdb/cli/cli-setshow.c | 615 |
1 files changed, 405 insertions, 210 deletions
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index 7ffb89e..89e095a 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,21 @@ 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 + || c->class == class_obscure) + return 0; + + return 1; +} + static enum auto_boolean parse_auto_binary_operation (const char *arg) @@ -116,283 +132,462 @@ 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) { - switch (c->var_type) - { - case var_string: + case var_string: + { + char *new; + char *p; + char *q; + int ch; + + if (arg == NULL) + arg = ""; + new = (char *) xmalloc (strlen (arg) + 2); + p = arg; + q = new; + while ((ch = *p++) != '\000') { - char *new; - char *p; - char *q; - int ch; - - if (arg == NULL) - arg = ""; - new = (char *) xmalloc (strlen (arg) + 2); - p = arg; - q = new; - while ((ch = *p++) != '\000') + if (ch == '\\') { - if (ch == '\\') - { - /* \ at end of argument is used after spaces - so they won't be lost. */ - /* This is obsolete now that we no longer strip - trailing whitespace and actually, the backslash - didn't get here in my test, readline or - something did something funky with a backslash - right before a newline. */ - if (*p == 0) - break; - ch = parse_escape (get_current_arch (), &p); - if (ch == 0) - break; /* C loses */ - else if (ch > 0) - *q++ = ch; - } - else + /* \ at end of argument is used after spaces + so they won't be lost. */ + /* This is obsolete now that we no longer strip + trailing whitespace and actually, the backslash + didn't get here in my test, readline or + something did something funky with a backslash + right before a newline. */ + if (*p == 0) + break; + ch = parse_escape (get_current_arch (), &p); + if (ch == 0) + break; /* C loses */ + else if (ch > 0) *q++ = ch; } + else + *q++ = ch; + } #if 0 - if (*(p - 1) != '\\') - *q++ = ' '; + if (*(p - 1) != '\\') + *q++ = ' '; #endif - *q++ = '\0'; - new = (char *) xrealloc (new, q - new); + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, new) != 0) + { xfree (*(char **) c->var); *(char **) c->var = new; + + option_changed = 1; } - break; - case var_string_noescape: - if (arg == NULL) - arg = ""; + else + xfree (new); + } + break; + case var_string_noescape: + if (arg == NULL) + arg = ""; + + if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0) + { xfree (*(char **) c->var); *(char **) c->var = xstrdup (arg); - break; - case var_filename: - if (arg == NULL) - error_no_arg (_("filename to set it to.")); - /* FALLTHROUGH */ - case var_optional_filename: - xfree (*(char **) c->var); - if (arg != NULL) - { - /* Clear trailing whitespace of filename. */ - char *ptr = arg + strlen (arg) - 1; + option_changed = 1; + } + break; + case var_filename: + if (arg == NULL) + error_no_arg (_("filename to set it to.")); + /* FALLTHROUGH */ + case var_optional_filename: + { + char *val = NULL; - while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) - ptr--; - *(ptr + 1) = '\0'; + if (arg != NULL) + { + /* Clear trailing whitespace of filename. */ + char *ptr = arg + strlen (arg) - 1; - *(char **) c->var = tilde_expand (arg); - } - else - *(char **) c->var = xstrdup (""); - break; - case var_boolean: - *(int *) c->var = parse_binary_operation (arg); - break; - case var_auto_boolean: - *(enum auto_boolean *) c->var = parse_auto_binary_operation (arg); - 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; - break; - case var_integer: - case var_zinteger: + while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; + + val = tilde_expand (arg); + } + else + val = xstrdup (""); + + if (*(char **) c->var == NULL + || strcmp (*(char **) c->var, val) != 0) { - unsigned int val; - - if (arg == NULL) - 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; - else if (val >= INT_MAX) - error (_("integer %u out of range"), val); - else - *(int *) c->var = val; - break; + xfree (*(char **) c->var); + *(char **) c->var = val; + + option_changed = 1; } - case var_enum: + else + xfree (val); + } + break; + case var_boolean: + { + 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 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 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: + { + unsigned int val; + + if (arg == NULL) + error_no_arg (_("integer to set it to.")); + val = parse_and_eval_long (arg); + if (val == 0 && c->var_type == var_integer) + val = INT_MAX; + else if (val >= INT_MAX) + error (_("integer %u out of range"), val); + + if (*(int *) c->var != val) { - int i; - int len; - int nmatches; - const char *match = NULL; - char *p; - - /* If no argument was supplied, print an informative error - message. */ - if (arg == NULL) + *(int *) c->var = val; + + option_changed = 1; + } + break; + } + case var_enum: + { + int i; + int len; + int nmatches; + const char *match = NULL; + char *p; + + /* If no argument was supplied, print an informative error + message. */ + if (arg == NULL) + { + char *msg; + int msg_len = 0; + + for (i = 0; c->enums[i]; i++) + msg_len += strlen (c->enums[i]) + 2; + + msg = xmalloc (msg_len); + *msg = '\0'; + make_cleanup (xfree, msg); + + for (i = 0; c->enums[i]; i++) { - char *msg; - int msg_len = 0; - - for (i = 0; c->enums[i]; i++) - msg_len += strlen (c->enums[i]) + 2; - - msg = xmalloc (msg_len); - *msg = '\0'; - make_cleanup (xfree, msg); - - for (i = 0; c->enums[i]; i++) - { - if (i != 0) - strcat (msg, ", "); - strcat (msg, c->enums[i]); - } - error (_("Requires an argument. Valid arguments are %s."), - msg); + if (i != 0) + strcat (msg, ", "); + strcat (msg, c->enums[i]); } + error (_("Requires an argument. Valid arguments are %s."), + msg); + } - p = strchr (arg, ' '); + p = strchr (arg, ' '); - if (p) - len = p - arg; - else - len = strlen (arg); + if (p) + len = p - arg; + else + len = strlen (arg); - nmatches = 0; - for (i = 0; c->enums[i]; i++) - if (strncmp (arg, c->enums[i], len) == 0) + nmatches = 0; + for (i = 0; c->enums[i]; i++) + if (strncmp (arg, c->enums[i], len) == 0) + { + if (c->enums[i][len] == '\0') + { + match = c->enums[i]; + nmatches = 1; + break; /* Exact match. */ + } + else { - if (c->enums[i][len] == '\0') - { - match = c->enums[i]; - nmatches = 1; - break; /* Exact match. */ - } - else - { - match = c->enums[i]; - nmatches++; - } + match = c->enums[i]; + nmatches++; } + } - if (nmatches <= 0) - error (_("Undefined item: \"%s\"."), arg); + if (nmatches <= 0) + error (_("Undefined item: \"%s\"."), arg); - if (nmatches > 1) - error (_("Ambiguous item \"%s\"."), arg); + if (nmatches > 1) + error (_("Ambiguous item \"%s\"."), arg); + 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")); - } + } + 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)) { - struct cleanup *old_chain; - struct ui_file *stb; + char *name, *cp; + struct cmd_list_element **cmds; + struct cmd_list_element *p; + int i; + int length = 0; + + /* 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. */ + + for (i = 0, p = c; p != NULL; i++) + { + length += strlen (p->name); + length++; + + p = p->prefix; + } + cp = name = xmalloc (length); + cmds = xmalloc (sizeof (struct cmd_list_element *) * i); + + /* Track back through filed 'prefix' and cache them in CMDS. */ + for (i = 0, p = c; p != NULL; i++) + { + cmds[i] = p; + p = p->prefix; + } + + /* Don't trigger any observer notification if prefixlist is not + setlist. */ + i--; + if (cmds[i]->prefixlist != &setlist) + { + xfree (cmds); + xfree (name); + + return; + } + /* Traverse them in the reversed order, and copy their names into + NAME. */ + for (i--; i >= 0; i--) + { + memcpy (cp, cmds[i]->name, strlen (cmds[i]->name)); + cp += strlen (cmds[i]->name); - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); + if (i != 0) + { + cp[0] = ' '; + cp++; + } + } + cp[0] = 0; - /* Possibly call the pre hook. */ - if (c->pre_show_hook) - (c->pre_show_hook) (c); + xfree (cmds); switch (c->var_type) { case var_string: - if (*(char **) c->var) - fputstr_filtered (*(char **) c->var, '"', stb); - break; case var_string_noescape: - case var_optional_filename: case var_filename: + case var_optional_filename: case var_enum: - if (*(char **) c->var) - fputs_filtered (*(char **) c->var, stb); + observer_notify_command_param_changed (name, *(char **) c->var); break; case var_boolean: - fputs_filtered (*(int *) c->var ? "on" : "off", stb); + { + char *opt = *(int *) c->var ? "on" : "off"; + + observer_notify_command_param_changed (name, opt); + } break; case var_auto_boolean: - switch (*(enum auto_boolean*) c->var) - { - case AUTO_BOOLEAN_TRUE: - fputs_filtered ("on", stb); - break; - case AUTO_BOOLEAN_FALSE: - fputs_filtered ("off", stb); - break; - case AUTO_BOOLEAN_AUTO: - fputs_filtered ("auto", stb); - break; - default: - internal_error (__FILE__, __LINE__, - _("do_setshow_command: " - "invalid var_auto_boolean")); - break; - } + { + 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: - if (c->var_type == var_uinteger - && *(unsigned int *) c->var == UINT_MAX) - fputs_filtered ("unlimited", stb); - else - fprintf_filtered (stb, "%u", *(unsigned int *) c->var); + { + 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: - if (c->var_type == var_integer - && *(int *) c->var == INT_MAX) - fputs_filtered ("unlimited", stb); - else - fprintf_filtered (stb, "%d", *(int *) c->var); - break; + { + char s[64]; - default: - error (_("gdb internal error: bad var_type in do_setshow_command")); + 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. */ - /* FIXME: cagney/2005-02-10: Need to split this in half: code to - convert the value into a string (esentially the above); and - code to print the value out. For the latter there should be - MI and CLI specific versions. */ +void +do_show_command (char *arg, int from_tty, struct cmd_list_element *c) +{ + struct ui_out *uiout = current_uiout; + struct cleanup *old_chain; + struct ui_file *stb; - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_stream (uiout, "value", stb); - else - { - char *value = ui_file_xstrdup (stb, NULL); + gdb_assert (c->type == show_cmd); + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); - make_cleanup (xfree, value); - if (c->show_value_func != NULL) - c->show_value_func (gdb_stdout, from_tty, c, value); - else - deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + /* Possibly call the pre hook. */ + if (c->pre_show_hook) + (c->pre_show_hook) (c); + + switch (c->var_type) + { + case var_string: + if (*(char **) c->var) + fputstr_filtered (*(char **) c->var, '"', stb); + break; + case var_string_noescape: + case var_optional_filename: + case var_filename: + case var_enum: + if (*(char **) c->var) + fputs_filtered (*(char **) c->var, stb); + break; + case var_boolean: + fputs_filtered (*(int *) c->var ? "on" : "off", stb); + break; + case var_auto_boolean: + switch (*(enum auto_boolean*) c->var) + { + case AUTO_BOOLEAN_TRUE: + fputs_filtered ("on", stb); + break; + case AUTO_BOOLEAN_FALSE: + fputs_filtered ("off", stb); + break; + case AUTO_BOOLEAN_AUTO: + fputs_filtered ("auto", stb); + break; + default: + internal_error (__FILE__, __LINE__, + _("do_show_command: " + "invalid var_auto_boolean")); + break; } - do_cleanups (old_chain); + break; + case var_uinteger: + case var_zuinteger: + if (c->var_type == var_uinteger + && *(unsigned int *) c->var == UINT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%u", *(unsigned int *) c->var); + break; + case var_integer: + case var_zinteger: + if (c->var_type == var_integer + && *(int *) c->var == INT_MAX) + fputs_filtered ("unlimited", stb); + else + fprintf_filtered (stb, "%d", *(int *) c->var); + break; + + default: + error (_("gdb internal error: bad var_type in do_show_command")); } + + + /* FIXME: cagney/2005-02-10: Need to split this in half: code to + convert the value into a string (esentially the above); and + code to print the value out. For the latter there should be + MI and CLI specific versions. */ + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_stream (uiout, "value", stb); else - error (_("gdb internal error: bad cmd_type in do_setshow_command")); + { + char *value = ui_file_xstrdup (stb, NULL); + + make_cleanup (xfree, value); + if (c->show_value_func != NULL) + c->show_value_func (gdb_stdout, from_tty, c, value); + else + deprecated_show_value_hack (gdb_stdout, from_tty, c, value); + } + do_cleanups (old_chain); + 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 +626,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. */ |