void do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) { /* A flag to indicate the option is changed or not. */ int option_changed = 0; gdb_assert (c->type == set_cmd); switch (c->var_type) { case var_string: { char *newobj; const char *p; char *q; int ch; if (arg == NULL) arg = ""; newobj = (char *) xmalloc (strlen (arg) + 2); p = arg; q = newobj; while ((ch = *p++) != '\000') { 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 *q++ = ch; } #if 0 if (*(p - 1) != '\\') *q++ = ' '; #endif *q++ = '\0'; newobj = (char *) xrealloc (newobj, q - newobj); if (*(char **) c->var == NULL || strcmp (*(char **) c->var, newobj) != 0) { xfree (*(char **) c->var); *(char **) c->var = newobj; option_changed = 1; } else xfree (newobj); } 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); 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; if (arg != NULL) { /* Clear trailing whitespace of filename. */ const char *ptr = arg + strlen (arg) - 1; char *copy; while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) ptr--; copy = xstrndup (arg, ptr + 1 - arg); val = tilde_expand (copy); xfree (copy); } 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 val = parse_cli_boolean_value (arg); if (val < 0) error (_("\"on\" or \"off\" expected.")); 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: { LONGEST val; if (arg == NULL) { if (c->var_type == var_uinteger) error_no_arg (_("integer to set it to, or \"unlimited\".")); else error_no_arg (_("integer to set it to.")); } if (c->var_type == var_uinteger && is_unlimited_literal (arg)) val = 0; else val = parse_and_eval_long (arg); if (c->var_type == var_uinteger && val == 0) val = UINT_MAX; else if (val < 0 /* For var_uinteger, don't let the user set the value to UINT_MAX directly, as that exposes an implementation detail to the user interface. */ || (c->var_type == var_uinteger && val >= UINT_MAX) || (c->var_type == var_zuinteger && val > UINT_MAX)) error (_("integer %s out of range"), plongest (val)); if (*(unsigned int *) c->var != val) { *(unsigned int *) c->var = val; option_changed = 1; } } break; case var_integer: case var_zinteger: { LONGEST val; if (arg == NULL) { if (c->var_type == var_integer) error_no_arg (_("integer to set it to, or \"unlimited\".")); else error_no_arg (_("integer to set it to.")); } if (c->var_type == var_integer && is_unlimited_literal (arg)) val = 0; else val = parse_and_eval_long (arg); if (val == 0 && c->var_type == var_integer) val = INT_MAX; else if (val < INT_MIN /* For var_integer, don't let the user set the value to INT_MAX directly, as that exposes an implementation detail to the user interface. */ || (c->var_type == var_integer && val >= INT_MAX) || (c->var_type == var_zinteger && val > INT_MAX)) error (_("integer %s out of range"), plongest (val)); if (*(int *) c->var != val) { *(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++) { if (i != 0) strcat (msg, ", "); strcat (msg, c->enums[i]); } error (_("Requires an argument. Valid arguments are %s."), msg); } p = strchr (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) { if (c->enums[i][len] == '\0') { match = c->enums[i]; nmatches = 1; break; /* Exact match. */ } else { match = c->enums[i]; nmatches++; } } if (nmatches <= 0) error (_("Undefined 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; case var_zuinteger_unlimited: { LONGEST val; if (arg == NULL) error_no_arg (_("integer to set it to, or \"unlimited\".")); if (is_unlimited_literal (arg)) val = -1; else val = parse_and_eval_long (arg); if (val > INT_MAX) error (_("integer %s out of range"), plongest (val)); else if (val < -1) error (_("only -1 is allowed to set as unlimited")); if (*(int *) c->var != val) { *(int *) c->var = val; option_changed = 1; } } break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } c->func (c, NULL, from_tty); if (notify_command_param_changed_p (option_changed, c)) { 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 = (char *) xmalloc (length); cmds = XNEWVEC (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); if (i != 0) { cp[0] = ' '; cp++; } } cp[0] = 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 = *(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: case var_zuinteger_unlimited: { char s[64]; xsnprintf (s, sizeof s, "%d", *(int *) c->var); observer_notify_command_param_changed (name, s); } break; } xfree (name); } }
void do_setshow_command(char *arg, int from_tty, struct cmd_list_element *c) { if (c->type == set_cmd) { switch (c->var_type) { case var_string: { char *newstr; char *p; char *q; int ch; if (arg == NULL) arg = ""; newstr = (char *)xmalloc(strlen(arg) + 2); p = arg; q = newstr; while ((ch = *p++) != '\000') { 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(&p); if (ch == 0) break; /* C loses */ else if (ch > 0) *q++ = ch; } else *q++ = ch; } #if 0 if (*(p - 1) != '\\') *q++ = ' '; #endif /* 0 */ *q++ = '\0'; newstr = (char *)xrealloc(newstr, (q - newstr)); if (*(char **)c->var != NULL) xfree(*(char **)c->var); *(char **)c->var = newstr; } break; case var_string_noescape: if (arg == NULL) arg = ""; if (*(char **)c->var != NULL) xfree(*(char **)c->var); *(char **)c->var = savestring(arg, strlen(arg)); break; case var_optional_filename: if (arg == NULL) arg = ""; if (*(char **)c->var != NULL) xfree(*(char **)c->var); *(char **)c->var = savestring(arg, strlen(arg)); break; case var_filename: if (arg == NULL) error_no_arg(_("filename to set it to.")); if (*(char **)c->var != NULL) xfree (*(char **)c->var); *(char **)c->var = tilde_expand(arg); 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: if (arg == NULL) error_no_arg(_("integer to set it to.")); *(unsigned int *)c->var = (unsigned int)parse_and_eval_long(arg); if (*(unsigned int *)c->var == 0) *(unsigned int *)c->var = UINT_MAX; break; case var_integer: { unsigned int val; if (arg == NULL) error_no_arg(_("integer to set it to.")); val = (unsigned int)parse_and_eval_long(arg); if (val == 0) *(int *)c->var = INT_MAX; else if (val >= INT_MAX) error(_("integer %u out of range"), val); else *(int *)c->var = val; break; } case var_zinteger: if (arg == NULL) error_no_arg(_("integer to set it to.")); *(int *)c->var = (int)parse_and_eval_long(arg); break; case var_enum: { int i; int len; int nmatches = 0; const char *match = NULL; char *p; /* APPLE LOCAL: Give the valid options for all error messages for enum type commands. */ /* If an argument was supplied, parse it. */ if (arg != NULL) { p = strchr(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) { if (c->enums[i][len] == '\0') { match = c->enums[i]; nmatches = 1; break; /* exact match. */ } else { match = c->enums[i]; nmatches++; } } } if (nmatches == 1) *(const char **)c->var = match; else { /* If there was an error, print an informative error message. */ struct ui_file *tmp_error_stream = mem_fileopen(); make_cleanup_ui_file_delete (tmp_error_stream); if (arg == NULL) fprintf_unfiltered(tmp_error_stream, "Requires an argument."); else if (nmatches <= 0) fprintf_unfiltered(tmp_error_stream, "Undefined item: \"%s\".", arg); else if (nmatches > 1) fprintf_unfiltered(tmp_error_stream, "Ambiguous item \"%s\".", arg); fprintf_unfiltered(tmp_error_stream, " Valid arguments are "); for (i = 0; c->enums[i]; i++) { if (i != 0) fprintf_unfiltered(tmp_error_stream, ", "); fputs_unfiltered(c->enums[i], tmp_error_stream); } fprintf_unfiltered(tmp_error_stream, "."); error_stream(tmp_error_stream); } /* END APPLE LOCAL */ } break; default: error(_("gdb internal error: bad var_type in do_setshow_command")); } } else if (c->type == show_cmd) { struct cleanup *old_chain; struct ui_stream *stb; stb = ui_out_stream_new(uiout); old_chain = make_cleanup_ui_out_stream_delete(stb); /* Possibly call the pre hook: */ if (c->pre_show_hook) (c->pre_show_hook)(c); switch (c->var_type) { case var_string: { if (*(unsigned char **)c->var) fputstr_filtered(*(char **)c->var, '"', stb->stream); } 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->stream); break; case var_boolean: fputs_filtered(*(int *)c->var ? "on" : "off", stb->stream); break; case var_auto_boolean: switch (*(enum auto_boolean*)c->var) { case AUTO_BOOLEAN_TRUE: fputs_filtered("on", stb->stream); break; case AUTO_BOOLEAN_FALSE: fputs_filtered("off", stb->stream); break; case AUTO_BOOLEAN_AUTO: fputs_filtered("auto", stb->stream); break; default: internal_error(__FILE__, __LINE__, _("do_setshow_command: invalid var_auto_boolean")); break; } break; case var_uinteger: if (*(unsigned int *)c->var == UINT_MAX) { fputs_filtered("unlimited", stb->stream); break; } /* else fall through */ case var_zinteger: fprintf_filtered(stb->stream, "%u", *(unsigned int *)c->var); break; case var_integer: if (*(int *)c->var == INT_MAX) { fputs_filtered("unlimited", stb->stream); } else fprintf_filtered(stb->stream, "%d", *(int *)c->var); break; default: error(_("gdb internal error: bad var_type in do_setshow_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 { long length; char *value = ui_file_xstrdup(stb->stream, &length); 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); } 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); }
void do_setshow_command (char *arg, int from_tty, struct cmd_list_element *c) { if (c->type == set_cmd) { switch (c->var_type) { case var_string: { if (arg == NULL) arg = ""; *(char **) c->var = g_strcompress (arg); } break; case var_string_noescape: if (arg == NULL) arg = ""; if (*(char **) c->var != NULL) g_free (*(char **) c->var); *(char **) c->var = savestring (arg, strlen (arg)); break; case var_optional_filename: if (arg == NULL) arg = ""; if (*(char **) c->var != NULL) g_free (*(char **) c->var); *(char **) c->var = savestring (arg, strlen (arg)); break; case var_filename: if (arg == NULL) bosh_command_error_no_argument (_("filename to set it to.")); if (*(char **) c->var != NULL) g_free (*(char **) c->var); { /* Clear trailing whitespace of filename. */ char *ptr = arg + strlen (arg) - 1; while (ptr >= arg && (*ptr == ' ' || *ptr == '\t')) ptr--; *(ptr + 1) = '\0'; } *(char **) c->var = tilde_expand (arg); break; case var_boolean: { int val = parse_binary_operation (arg); if (val != -1) *(int *) c->var = val; break; } case var_auto_boolean: { enum auto_boolean val = parse_auto_binary_operation (arg); if (val != AUTO_BOOLEAN_INVALID) *(enum auto_boolean *) c->var = val; break; } case var_uinteger: if (arg == NULL) bosh_command_error_no_argument (_("integer to set it to.")); *(unsigned int *) c->var = parse_and_eval_long (arg); if (*(unsigned int *) c->var == 0) *(unsigned int *) c->var = UINT_MAX; break; case var_integer: { unsigned int val; if (arg == NULL) { bosh_command_error_no_argument (_("integer to set it to.")); break; } val = parse_and_eval_long (arg); if (val == 0) *(int *) c->var = INT_MAX; else if (val >= INT_MAX) { g_print (_("integer %u out of range"), val); break; } else *(int *) c->var = val; break; } case var_zinteger: if (arg == NULL) bosh_command_error_no_argument (_("integer to set it to.")); *(int *) c->var = parse_and_eval_long (arg); 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 = g_malloc (msg_len); *msg = '\0'; for (i = 0; c->enums[i]; i++) { if (i != 0) strcat (msg, ", "); strcat (msg, c->enums[i]); } g_print (_("Requires an argument. Valid arguments are %s."), msg); g_free (msg); break; } p = strchr (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) { if (c->enums[i][len] == '\0') { match = c->enums[i]; nmatches = 1; break; /* exact match. */ } else { match = c->enums[i]; nmatches++; } } if (nmatches <= 0) { g_print (_("Undefined item: \"%s\"."), arg); break; } if (nmatches > 1) { g_print (_("Ambiguous item \"%s\"."), arg); break; } *(const char **) c->var = match; } break; default: g_warning (_("gdb internal error: bad var_type in do_setshow_command")); } } else if (c->type == show_cmd) { char *val; /* 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) val = g_strescape (*(char **) c->var, ""); break; case var_string_noescape: case var_optional_filename: case var_filename: case var_enum: if (*(char **) c->var) val = g_strdup (*(char **) c->var); break; case var_boolean: val = g_strdup (c->var ? "on" : "off"); break; case var_auto_boolean: switch (*(enum auto_boolean*) c->var) { case AUTO_BOOLEAN_TRUE: val = g_strdup ("on"); break; case AUTO_BOOLEAN_FALSE: val = g_strdup ("off"); break; case AUTO_BOOLEAN_AUTO: val = g_strdup ("auto"); break; default: g_warning ("%s:%d %s", __FILE__, __LINE__, _("do_setshow_command: invalid var_auto_boolean")); break; } break; case var_uinteger: if (*(unsigned int *) c->var == UINT_MAX) { val = g_strdup ("unlimited"); break; } /* else fall through */ case var_zinteger: val = g_strdup_printf ("%u", *(unsigned int *) c->var); break; case var_integer: if (*(int *) c->var == INT_MAX) val = g_strdup ("unlimited"); else val = g_strdup_printf ("%d", *(int *) c->var); break; default: g_warning (_("gdb internal error: bad var_type in do_setshow_command")); } if (c->show_value_func != NULL) c->show_value_func (NULL, from_tty, c, val); else g_warning ("command %s missing show_value_func", c->name); } else g_warning (_("gdb internal error: bad cmd_type in do_setshow_command")); c->func (c, NULL, from_tty); }