diff options
author | Maciej W. Rozycki <macro@embecosm.com> | 2023-01-19 21:15:56 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@embecosm.com> | 2023-01-19 21:15:56 +0000 |
commit | 7aeb03e2d4186d1184050d2ec048301f48255644 (patch) | |
tree | 3d2f57b0f5fa23d6f977c7fbaee809c284e7bc5c /gdb/cli | |
parent | 0fcd58d843ce1b07c8516c51f9120714673003a3 (diff) | |
download | gdb-7aeb03e2d4186d1184050d2ec048301f48255644.zip gdb-7aeb03e2d4186d1184050d2ec048301f48255644.tar.gz gdb-7aeb03e2d4186d1184050d2ec048301f48255644.tar.bz2 |
GDB: Allow arbitrary keywords in integer set commands
Rather than just `unlimited' allow the integer set commands (or command
options) to define arbitrary keywords for the user to use, removing
hardcoded arrangements for the `unlimited' keyword.
Remove the confusingly named `var_zinteger', `var_zuinteger' and
`var_zuinteger_unlimited' `set'/`show' command variable types redefining
them in terms of `var_uinteger', `var_integer' and `var_pinteger', which
have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.
Following existing practice `var_pinteger' allows extra negative values
to be used, however unlike `var_zuinteger_unlimited' any number of such
values can be defined rather than just `-1'.
The "p" in `var_pinteger' stands for "positive", for the lack of a more
appropriate unambiguous letter, even though 0 obviously is not positive;
"n" would be confusing as to whether it stands for "non-negative" or
"negative".
Add a new structure, `literal_def', the entries of which define extra
keywords allowed for a command and numerical values they correspond to.
Those values are not verified against the basic range supported by the
underlying variable type, allowing extra values to be allowed outside
that range, which may or may not be individually made visible to the
user. An optional value translation is possible with the structure to
follow the existing practice for some commands where user-entered 0 is
internally translated to UINT_MAX or INT_MAX. Such translation can now
be arbitrary. Literals defined by this structure are automatically used
for completion as necessary.
So for example:
const literal_def integer_unlimited_literals[] =
{
{ "unlimited", INT_MAX, 0 },
{ nullptr }
};
defines an extra `unlimited' keyword and a user-visible 0 value, both of
which get translated to INT_MAX for the setting to be used with.
Similarly:
const literal_def zuinteger_unlimited_literals[] =
{
{ "unlimited", -1, -1 },
{ nullptr }
};
defines the same keyword and a corresponding user-visible -1 value that
is used for the requested setting. If the last member were omitted (or
set to `{}') here, then only the keyword would be allowed for the user
to enter and while -1 would still be used internally trying to enter it
as a part of a command would result in an "integer -1 out of range"
error.
Use said error message in all cases (citing the invalid value requested)
replacing "only -1 is allowed to set as unlimited" previously used for
`var_zuinteger_unlimited' settings only rather than propagating it to
`var_pinteger' type. It could only be used for the specific case where
a single extra `unlimited' keyword was defined standing for -1 and the
use of numeric equivalents is discouraged anyway as it is for historical
reasons only that they expose GDB internals, confusingly different
across variable types. Similarly update the "must be >= -1" Guile error
message.
Redefine Guile and Python parameter types in terms of the new variable
types and interpret extra keywords as Scheme keywords and Python strings
used to communicate corresponding parameter values. Do not add a new
PARAM_INTEGER Guile parameter type, however do handle the `var_integer'
variable type now, permitting existing parameters defined by GDB proper,
such as `listsize', to be accessed from Scheme code.
With these changes in place it should be trivial for a Scheme or Python
programmer to expand the syntax of the `make-parameter' command and the
`gdb.Parameter' class initializer to have arbitrary extra literals along
with their internal representation supplied.
Update the testsuite accordingly.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Diffstat (limited to 'gdb/cli')
-rw-r--r-- | gdb/cli/cli-cmds.c | 59 | ||||
-rw-r--r-- | gdb/cli/cli-decode.c | 321 | ||||
-rw-r--r-- | gdb/cli/cli-option.c | 104 | ||||
-rw-r--r-- | gdb/cli/cli-option.h | 54 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.c | 247 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.h | 20 |
6 files changed, 521 insertions, 284 deletions
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index b41aa49..6c0d780 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -2213,22 +2213,40 @@ value_from_setting (const setting &var, struct gdbarch *gdbarch) { switch (var.type ()) { + case var_uinteger: case var_integer: - if (var.get<int> () == INT_MAX) - return value_from_longest (builtin_type (gdbarch)->builtin_int, - 0); - else - return value_from_longest (builtin_type (gdbarch)->builtin_int, - var.get<int> ()); - case var_zinteger: - return value_from_longest (builtin_type (gdbarch)->builtin_int, - var.get<int> ()); + case var_pinteger: + { + LONGEST value + = (var.type () == var_uinteger + ? static_cast<LONGEST> (var.get<unsigned int> ()) + : static_cast<LONGEST> (var.get<int> ())); + + if (var.extra_literals () != nullptr) + for (const literal_def *l = var.extra_literals (); + l->literal != nullptr; + l++) + if (value == l->use) + { + if (l->val.has_value ()) + value = *l->val; + else + return allocate_value (builtin_type (gdbarch)->builtin_void); + break; + } + + if (var.type () == var_uinteger) + return + value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int, + static_cast<unsigned int> (value)); + else + return + value_from_longest (builtin_type (gdbarch)->builtin_int, + static_cast<int> (value)); + } case var_boolean: return value_from_longest (builtin_type (gdbarch)->builtin_int, var.get<bool> () ? 1 : 0); - case var_zuinteger_unlimited: - return value_from_longest (builtin_type (gdbarch)->builtin_int, - var.get<int> ()); case var_auto_boolean: { int val; @@ -2250,17 +2268,6 @@ value_from_setting (const setting &var, struct gdbarch *gdbarch) return value_from_longest (builtin_type (gdbarch)->builtin_int, val); } - case var_uinteger: - if (var.get<unsigned int> () == UINT_MAX) - return value_from_ulongest - (builtin_type (gdbarch)->builtin_unsigned_int, 0); - else - return value_from_ulongest - (builtin_type (gdbarch)->builtin_unsigned_int, - var.get<unsigned int> ()); - case var_zuinteger: - return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int, - var.get<unsigned int> ()); case var_string: case var_string_noescape: case var_optional_filename: @@ -2330,13 +2337,11 @@ str_value_from_setting (const setting &var, struct gdbarch *gdbarch) { switch (var.type ()) { + case var_uinteger: case var_integer: - case var_zinteger: + case var_pinteger: case var_boolean: - case var_zuinteger_unlimited: case var_auto_boolean: - case var_uinteger: - case var_zuinteger: { std::string cmd_val = get_setshow_command_value_string (var); diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index fdc29c0..2a4f9b4 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -496,6 +496,8 @@ empty_func (const char *args, int from_tty, cmd_list_element *c) TYPE is set_cmd or show_cmd. THECLASS is as in add_cmd. VAR_TYPE is the kind of thing we are setting. + EXTRA_LITERALS if non-NULL define extra literals to be accepted in lieu of + a number for integer variables. ARGS is a pre-validated type-erased reference to the variable being controlled by this command. DOC is the documentation string. */ @@ -505,6 +507,7 @@ add_set_or_show_cmd (const char *name, enum cmd_types type, enum command_class theclass, var_types var_type, + const literal_def *extra_literals, const setting::erased_args &arg, const char *doc, struct cmd_list_element **list) @@ -513,7 +516,7 @@ add_set_or_show_cmd (const char *name, gdb_assert (type == set_cmd || type == show_cmd); c->type = type; - c->var.emplace (var_type, arg); + c->var.emplace (var_type, extra_literals, arg); /* This needs to be something besides NULL so that this isn't treated as a help class. */ @@ -523,10 +526,12 @@ add_set_or_show_cmd (const char *name, /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. THECLASS is as in add_cmd. VAR_TYPE is the kind of thing we are - setting. ARGS is a pre-validated type-erased reference to the - variable being controlled by this command. SET_FUNC and SHOW_FUNC - are the callback functions (if non-NULL). SET_DOC, SHOW_DOC and - HELP_DOC are the documentation strings. + setting. EXTRA_LITERALS if non-NULL define extra literals to be + accepted in lieu of a number for integer variables. ARGS is a + pre-validated type-erased reference to the variable being controlled + by this command. SET_FUNC and SHOW_FUNC are the callback functions + (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the documentation + strings. Return the newly created set and show commands. */ @@ -534,6 +539,7 @@ static set_show_commands add_setshow_cmd_full_erased (const char *name, enum command_class theclass, var_types var_type, + const literal_def *extra_literals, const setting::erased_args &args, const char *set_doc, const char *show_doc, const char *help_doc, @@ -557,14 +563,16 @@ add_setshow_cmd_full_erased (const char *name, full_set_doc = make_unique_xstrdup (set_doc); full_show_doc = make_unique_xstrdup (show_doc); } - set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, args, + set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, + extra_literals, args, full_set_doc.release (), set_list); set->doc_allocated = 1; if (set_func != NULL) set->func = set_func; - show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, args, + show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, + extra_literals, args, full_show_doc.release (), show_list); show->doc_allocated = 1; show->show_value_func = show_func; @@ -575,14 +583,41 @@ add_setshow_cmd_full_erased (const char *name, return {set, show}; } +/* Completes on integer commands that support extra literals. */ + +static void +integer_literals_completer (struct cmd_list_element *c, + completion_tracker &tracker, + const char *text, const char *word) +{ + const literal_def *extra_literals = c->var->extra_literals (); + + if (*text == '\0') + { + tracker.add_completion (make_unique_xstrdup ("NUMBER")); + for (const literal_def *l = extra_literals; + l->literal != nullptr; + l++) + tracker.add_completion (make_unique_xstrdup (l->literal)); + } + else + for (const literal_def *l = extra_literals; + l->literal != nullptr; + l++) + if (startswith (l->literal, text)) + tracker.add_completion (make_unique_xstrdup (l->literal)); +} + /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. THECLASS is as in add_cmd. VAR_TYPE is the kind of thing we are setting. VAR is address of the variable being controlled by this - command. If nullptr is given as VAR, then both SET_SETTING_FUNC and - GET_SETTING_FUNC must be provided. SET_SETTING_FUNC and GET_SETTING_FUNC - are callbacks used to access and modify the underlying property, - whatever its storage is. SET_FUNC and SHOW_FUNC are the callback - functions (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the + command. EXTRA_LITERALS if non-NULL define extra literals to be + accepted in lieu of a number for integer variables. If nullptr is + given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must + be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks + used to access and modify the underlying property, whatever its + storage is. SET_FUNC and SHOW_FUNC are the callback functions + (if non-NULL). SET_DOC, SHOW_DOC and HELP_DOC are the documentation strings. Return the newly created set and show commands. */ @@ -592,6 +627,7 @@ static set_show_commands add_setshow_cmd_full (const char *name, enum command_class theclass, var_types var_type, T *var, + const literal_def *extra_literals, const char *set_doc, const char *show_doc, const char *help_doc, typename setting_func_types<T>::set set_setting_func, @@ -604,16 +640,43 @@ add_setshow_cmd_full (const char *name, auto erased_args = setting::erase_args (var_type, var, set_setting_func, get_setting_func); + auto cmds = add_setshow_cmd_full_erased (name, + theclass, + var_type, extra_literals, + erased_args, + set_doc, show_doc, + help_doc, + set_func, + show_func, + set_list, + show_list); + + if (extra_literals != nullptr) + set_cmd_completer (cmds.set, integer_literals_completer); - return add_setshow_cmd_full_erased (name, - theclass, - var_type, erased_args, - set_doc, show_doc, - help_doc, - set_func, - show_func, - set_list, - show_list); + return cmds; +} + +/* Same as above but omitting EXTRA_LITERALS. */ + +template<typename T> +static set_show_commands +add_setshow_cmd_full (const char *name, + enum command_class theclass, + var_types var_type, T *var, + const char *set_doc, const char *show_doc, + const char *help_doc, + typename setting_func_types<T>::set set_setting_func, + typename setting_func_types<T>::get get_setting_func, + cmd_func_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + return add_setshow_cmd_full (name, theclass, var_type, var, nullptr, + set_doc, show_doc, help_doc, + set_setting_func, get_setting_func, + set_func, show_func, set_list, show_list); } /* Add element named NAME to command list LIST (the list for set or @@ -982,25 +1045,6 @@ add_setshow_optional_filename_cmd (const char *name, command_class theclass, return cmds; } -/* Completes on literal "unlimited". Used by integer commands that - support a special "unlimited" value. */ - -static void -integer_unlimited_completer (struct cmd_list_element *ignore, - completion_tracker &tracker, - const char *text, const char *word) -{ - static const char * const keywords[] = - { - "unlimited", - NULL, - }; - - if (*text == '\0') - tracker.add_completion (make_unique_xstrdup ("NUMBER")); - complete_on_enum (tracker, keywords, text, word); -} - /* Add element named NAME to both the set and show command LISTs (the list for set/show or some sublist thereof). THECLASS is as in add_cmd. VAR is address of the variable which will contain the @@ -1009,6 +1053,55 @@ integer_unlimited_completer (struct cmd_list_element *ignore, set_show_commands add_setshow_integer_cmd (const char *name, enum command_class theclass, + int *var, const literal_def *extra_literals, + const char *set_doc, const char *show_doc, + const char *help_doc, + cmd_func_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + set_show_commands commands + = add_setshow_cmd_full<int> (name, theclass, var_integer, var, + extra_literals, set_doc, show_doc, + help_doc, nullptr, nullptr, set_func, + show_func, set_list, show_list); + return commands; +} + +/* Same as above but using a getter and a setter function instead of a pointer + to a global storage buffer. */ + +set_show_commands +add_setshow_integer_cmd (const char *name, command_class theclass, + const literal_def *extra_literals, + const char *set_doc, const char *show_doc, + const char *help_doc, + setting_func_types<int>::set set_func, + setting_func_types<int>::get get_func, + show_value_ftype *show_func, + cmd_list_element **set_list, + cmd_list_element **show_list) +{ + auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, + extra_literals, set_doc, show_doc, + help_doc, set_func, get_func, nullptr, + show_func, set_list, show_list); + return cmds; +} + +/* Accept `unlimited' or 0, translated internally to INT_MAX. */ +const literal_def integer_unlimited_literals[] = + { + { "unlimited", INT_MAX, 0 }, + { nullptr } + }; + +/* Same as above but using `integer_unlimited_literals', with a pointer + to a global storage buffer. */ + +set_show_commands +add_setshow_integer_cmd (const char *name, enum command_class theclass, int *var, const char *set_doc, const char *show_doc, const char *help_doc, @@ -1019,12 +1112,10 @@ add_setshow_integer_cmd (const char *name, enum command_class theclass, { set_show_commands commands = add_setshow_cmd_full<int> (name, theclass, var_integer, var, + integer_unlimited_literals, set_doc, show_doc, help_doc, nullptr, nullptr, set_func, show_func, set_list, show_list); - - set_cmd_completer (commands.set, integer_unlimited_completer); - return commands; } @@ -1042,12 +1133,54 @@ add_setshow_integer_cmd (const char *name, command_class theclass, cmd_list_element **show_list) { auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, + integer_unlimited_literals, set_doc, show_doc, help_doc, set_func, get_func, nullptr, show_func, set_list, show_list); + return cmds; +} - set_cmd_completer (cmds.set, integer_unlimited_completer); +/* Add element named NAME to both the set and show command LISTs (the + list for set/show or some sublist thereof). CLASS is as in + add_cmd. VAR is address of the variable which will contain the + value. SET_DOC and SHOW_DOC are the documentation strings. */ + +set_show_commands +add_setshow_pinteger_cmd (const char *name, enum command_class theclass, + int *var, const literal_def *extra_literals, + const char *set_doc, const char *show_doc, + const char *help_doc, + cmd_func_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + set_show_commands commands + = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, + extra_literals, set_doc, show_doc, + help_doc, nullptr, nullptr, set_func, + show_func, set_list, show_list); + return commands; +} +/* Same as above but using a getter and a setter function instead of a pointer + to a global storage buffer. */ + +set_show_commands +add_setshow_pinteger_cmd (const char *name, command_class theclass, + const literal_def *extra_literals, + const char *set_doc, const char *show_doc, + const char *help_doc, + setting_func_types<int>::set set_func, + setting_func_types<int>::get get_func, + show_value_ftype *show_func, + cmd_list_element **set_list, + cmd_list_element **show_list) +{ + auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, + extra_literals, set_doc, show_doc, + help_doc, set_func, get_func, nullptr, + show_func, set_list, show_list); return cmds; } @@ -1058,7 +1191,7 @@ add_setshow_integer_cmd (const char *name, command_class theclass, set_show_commands add_setshow_uinteger_cmd (const char *name, enum command_class theclass, - unsigned int *var, + unsigned int *var, const literal_def *extra_literals, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, @@ -1068,12 +1201,9 @@ add_setshow_uinteger_cmd (const char *name, enum command_class theclass, { set_show_commands commands = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, - set_doc, show_doc, help_doc, - nullptr, nullptr, set_func, + extra_literals, set_doc, show_doc, + help_doc, nullptr, nullptr, set_func, show_func, set_list, show_list); - - set_cmd_completer (commands.set, integer_unlimited_completer); - return commands; } @@ -1082,6 +1212,7 @@ add_setshow_uinteger_cmd (const char *name, enum command_class theclass, set_show_commands add_setshow_uinteger_cmd (const char *name, command_class theclass, + const literal_def *extra_literals, const char *set_doc, const char *show_doc, const char *help_doc, setting_func_types<unsigned int>::set set_func, @@ -1091,13 +1222,63 @@ add_setshow_uinteger_cmd (const char *name, command_class theclass, cmd_list_element **show_list) { auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, - nullptr, set_doc, show_doc, - help_doc, set_func, get_func, - nullptr, show_func, set_list, + nullptr, extra_literals, + set_doc, show_doc, help_doc, + set_func, get_func, nullptr, + show_func, set_list, show_list); + return cmds; +} + +/* Accept `unlimited' or 0, translated internally to UINT_MAX. */ +const literal_def uinteger_unlimited_literals[] = + { + { "unlimited", UINT_MAX, 0 }, + { nullptr } + }; - set_cmd_completer (cmds.set, integer_unlimited_completer); +/* Same as above but using `uinteger_unlimited_literals', with a pointer + to a global storage buffer. */ + +set_show_commands +add_setshow_uinteger_cmd (const char *name, enum command_class theclass, + unsigned int *var, + const char *set_doc, const char *show_doc, + const char *help_doc, + cmd_func_ftype *set_func, + show_value_ftype *show_func, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + set_show_commands commands + = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, + uinteger_unlimited_literals, + set_doc, show_doc, help_doc, nullptr, + nullptr, set_func, show_func, + set_list, show_list); + return commands; +} +/* Same as above but using a getter and a setter function instead of a pointer + to a global storage buffer. */ + +set_show_commands +add_setshow_uinteger_cmd (const char *name, command_class theclass, + const char *set_doc, const char *show_doc, + const char *help_doc, + setting_func_types<unsigned int>::set set_func, + setting_func_types<unsigned int>::get get_func, + show_value_ftype *show_func, + cmd_list_element **set_list, + cmd_list_element **show_list) +{ + auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, + nullptr, + uinteger_unlimited_literals, + set_doc, show_doc, help_doc, + set_func, get_func, nullptr, + show_func, set_list, + show_list); return cmds; } @@ -1116,7 +1297,7 @@ add_setshow_zinteger_cmd (const char *name, enum command_class theclass, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var, + return add_setshow_cmd_full<int> (name, theclass, var_integer, var, set_doc, show_doc, help_doc, nullptr, nullptr, set_func, show_func, set_list, show_list); @@ -1135,12 +1316,22 @@ add_setshow_zinteger_cmd (const char *name, command_class theclass, cmd_list_element **set_list, cmd_list_element **show_list) { - return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr, + return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, set_doc, show_doc, help_doc, set_func, get_func, nullptr, show_func, set_list, show_list); } +/* Accept `unlimited' or -1, using -1 internally. */ +const literal_def pinteger_unlimited_literals[] = + { + { "unlimited", -1, -1 }, + { nullptr } + }; + +/* Same as above but using `pinteger_unlimited_literals', with a pointer + to a global storage buffer. */ + set_show_commands add_setshow_zuinteger_unlimited_cmd (const char *name, enum command_class theclass, @@ -1154,13 +1345,11 @@ add_setshow_zuinteger_unlimited_cmd (const char *name, struct cmd_list_element **show_list) { set_show_commands commands - = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var, + = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, + pinteger_unlimited_literals, set_doc, show_doc, help_doc, nullptr, nullptr, set_func, show_func, set_list, show_list); - - set_cmd_completer (commands.set, integer_unlimited_completer); - return commands; } @@ -1178,13 +1367,11 @@ add_setshow_zuinteger_unlimited_cmd (const char *name, command_class theclass, cmd_list_element **show_list) { auto cmds - = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, - nullptr, set_doc, show_doc, help_doc, set_func, + = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, + pinteger_unlimited_literals, + set_doc, show_doc, help_doc, set_func, get_func, nullptr, show_func, set_list, show_list); - - set_cmd_completer (cmds.set, integer_unlimited_completer); - return cmds; } @@ -1203,7 +1390,7 @@ add_setshow_zuinteger_cmd (const char *name, enum command_class theclass, struct cmd_list_element **set_list, struct cmd_list_element **show_list) { - return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger, + return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, set_doc, show_doc, help_doc, nullptr, nullptr, set_func, show_func, set_list, show_list); @@ -1222,7 +1409,7 @@ add_setshow_zuinteger_cmd (const char *name, command_class theclass, cmd_list_element **set_list, cmd_list_element **show_list) { - return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger, + return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, nullptr, set_doc, show_doc, help_doc, set_func, get_func, nullptr, show_func, set_list, diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c index 95dc9ab..9b303b1 100644 --- a/gdb/cli/cli-option.c +++ b/gdb/cli/cli-option.c @@ -38,7 +38,7 @@ union option_value /* For var_uinteger options. */ unsigned int uinteger; - /* For var_zuinteger_unlimited options. */ + /* For var_integer and var_pinteger options. */ int integer; /* For var_enum options. */ @@ -356,42 +356,52 @@ parse_option (gdb::array_view<const option_def_group> options_group, return option_def_and_value {*match, match_ctx, val}; } case var_uinteger: - case var_zuinteger_unlimited: + case var_integer: + case var_pinteger: { - if (completion != nullptr) + if (completion != nullptr && match->extra_literals != nullptr) { + /* Convenience to let the user know what the option can + accept. Make sure there's no common prefix between + "NUMBER" and all the strings when adding new ones, + so that readline doesn't do a partial match. */ if (**args == '\0') { - /* Convenience to let the user know what the option - can accept. Note there's no common prefix between - the strings on purpose, so that readline doesn't do - a partial match. */ completion->tracker.add_completion (make_unique_xstrdup ("NUMBER")); - completion->tracker.add_completion - (make_unique_xstrdup ("unlimited")); + for (const literal_def *l = match->extra_literals; + l->literal != nullptr; + l++) + completion->tracker.add_completion + (make_unique_xstrdup (l->literal)); return {}; } - else if (startswith ("unlimited", *args)) + else { - completion->tracker.add_completion - (make_unique_xstrdup ("unlimited")); - return {}; + bool completions = false; + for (const literal_def *l = match->extra_literals; + l->literal != nullptr; + l++) + if (startswith (l->literal, *args)) + { + completion->tracker.add_completion + (make_unique_xstrdup (l->literal)); + completions = true; + } + if (completions) + return {}; } } - if (match->type == var_zuinteger_unlimited) - { - option_value val; - val.integer = parse_cli_var_zuinteger_unlimited (args, false); - return option_def_and_value {*match, match_ctx, val}; - } + LONGEST v = parse_cli_var_integer (match->type, + match->extra_literals, + args, false); + option_value val; + if (match->type == var_uinteger) + val.uinteger = v; else - { - option_value val; - val.uinteger = parse_cli_var_uinteger (match->type, args, false); - return option_def_and_value {*match, match_ctx, val}; - } + val.integer = v; + return option_def_and_value {*match, match_ctx, val}; } case var_enum: { @@ -593,7 +603,8 @@ save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov) *ov->option.var_address.uinteger (ov->option, ov->ctx) = ov->value->uinteger; break; - case var_zuinteger_unlimited: + case var_integer: + case var_pinteger: *ov->option.var_address.integer (ov->option, ov->ctx) = ov->value->integer; break; @@ -664,8 +675,20 @@ get_val_type_str (const option_def &opt, std::string &buffer) case var_boolean: return "[on|off]"; case var_uinteger: - case var_zuinteger_unlimited: - return "NUMBER|unlimited"; + case var_integer: + case var_pinteger: + { + buffer = "NUMBER"; + if (opt.extra_literals != nullptr) + for (const literal_def *l = opt.extra_literals; + l->literal != nullptr; + l++) + { + buffer += '|'; + buffer += l->literal; + } + return buffer.c_str (); + } case var_enum: { buffer = ""; @@ -789,20 +812,31 @@ add_setshow_cmds_for_options (command_class cmd_class, { add_setshow_uinteger_cmd (option.name, cmd_class, option.var_address.uinteger (option, data), + option.extra_literals, option.set_doc, option.show_doc, option.help_doc, nullptr, option.show_cmd_cb, set_list, show_list); } - else if (option.type == var_zuinteger_unlimited) + else if (option.type == var_integer) + { + add_setshow_integer_cmd (option.name, cmd_class, + option.var_address.integer (option, data), + option.extra_literals, + option.set_doc, option.show_doc, + option.help_doc, + nullptr, option.show_cmd_cb, + set_list, show_list); + } + else if (option.type == var_pinteger) { - add_setshow_zuinteger_unlimited_cmd - (option.name, cmd_class, - option.var_address.integer (option, data), - option.set_doc, option.show_doc, - option.help_doc, - nullptr, option.show_cmd_cb, - set_list, show_list); + add_setshow_pinteger_cmd (option.name, cmd_class, + option.var_address.integer (option, data), + option.extra_literals, + option.set_doc, option.show_doc, + option.help_doc, + nullptr, option.show_cmd_cb, + set_list, show_list); } else if (option.type == var_enum) { diff --git a/gdb/cli/cli-option.h b/gdb/cli/cli-option.h index 319ae3b..7b015b8 100644 --- a/gdb/cli/cli-option.h +++ b/gdb/cli/cli-option.h @@ -49,12 +49,13 @@ protected: used to create the option's "set/show" commands. */ constexpr option_def (const char *name_, var_types var_type_, + const literal_def *extra_literals_, erased_get_var_address_ftype *erased_get_var_address_, show_value_ftype *show_cmd_cb_, const char *set_doc_, const char *show_doc_, const char *help_doc_) - : name (name_), type (var_type_), + : name (name_), type (var_type_), extra_literals (extra_literals_), erased_get_var_address (erased_get_var_address_), var_address {}, show_cmd_cb (show_cmd_cb_), @@ -68,6 +69,9 @@ public: /* The option's type. */ var_types type; + /* Extra literals, such as `unlimited', accepted in lieu of a number. */ + const literal_def *extra_literals; + /* A function that gets the controlling variable's address, type erased. */ erased_get_var_address_ftype *erased_get_var_address; @@ -160,7 +164,7 @@ struct boolean_option_def : option_def const char *set_doc_, const char *show_doc_ = nullptr, const char *help_doc_ = nullptr) - : option_def (long_option_, var_boolean, + : option_def (long_option_, var_boolean, nullptr, (erased_get_var_address_ftype *) get_var_address_cb_, show_cmd_cb_, set_doc_, show_doc_, help_doc_) @@ -207,37 +211,59 @@ struct uinteger_option_def : option_def { uinteger_option_def (const char *long_option_, unsigned int *(*get_var_address_cb_) (Context *), + const literal_def *extra_literals_, show_value_ftype *show_cmd_cb_, const char *set_doc_, const char *show_doc_ = nullptr, const char *help_doc_ = nullptr) - : option_def (long_option_, var_uinteger, + : option_def (long_option_, var_uinteger, extra_literals_, (erased_get_var_address_ftype *) get_var_address_cb_, show_cmd_cb_, set_doc_, show_doc_, help_doc_) { var_address.uinteger = detail::get_var_address<unsigned int, Context>; } + + uinteger_option_def (const char *long_option_, + unsigned int *(*get_var_address_cb_) (Context *), + show_value_ftype *show_cmd_cb_, + const char *set_doc_, + const char *show_doc_ = nullptr, + const char *help_doc_ = nullptr) + : uinteger_option_def (long_option_, get_var_address_cb_, nullptr, + show_cmd_cb_, set_doc_, show_doc_, help_doc_) + { /* Nothing. */ } }; -/* A var_zuinteger_unlimited command line option. */ +/* A var_pinteger command line option. */ template<typename Context> -struct zuinteger_unlimited_option_def : option_def +struct pinteger_option_def : option_def { - zuinteger_unlimited_option_def (const char *long_option_, - int *(*get_var_address_cb_) (Context *), - show_value_ftype *show_cmd_cb_, - const char *set_doc_, - const char *show_doc_ = nullptr, - const char *help_doc_ = nullptr) - : option_def (long_option_, var_zuinteger_unlimited, + pinteger_option_def (const char *long_option_, + int *(*get_var_address_cb_) (Context *), + const literal_def *extra_literals_, + show_value_ftype *show_cmd_cb_, + const char *set_doc_, + const char *show_doc_ = nullptr, + const char *help_doc_ = nullptr) + : option_def (long_option_, var_pinteger, extra_literals_, (erased_get_var_address_ftype *) get_var_address_cb_, show_cmd_cb_, set_doc_, show_doc_, help_doc_) { var_address.integer = detail::get_var_address<int, Context>; } + + pinteger_option_def (const char *long_option_, + int *(*get_var_address_cb_) (Context *), + show_value_ftype *show_cmd_cb_, + const char *set_doc_, + const char *show_doc_ = nullptr, + const char *help_doc_ = nullptr) + : pinteger_option_def (long_option_, get_var_address_cb_, nullptr, + show_cmd_cb_, set_doc_, show_doc_, help_doc_) + { /* Nothing. */ } }; /* An var_enum command line option. */ @@ -252,7 +278,7 @@ struct enum_option_def : option_def const char *set_doc_, const char *show_doc_ = nullptr, const char *help_doc_ = nullptr) - : option_def (long_option_, var_enum, + : option_def (long_option_, var_enum, nullptr, (erased_get_var_address_ftype *) get_var_address_cb_, show_cmd_cb_, set_doc_, show_doc_, help_doc_) @@ -273,7 +299,7 @@ struct string_option_def : option_def const char *set_doc_, const char *show_doc_ = nullptr, const char *help_doc_ = nullptr) - : option_def (long_option_, var_string, + : option_def (long_option_, var_string, nullptr, (erased_get_var_address_ftype *) get_var_address_cb_, show_cmd_cb_, set_doc_, show_doc_, help_doc_) diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index dccf04e..dad3e60 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_file *ignore_file, } } -/* Returns true if ARG is "unlimited". */ +/* Returns true and the value in VAL if ARG is an accepted literal. */ static bool -is_unlimited_literal (const char **arg, bool expression) +get_literal_val (LONGEST &val, const literal_def *extra_literals, + const char **arg, bool expression) { *arg = skip_spaces (*arg); @@ -162,85 +163,104 @@ is_unlimited_literal (const char **arg, bool expression) size_t len = p - *arg; - if (len > 0 && strncmp ("unlimited", *arg, len) == 0) - { - *arg += len; - - /* If parsing an expression (i.e., parsing for a "set" command), - anything after "unlimited" is junk. For options, anything - after "unlimited" might be a command argument or another - option. */ - if (expression) + if (len > 0 && extra_literals != nullptr) + for (const literal_def *l = extra_literals; + l->literal != nullptr; + l++) + if (strncmp (l->literal, *arg, len) == 0) { - const char *after = skip_spaces (*arg); - if (*after != '\0') - error (_("Junk after \"%.*s\": %s"), - (int) len, unl_start, after); - } + *arg += len; - return true; - } + /* If parsing an expression (i.e., parsing for a "set" command), + anything after the literal is junk. For options, anything + after the literal might be a command argument or another + option. */ + if (expression) + { + const char *after = skip_spaces (*arg); + if (*after != '\0') + error (_("Junk after \"%.*s\": %s"), + (int) len, unl_start, after); + } + + val = l->use; + return true; + } return false; } /* See cli-setshow.h. */ -unsigned int -parse_cli_var_uinteger (var_types var_type, const char **arg, - bool expression) +LONGEST +parse_cli_var_integer (var_types var_type, const literal_def *extra_literals, + const char **arg, bool expression) { LONGEST val; if (*arg == nullptr || **arg == '\0') { - if (var_type == var_uinteger) - error_no_arg (_("integer to set it to, or \"unlimited\"")); - else + if (extra_literals == nullptr) error_no_arg (_("integer to set it to")); - } - - if (var_type == var_uinteger && is_unlimited_literal (arg, expression)) - val = 0; - else if (expression) - val = parse_and_eval_long (*arg); - else - val = get_ulongest (arg); - - if (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. */ - || (var_type == var_uinteger && val >= UINT_MAX) - || (var_type == var_zuinteger && val > UINT_MAX)) - error (_("integer %s out of range"), plongest (val)); - - return val; -} - -/* See cli-setshow.h. */ + else + { + std::string buffer = ""; + size_t count = 0; -int -parse_cli_var_zuinteger_unlimited (const char **arg, bool expression) -{ - LONGEST val; + for (const literal_def *l = extra_literals; + l->literal != nullptr; + l++, count++) + { + if (count != 0) + buffer += ", "; + buffer = buffer + '"' + l->literal + '"'; + } + if (count > 1) + error_no_arg + (string_printf (_("integer to set it to, or one of: %s"), + buffer.c_str ()).c_str ()); + else + error_no_arg + (string_printf (_("integer to set it to, or %s"), + buffer.c_str ()).c_str ()); + } + } - if (*arg == nullptr || **arg == '\0') - error_no_arg (_("integer to set it to, or \"unlimited\"")); + if (!get_literal_val (val, extra_literals, arg, expression)) + { + if (expression) + val = parse_and_eval_long (*arg); + else + val = get_ulongest (arg); - if (is_unlimited_literal (arg, expression)) - val = -1; - else if (expression) - val = parse_and_eval_long (*arg); - else - val = get_ulongest (arg); + enum tribool allowed = TRIBOOL_UNKNOWN; + if (extra_literals != nullptr) + { + for (const literal_def *l = extra_literals; + l->literal != nullptr; + l++) + if (l->val.has_value () && val == *l->val) + { + allowed = TRIBOOL_TRUE; + val = l->use; + break; + } + else if (val == l->use) + allowed = TRIBOOL_FALSE; + } - 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 (allowed == TRIBOOL_UNKNOWN) + { + if (val > UINT_MAX || val < INT_MIN + || (var_type == var_uinteger && val < 0) + || (var_type == var_integer && val > INT_MAX) + || (var_type == var_pinteger && val < 0) + || (var_type == var_pinteger && val > INT_MAX)) + allowed = TRIBOOL_FALSE; + } + if (allowed == TRIBOOL_FALSE) + error (_("integer %s out of range"), plongest (val)); + } return val; } @@ -405,41 +425,18 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg)); break; case var_uinteger: - case var_zuinteger: option_changed - = c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (), - &arg, true)); + = c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (), + c->var-> + extra_literals (), + &arg, true)); break; case var_integer: - case var_zinteger: - { - LONGEST val; - - if (*arg == '\0') - { - 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, true)) - 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)); - - option_changed = c->var->set<int> (val); - } + case var_pinteger: + option_changed + = c->var->set<int> (parse_cli_var_integer (c->var->type (), + c->var->extra_literals (), + &arg, true)); break; case var_enum: { @@ -454,10 +451,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) option_changed = c->var->set<const char *> (match); } break; - case var_zuinteger_unlimited: - option_changed = c->var->set<int> - (parse_cli_var_zuinteger_unlimited (&arg, true)); - break; default: error (_("gdb internal error: bad var_type in do_setshow_command")); } @@ -551,7 +544,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) } break; case var_uinteger: - case var_zuinteger: { char s[64]; @@ -560,8 +552,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) } break; case var_integer: - case var_zinteger: - case var_zuinteger_unlimited: + case var_pinteger: { char s[64]; @@ -623,36 +614,32 @@ get_setshow_command_value_string (const setting &var) } break; case var_uinteger: - case var_zuinteger: - { - const unsigned int value = var.get<unsigned int> (); - - if (var.type () == var_uinteger - && value == UINT_MAX) - stb.puts ("unlimited"); - else - stb.printf ("%u", value); - } - break; case var_integer: - case var_zinteger: - { - const int value = var.get<int> (); - - if (var.type () == var_integer - && value == INT_MAX) - stb.puts ("unlimited"); - else - stb.printf ("%d", value); - } - break; - case var_zuinteger_unlimited: + case var_pinteger: { - const int value = var.get<int> (); - if (value == -1) - stb.puts ("unlimited"); - else - stb.printf ("%d", value); + bool printed = false; + const LONGEST value + = (var.type () == var_uinteger + ? static_cast<LONGEST> (var.get<unsigned int> ()) + : static_cast<LONGEST> (var.get<int> ())); + + if (var.extra_literals () != nullptr) + for (const literal_def *l = var.extra_literals (); + l->literal != nullptr; + l++) + if (value == l->use) + { + stb.puts (l->literal); + printed = true; + break; + } + if (!printed) + { + if (var.type () == var_uinteger) + stb.printf ("%u", static_cast<unsigned int> (value)); + else + stb.printf ("%d", static_cast<int> (value)); + } } break; default: diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index 78573c0..bc70ea6 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (const char *arg); past a successfully parsed value. */ extern int parse_cli_boolean_value (const char **arg); -/* Parse ARG, an option to a var_uinteger or var_zuinteger variable. - Either returns the parsed value on success or throws an error. If - EXPRESSION is true, *ARG is parsed as an expression; otherwise, it - is parsed with get_ulongest. It's not possible to parse the +/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger + variable. Return the parsed value on success or throw an error. If + EXTRA_LITERALS is non-null, then interpret those literals accordingly. + If EXPRESSION is true, *ARG is parsed as an expression; otherwise, + it is parsed with get_ulongest. It's not possible to parse the integer as an expression when there may be valid input after the integer, such as when parsing command options. E.g., "print -elements NUMBER -obj --". In such case, parsing as an expression would parse "-obj --" as part of the expression as well. */ -extern unsigned int parse_cli_var_uinteger (var_types var_type, - const char **arg, - bool expression); - -/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited. */ -extern int parse_cli_var_zuinteger_unlimited (const char **arg, - bool expression); +extern LONGEST parse_cli_var_integer (var_types var_type, + const literal_def *extra_literals, + const char **arg, + bool expression); /* Parse ARG, an option to a var_enum variable. ENUM is a null-terminated array of possible values. Either returns the parsed |