diff --git a/gdb/ChangeLog b/gdb/ChangeLog index adc56b49899..43f0ef14cec 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,27 @@ +2019-07-03 Pedro Alves + + * cli/cli-option.c (parse_option) : Don't return an + option_value with a null enumeration. + (complete_options): Save the option values in the context. + (save_option_value_in_ctx): New, factored out from ... + (process_options): ... here. + * cli/cli-utils.c (get_ulongest): Don't advance PP until the end + of the function. + * maint-test-options.c (test_options_opts::dump): New, factored + out from ... + (maintenance_test_options_command_mode): ... here. + (maintenance_test_options_command_completion_result): Delete. + (maintenance_test_options_command_completion_text): Update + comment. + (maintenance_show_test_options_completion_result): Change + prototype. Just print + maintenance_test_options_command_completion_text. + (save_completion_result): New. + (maintenance_test_options_completer_mode): Pass options context to + complete_options, and then save a dump. + (_initialize_maint_test_options): Use add_cmd to install "maint + show test-options-completion-result". + 2019-07-03 Pedro Alves * NEWS (New commands): Mention "with" and "maint with". diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c index 9a53ec0592d..8f2844610b5 100644 --- a/gdb/cli/cli-option.c +++ b/gdb/cli/cli-option.c @@ -58,6 +58,8 @@ struct option_def_and_value gdb::optional value; }; +static void save_option_value_in_ctx (gdb::optional &ov); + /* Info passed around when handling completion. */ struct parse_option_completion_info { @@ -349,11 +351,12 @@ parse_option (gdb::array_view options_group, { complete_on_enum (completion->tracker, match->enums, *args, *args); - *args = after_arg; + if (completion->tracker.have_completions ()) + return {}; - option_value val; - val.enumeration = nullptr; - return option_def_and_value {*match, match_ctx, val}; + /* If we don't have completions, let the + non-completion path throw on invalid enum value + below, so that completion processing stops. */ } } @@ -456,6 +459,11 @@ complete_options (completion_tracker &tracker, (*args - text); return true; } + + /* If the caller passed in a context, then it is + interested in the option argument values. */ + if (ov && ov->ctx != nullptr) + save_option_value_in_ctx (ov); } else { @@ -499,6 +507,36 @@ complete_options (completion_tracker &tracker, return false; } +/* Save the parsed value in the option's context. */ + +static void +save_option_value_in_ctx (gdb::optional &ov) +{ + switch (ov->option.type) + { + case var_boolean: + { + bool value = ov->value.has_value () ? ov->value->boolean : true; + *ov->option.var_address.boolean (ov->option, ov->ctx) = value; + } + break; + case var_uinteger: + *ov->option.var_address.uinteger (ov->option, ov->ctx) + = ov->value->uinteger; + break; + case var_zuinteger_unlimited: + *ov->option.var_address.integer (ov->option, ov->ctx) + = ov->value->integer; + break; + case var_enum: + *ov->option.var_address.enumeration (ov->option, ov->ctx) + = ov->value->enumeration; + break; + default: + gdb_assert_not_reached ("unhandled option type"); + } +} + /* See cli-option.h. */ bool @@ -534,29 +572,7 @@ process_options (const char **args, processed_any = true; - switch (ov->option.type) - { - case var_boolean: - { - bool value = ov->value.has_value () ? ov->value->boolean : true; - *ov->option.var_address.boolean (ov->option, ov->ctx) = value; - } - break; - case var_uinteger: - *ov->option.var_address.uinteger (ov->option, ov->ctx) - = ov->value->uinteger; - break; - case var_zuinteger_unlimited: - *ov->option.var_address.integer (ov->option, ov->ctx) - = ov->value->integer; - break; - case var_enum: - *ov->option.var_address.enumeration (ov->option, ov->ctx) - = ov->value->enumeration; - break; - default: - gdb_assert_not_reached ("unhandled option type"); - } + save_option_value_in_ctx (ov); } } diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c index f5d47aeffbc..333a86a81b9 100644 --- a/gdb/cli/cli-utils.c +++ b/gdb/cli/cli-utils.c @@ -60,13 +60,14 @@ get_ulongest (const char **pp, int trailer) } else { - retval = strtoulst (p, pp, 0); - if (p == *pp) + const char *end = p; + retval = strtoulst (p, &end, 0); + if (p == end) { /* There is no number here. (e.g. "cond a == b"). */ error (_("Expected integer at: %s"), p); } - p = *pp; + p = end; } if (!(isspace (*p) || *p == '\0' || *p == trailer)) diff --git a/gdb/maint-test-options.c b/gdb/maint-test-options.c index 599155cbfe6..7e7ef6e7992 100644 --- a/gdb/maint-test-options.c +++ b/gdb/maint-test-options.c @@ -133,6 +133,27 @@ struct test_options_opts const char *enum_opt = test_options_enum_values_xxx; unsigned int uint_opt = 0; int zuint_unl_opt = 0; + + /* Dump the options to FILE. ARGS is the remainder unprocessed + arguments. */ + void dump (ui_file *file, const char *args) const + { + fprintf_unfiltered (file, + _("-flag %d -xx1 %d -xx2 %d -bool %d " + "-enum %s -uint %s -zuint-unl %s -- %s\n"), + flag_opt, + xx1_opt, + xx2_opt, + boolean_opt, + enum_opt, + (uint_opt == UINT_MAX + ? "unlimited" + : pulongest (uint_opt)), + (zuint_unl_opt == -1 + ? "unlimited" + : plongest (zuint_unl_opt)), + args); + } }; /* Option definitions for the "maintenance test-options" commands. */ @@ -226,46 +247,48 @@ maintenance_test_options_command_mode (const char *args, else args = skip_spaces (args); - printf_unfiltered (_("-flag %d -xx1 %d -xx2 %d -bool %d " - "-enum %s -uint %s -zuint-unl %s -- %s\n"), - opts.flag_opt, - opts.xx1_opt, - opts.xx2_opt, - opts.boolean_opt, - opts.enum_opt, - (opts.uint_opt == UINT_MAX - ? "unlimited" - : pulongest (opts.uint_opt)), - (opts.zuint_unl_opt == -1 - ? "unlimited" - : plongest (opts.zuint_unl_opt)), - args); + opts.dump (gdb_stdout, args); } -/* Variables used by the "maintenance show - test-options-completion-result" command. These variables are - stored by the completer of the "maint test-options" - subcommands. */ +/* Variable used by the "maintenance show + test-options-completion-result" command. This variable is stored + by the completer of the "maint test-options" subcommands. -/* The result of gdb::option::complete_options. */ -static int maintenance_test_options_command_completion_result; -/* The text at the word point after gdb::option::complete_options - returns. */ + If the completer returned false, this includes the text at the word + point after gdb::option::complete_options returns. If true, then + this includes a dump of the processed options. */ static std::string maintenance_test_options_command_completion_text; /* The "maintenance show test-options-completion-result" command. */ static void -maintenance_show_test_options_completion_result - (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) +maintenance_show_test_options_completion_result (const char *args, + int from_tty) { - if (maintenance_test_options_command_completion_result) - fprintf_filtered (file, "1\n"); + puts_filtered (maintenance_test_options_command_completion_text.c_str ()); +} + +/* Save the completion result in the global variables read by the + "maintenance test-options require-delimiter" command. */ + +static void +save_completion_result (const test_options_opts &opts, bool res, + const char *text) +{ + if (res) + { + string_file stream; + + stream.puts ("1 "); + opts.dump (&stream, text); + maintenance_test_options_command_completion_text + = std::move (stream.string ()); + } else - fprintf_filtered - (file, _("0 %s\n"), - maintenance_test_options_command_completion_text.c_str ()); + { + maintenance_test_options_command_completion_text + = string_printf ("0 %s\n", text); + } } /* Implementation of completer for the "maintenance test-options @@ -278,17 +301,19 @@ maintenance_test_options_completer_mode (completion_tracker &tracker, const char *text, gdb::option::process_options_mode mode) { + test_options_opts opts; + try { - maintenance_test_options_command_completion_result - = gdb::option::complete_options - (tracker, &text, mode, - make_test_options_options_def_group (nullptr)); - maintenance_test_options_command_completion_text = text; + bool res = (gdb::option::complete_options + (tracker, &text, mode, + make_test_options_options_def_group (&opts))); + + save_completion_result (opts, res, text); } catch (const gdb_exception_error &ex) { - maintenance_test_options_command_completion_result = 1; + save_completion_result (opts, true, text); throw; } } @@ -445,17 +470,13 @@ Options:\n\ set_cmd_completer_handle_brkchars (cmd, maintenance_test_options_unknown_is_operand_command_completer); - add_setshow_zinteger_cmd ("test-options-completion-result", class_maintenance, - &maintenance_test_options_command_completion_result, - _("\ -Set maintenance test-options completion result."), _("\ -Show maintenance test-options completion result."), _("\ -Show the results of completing\n\ + add_cmd ("test-options-completion-result", class_maintenance, + maintenance_show_test_options_completion_result, + _("\ +Show maintenance test-options completion result.\n\ +Shows the results of completing\n\ \"maint test-options require-delimiter\",\n\ \"maint test-options unknown-is-error\", or\n\ \"maint test-options unknown-is-operand\"."), - NULL, - maintenance_show_test_options_completion_result, - &maintenance_set_cmdlist, - &maintenance_show_cmdlist); + &maintenance_show_cmdlist); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 6e2234984da..209f15f9c35 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-07-03 Pedro Alves + + * gdb.base/options.exp (test-misc, test-flag, test-boolean) + (test-uinteger, test-enum): Adjust res_test_gdb_... calls to pass + the expected output in the success. + 2019-07-03 Pedro Alves * lib/completion-support.exp (test_gdb_complete_tab_multiple): diff --git a/gdb/testsuite/gdb.base/options.exp b/gdb/testsuite/gdb.base/options.exp index f88e6a87d3e..1a652b3c9dc 100644 --- a/gdb/testsuite/gdb.base/options.exp +++ b/gdb/testsuite/gdb.base/options.exp @@ -486,21 +486,27 @@ proc_with_prefix test-misc {variant} { } # Completing at "-" should list all options. - res_test_gdb_complete_multiple "1" "$cmd " "-" "" $all_options + res_test_gdb_complete_multiple \ + "1 [expect_none "-"]" \ + "$cmd " "-" "" $all_options # Now with a double dash. gdb_test "$cmd --" [expect_none ""] # "--" is recognized by options completer, gdb auto-appends a # space. - test_completer_recognizes 1 "$cmd --" + test_completer_recognizes \ + "1 [expect_none "--"]" \ + "$cmd --" # Now with a double dash, plus a dash as operand. gdb_test "$cmd -- -" [expect_none "-"] res_test_gdb_complete_none "0 -" "$cmd -- -" # Completing an unambiguous option just appends an empty space. - test_completer_recognizes 1 "$cmd -flag" + test_completer_recognizes \ + "1 [expect_none "-flag"]" \ + "$cmd -flag" # Try running an ambiguous option. if {$variant == "require-delimiter"} { @@ -540,10 +546,14 @@ proc_with_prefix test-flag {variant} { set cmd [make_cmd $variant] # Completing a flag just appends a space. - test_completer_recognizes 1 "$cmd -flag" + test_completer_recognizes \ + "1 [expect_none "-flag"]" \ + "$cmd -flag" # Add a dash, and all options should be shown. - test_gdb_complete_multiple "$cmd -flag " "-" "" $all_options + res_test_gdb_complete_multiple \ + "1 [expect_flag "-"]" \ + "$cmd -flag " "-" "" $all_options # Basic smoke tests of accepted / not accepted values. @@ -582,7 +592,9 @@ proc_with_prefix test-flag {variant} { # "on/off". if {$variant == "require-delimiter"} { - res_test_gdb_complete_none "1" "$cmd -flag o" + res_test_gdb_complete_none \ + "1 [expect_flag "o"]" \ + "$cmd -flag o" gdb_test "$cmd -flag o" [expect_none "-flag o"] } else { @@ -612,7 +624,9 @@ proc_with_prefix test-boolean {variant} { # E.g., "frame apply all -past-main COMMAND". if {$variant == "require-delimiter"} { - res_test_gdb_complete_multiple 1 "$cmd -bool " "" "" { + res_test_gdb_complete_multiple \ + "1 [expect_none ""]" \ + "$cmd -bool " "" "" { "-bool" "-enum" "-flag" @@ -628,7 +642,9 @@ proc_with_prefix test-boolean {variant} { } # Add another dash, and "on/off" are no longer offered: - res_test_gdb_complete_multiple 1 "$cmd -bool " "-" "" $all_options + res_test_gdb_complete_multiple \ + "1 [expect_bool "-"]" \ + "$cmd -bool " "-" "" $all_options # Basic smoke tests of accepted / not accepted values. @@ -643,20 +659,25 @@ proc_with_prefix test-boolean {variant} { # However, the completer does recognize them if you start typing # the boolean value. foreach value {"0" "1"} { - test_completer_recognizes 1 "$cmd -bool $value" + test_completer_recognizes \ + "1 [expect_none ""]" \ + "$cmd -bool $value" } foreach value {"of" "off"} { - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none ""]" \ "$cmd -bool $value" \ "$cmd -bool off" } foreach value {"y" "ye" "yes"} { - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none ""]" \ "$cmd -bool $value" \ "$cmd -bool yes" } foreach value {"n" "no"} { - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none ""]" \ "$cmd -bool $value" \ "$cmd -bool no" } @@ -668,7 +689,8 @@ proc_with_prefix test-boolean {variant} { "enabl" "enable" } { - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none ""]" \ "$cmd -bool $value" \ "$cmd -bool enable" } @@ -681,13 +703,16 @@ proc_with_prefix test-boolean {variant} { "disabl" "disable" } { - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none ""]" \ "$cmd -bool $value" \ "$cmd -bool disable" } if {$variant == "require-delimiter"} { - res_test_gdb_complete_none "1" "$cmd -bool xxx" + res_test_gdb_complete_none \ + "1 [expect_none "xxx"]" \ + "$cmd -bool xxx" } else { res_test_gdb_complete_none "0 xxx" "$cmd -bool xxx" } @@ -763,7 +788,9 @@ proc_with_prefix test-boolean {variant} { # Completing after a boolean option + "o" does list "on/off", # though. if {$variant == "require-delimiter"} { - res_test_gdb_complete_multiple 1 "$cmd -bool " "o" "" { + res_test_gdb_complete_multiple \ + "1 [expect_none "o"]" \ + "$cmd -bool " "o" "" { "off" "on" } @@ -783,17 +810,22 @@ proc_with_prefix test-uinteger {variant option} { set cmd "[make_cmd $variant] -$option" # Test completing a uinteger option: - res_test_gdb_complete_multiple 1 "$cmd " "" "" { + res_test_gdb_complete_multiple \ + "1 [expect_none ""]" \ + "$cmd " "" "" { "NUMBER" "unlimited" } # NUMBER above is just a placeholder, make sure we don't complete # it as a valid option. - res_test_gdb_complete_none 1 "$cmd NU" + res_test_gdb_complete_none \ + "1 [expect_none "NU"]" \ + "$cmd NU" # "unlimited" is valid though. - res_test_gdb_complete_unique 1 \ + res_test_gdb_complete_unique \ + "1 [expect_none "u"]" \ "$cmd u" \ "$cmd unlimited" @@ -815,24 +847,34 @@ proc_with_prefix test-uinteger {variant option} { # Don't offer completions until we're past the # -uinteger/-zuinteger-unlimited argument. - res_test_gdb_complete_none 1 "$cmd 1" + res_test_gdb_complete_none \ + "1 [expect_none ""]" \ + "$cmd 1" # A number of invalid values. foreach value {"x" "x " "1a" "1a " "1-" "1- " "unlimitedx"} { - res_test_gdb_complete_none 1 "$cmd $value" + res_test_gdb_complete_none \ + "1 [expect_none $value]" \ + "$cmd $value" } # Try "-1". if {$option == "uinteger"} { # -1 is invalid uinteger. foreach value {"-1" "-1 "} { - res_test_gdb_complete_none 1 "$cmd $value" + res_test_gdb_complete_none \ + "1 [expect_none ""]" \ + "$cmd $value" } } else { # -1 is valid for zuinteger-unlimited. - res_test_gdb_complete_none 1 "$cmd -1" + res_test_gdb_complete_none \ + "1 [expect_none ""]" \ + "$cmd -1" if {$variant == "require-delimiter"} { - res_test_gdb_complete_multiple 1 "$cmd -1 " "" "-" $all_options + res_test_gdb_complete_multiple \ + "1 [expect_integer $option "unlimited" ""]" \ + "$cmd -1 " "" "-" $all_options } else { res_test_gdb_complete_none "0 " "$cmd -1 " } @@ -846,7 +888,9 @@ proc_with_prefix test-uinteger {variant option} { # - for !require-delimiter commands, completion offers nothing # and returns false. if {$variant == "require-delimiter"} { - res_test_gdb_complete_multiple 1 "$cmd 1 " "" "-" $all_options + res_test_gdb_complete_multiple \ + "1 [expect_integer $option 1 ""]" \ + "$cmd 1 " "" "-" $all_options } else { res_test_gdb_complete_none "0 " "$cmd 1 " } @@ -854,7 +898,9 @@ proc_with_prefix test-uinteger {variant option} { # Test completing non-option arguments after "-uinteger 1 ". foreach operand {"x" "x " "1a" "1a " "1-" "1- "} { if {$variant == "require-delimiter"} { - res_test_gdb_complete_none 1 "$cmd 1 $operand" + res_test_gdb_complete_none \ + "1 [expect_integer $option 1 $operand]" \ + "$cmd 1 $operand" } else { res_test_gdb_complete_none "0 $operand" "$cmd 1 $operand" } @@ -864,7 +910,9 @@ proc_with_prefix test-uinteger {variant option} { if {$variant == "unknown-is-operand"} { res_test_gdb_complete_none "0 $operand" "$cmd 1 $operand" } else { - res_test_gdb_complete_none 1 "$cmd 1 $operand" + res_test_gdb_complete_none \ + "1 [expect_integer $option 1 $operand]" \ + "$cmd 1 $operand" } } } @@ -873,7 +921,9 @@ proc_with_prefix test-uinteger {variant option} { proc_with_prefix test-enum {variant} { set cmd [make_cmd $variant] - res_test_gdb_complete_multiple 1 "$cmd -enum " "" "" { + res_test_gdb_complete_multiple \ + "1 [expect_none ""]" \ + "$cmd -enum " "" "" { "xxx" "yyy" "zzz" @@ -882,7 +932,9 @@ proc_with_prefix test-enum {variant} { # Check that "-" where a value is expected does not show the # command's options. I.e., an enum's value is not optional. # Check both completion and running the command. - res_test_gdb_complete_none 1 "$cmd -enum -" + res_test_gdb_complete_none \ + "1 [expect_none "-"]" \ + "$cmd -enum -" gdb_test "$cmd -enum --"\ "Requires an argument. Valid arguments are xxx, yyy, zzz\\."