RISC-V: Don't report warnings when linking different privileged spec objects.
[binutils-gdb.git] / gdb / maint-test-options.c
blob9d7681777984e886589352b4a9da215c7193abda
1 /* Maintenance commands for testing the options framework.
3 Copyright (C) 2019-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "cli/cli-cmds.h"
21 #include "cli/cli-option.h"
23 /* This file defines three "maintenance test-options" subcommands to
24 exercise TAB-completion and option processing:
26 (gdb) maint test-options require-delimiter
27 (gdb) maint test-options unknown-is-error
28 (gdb) maint test-options unknown-is-operand
30 And a fourth one to help with TAB-completion testing.
32 (gdb) maint show test-options-completion-result
34 Each of the test-options subcommands exercise
35 gdb::option::process_options with a different enum
36 process_options_mode value. Examples for commands they model:
38 - "print" and "compile print", are like "require-delimiter",
39 because they accept random expressions as argument.
41 - "backtrace" and "frame/thread apply" are like
42 "unknown-is-operand", because "-" is a valid command.
44 - "compile file" and "compile code" are like "unknown-is-error".
46 These commands allow exercising all aspects of option processing
47 without having to pick some existing command. That should be more
48 stable going forward than relying on an existing user command,
49 since if we picked say "print", that command or its options could
50 change in future, and then we'd be left with having to pick some
51 other command or option to exercise some non-command-specific
52 option processing detail. Also, actual user commands have side
53 effects that we're not interested in when we're focusing on unit
54 testing the options machinery. BTW, a maintenance command is used
55 as a sort of unit test driver instead of actual "maint selftest"
56 unit tests, since we need to go all the way via gdb including
57 readline, for proper testing of TAB completion.
59 These maintenance commands support options of all the different
60 available kinds of commands (boolean, enum, flag, string, filename,
61 uinteger):
63 (gdb) maint test-options require-delimiter -[TAB]
64 -bool -flag -uinteger-unlimited
65 -enum -pinteger-unlimited -xx1
66 -filename -string -xx2
68 (gdb) maint test-options require-delimiter -bool o[TAB]
69 off on
70 (gdb) maint test-options require-delimiter -enum [TAB]
71 xxx yyy zzz
72 (gdb) maint test-options require-delimiter -uinteger-unlimited [TAB]
73 NUMBER unlimited
75 '-xx1' and '-xx2' are flag options too. They exist in order to
76 test ambiguous option names, like '-xx'.
78 Invoking the commands makes them print out the options parsed:
80 (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
81 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -filename '' -- cmdarg
83 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
84 -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint-unl 0 -pint-unl 0 -string '' -filename '' -- -flag -enum yyy cmdarg
85 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
86 Unrecognized option at: cmdarg --
87 (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
88 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint-unl 0 -pint-unl 0 -string '' -filename '' -- cmdarg
90 The "maint show test-options-completion-result" command exists in
91 order to do something similar for completion:
93 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
94 (gdb) maint show test-options-completion-result
95 0 OPERAND
97 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
98 (gdb) maint show test-options-completion-result
101 (gdb) maint test-options require-dash -unknown[TAB]
102 (gdb) maint show test-options-completion-result
105 Here, "1" means the completion function processed the whole input
106 line, and that the command shouldn't do anything with the arguments,
107 since there are no operands. While "0" indicates that there are
108 operands after options. The text after "0" is the operands.
110 This level of detail is particularly important because getting the
111 completion function's entry point to return back to the caller the
112 right pointer into the operand is quite tricky in several
113 scenarios. */
115 /* Enum values for the "maintenance test-options" commands. */
116 const char test_options_enum_values_xxx[] = "xxx";
117 const char test_options_enum_values_yyy[] = "yyy";
118 const char test_options_enum_values_zzz[] = "zzz";
119 static const char *const test_options_enum_values_choices[] =
121 test_options_enum_values_xxx,
122 test_options_enum_values_yyy,
123 test_options_enum_values_zzz,
124 NULL
127 /* Option data for the "maintenance test-options" commands. */
129 struct test_options_opts
131 bool flag_opt = false;
132 bool xx1_opt = false;
133 bool xx2_opt = false;
134 bool boolean_opt = false;
135 const char *enum_opt = test_options_enum_values_xxx;
136 unsigned int uint_unl_opt = 0;
137 int pint_unl_opt = 0;
138 std::string string_opt;
139 std::string filename_opt;
141 test_options_opts () = default;
143 DISABLE_COPY_AND_ASSIGN (test_options_opts);
145 /* Dump the options to FILE. ARGS is the remainder unprocessed
146 arguments. */
147 void dump (ui_file *file, const char *args) const
149 gdb_printf (file,
150 _("-flag %d -xx1 %d -xx2 %d -bool %d "
151 "-enum %s -uint-unl %s -pint-unl %s -string '%s' "
152 "-filename '%s' -- %s\n"),
153 flag_opt,
154 xx1_opt,
155 xx2_opt,
156 boolean_opt,
157 enum_opt,
158 (uint_unl_opt == UINT_MAX
159 ? "unlimited"
160 : pulongest (uint_unl_opt)),
161 (pint_unl_opt == -1
162 ? "unlimited"
163 : plongest (pint_unl_opt)),
164 string_opt.c_str (),
165 filename_opt.c_str (),
166 args);
170 /* Option definitions for the "maintenance test-options" commands. */
172 static const gdb::option::option_def test_options_option_defs[] = {
174 /* A flag option. */
175 gdb::option::flag_option_def<test_options_opts> {
176 "flag",
177 [] (test_options_opts *opts) { return &opts->flag_opt; },
178 N_("A flag option."),
181 /* A couple flags with similar names, for "ambiguous option names"
182 testing. */
183 gdb::option::flag_option_def<test_options_opts> {
184 "xx1",
185 [] (test_options_opts *opts) { return &opts->xx1_opt; },
186 N_("A flag option."),
188 gdb::option::flag_option_def<test_options_opts> {
189 "xx2",
190 [] (test_options_opts *opts) { return &opts->xx2_opt; },
191 N_("A flag option."),
194 /* A boolean option. */
195 gdb::option::boolean_option_def<test_options_opts> {
196 "bool",
197 [] (test_options_opts *opts) { return &opts->boolean_opt; },
198 nullptr, /* show_cmd_cb */
199 N_("A boolean option."),
202 /* An enum option. */
203 gdb::option::enum_option_def<test_options_opts> {
204 "enum",
205 test_options_enum_values_choices,
206 [] (test_options_opts *opts) { return &opts->enum_opt; },
207 nullptr, /* show_cmd_cb */
208 N_("An enum option."),
211 /* A uinteger + "unlimited" option. */
212 gdb::option::uinteger_option_def<test_options_opts> {
213 "uinteger-unlimited",
214 [] (test_options_opts *opts) { return &opts->uint_unl_opt; },
215 uinteger_unlimited_literals,
216 nullptr, /* show_cmd_cb */
217 N_("A uinteger option."),
218 nullptr, /* show_doc */
219 N_("A help doc that spawns\nmultiple lines."),
222 /* A pinteger + "unlimited" option. */
223 gdb::option::pinteger_option_def<test_options_opts> {
224 "pinteger-unlimited",
225 [] (test_options_opts *opts) { return &opts->pint_unl_opt; },
226 pinteger_unlimited_literals,
227 nullptr, /* show_cmd_cb */
228 N_("A pinteger-unlimited option."),
229 nullptr, /* show_doc */
230 nullptr, /* help_doc */
233 /* A string option. */
234 gdb::option::string_option_def<test_options_opts> {
235 "string",
236 [] (test_options_opts *opts) { return &opts->string_opt; },
237 nullptr, /* show_cmd_cb */
238 N_("A string option."),
241 /* A filename option. */
242 gdb::option::filename_option_def<test_options_opts> {
243 "filename",
244 [] (test_options_opts *opts) { return &opts->filename_opt; },
245 nullptr, /* show_cmd_cb */
246 N_("A filename option."),
250 /* Create an option_def_group for the test_options_opts options, with
251 OPTS as context. */
253 static inline gdb::option::option_def_group
254 make_test_options_options_def_group (test_options_opts *opts)
256 return {{test_options_option_defs}, opts};
259 /* Implementation of the "maintenance test-options
260 require-delimiter/unknown-is-error/unknown-is-operand" commands.
261 Each of the commands maps to a different enum process_options_mode
262 enumerator. The test strategy is simply processing the options in
263 a number of scenarios, and printing back the parsed result. */
265 static void
266 maintenance_test_options_command_mode (const char *args,
267 gdb::option::process_options_mode mode)
269 test_options_opts opts;
271 gdb::option::process_options (&args, mode,
272 make_test_options_options_def_group (&opts));
274 if (args == nullptr)
275 args = "";
276 else
277 args = skip_spaces (args);
279 opts.dump (gdb_stdout, args);
282 /* Variable used by the "maintenance show
283 test-options-completion-result" command. This variable is stored
284 by the completer of the "maint test-options" subcommands.
286 If the completer returned false, this includes the text at the word
287 point after gdb::option::complete_options returns. If true, then
288 this includes a dump of the processed options. */
289 static std::string maintenance_test_options_command_completion_text;
291 /* The "maintenance show test-options-completion-result" command. */
293 static void
294 maintenance_show_test_options_completion_result (const char *args,
295 int from_tty)
297 gdb_puts (maintenance_test_options_command_completion_text.c_str ());
300 /* Save the completion result in the global variables read by the
301 "maintenance test-options require-delimiter" command. */
303 static void
304 save_completion_result (const test_options_opts &opts, bool res,
305 const char *text)
307 if (res)
309 string_file stream;
311 stream.puts ("1 ");
312 opts.dump (&stream, text);
313 maintenance_test_options_command_completion_text = stream.release ();
315 else
317 maintenance_test_options_command_completion_text
318 = string_printf ("0 %s\n", text);
322 /* Implementation of completer for the "maintenance test-options
323 require-delimiter/unknown-is-error/unknown-is-operand" commands.
324 Each of the commands maps to a different enum process_options_mode
325 enumerator. */
327 static void
328 maintenance_test_options_completer_mode (completion_tracker &tracker,
329 const char *text,
330 gdb::option::process_options_mode mode)
332 test_options_opts opts;
336 bool res = (gdb::option::complete_options
337 (tracker, &text, mode,
338 make_test_options_options_def_group (&opts)));
340 save_completion_result (opts, res, text);
342 catch (const gdb_exception_error &ex)
344 save_completion_result (opts, true, text);
345 throw;
349 /* Implementation of the "maintenance test-options require-delimiter"
350 command. */
352 static void
353 maintenance_test_options_require_delimiter_command (const char *args,
354 int from_tty)
356 maintenance_test_options_command_mode
357 (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
360 /* Implementation of the "maintenance test-options
361 unknown-is-error" command. */
363 static void
364 maintenance_test_options_unknown_is_error_command (const char *args,
365 int from_tty)
367 maintenance_test_options_command_mode
368 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
371 /* Implementation of the "maintenance test-options
372 unknown-is-operand" command. */
374 static void
375 maintenance_test_options_unknown_is_operand_command (const char *args,
376 int from_tty)
378 maintenance_test_options_command_mode
379 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
382 /* Completer for the "maintenance test-options require-delimiter"
383 command. */
385 static void
386 maintenance_test_options_require_delimiter_command_completer
387 (cmd_list_element *ignore, completion_tracker &tracker,
388 const char *text, const char *word)
390 maintenance_test_options_completer_mode
391 (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
394 /* Completer for the "maintenance test-options unknown-is-error"
395 command. */
397 static void
398 maintenance_test_options_unknown_is_error_command_completer
399 (cmd_list_element *ignore, completion_tracker &tracker,
400 const char *text, const char *word)
402 maintenance_test_options_completer_mode
403 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
406 /* Completer for the "maintenance test-options unknown-is-operand"
407 command. */
409 static void
410 maintenance_test_options_unknown_is_operand_command_completer
411 (cmd_list_element *ignore, completion_tracker &tracker,
412 const char *text, const char *word)
414 maintenance_test_options_completer_mode
415 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
418 /* Command list for maint test-options. */
419 static cmd_list_element *maintenance_test_options_list;
422 void _initialize_maint_test_options ();
423 void
424 _initialize_maint_test_options ()
426 cmd_list_element *cmd;
428 add_basic_prefix_cmd ("test-options", no_class,
429 _("\
430 Generic command for testing the options infrastructure."),
431 &maintenance_test_options_list,
432 0, &maintenancelist);
434 const auto def_group = make_test_options_options_def_group (nullptr);
436 static const std::string help_require_delim_str
437 = gdb::option::build_help (_("\
438 Command used for testing options processing.\n\
439 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
441 Options:\n\
442 %OPTIONS%\n\
444 If you specify any command option, you must use a double dash (\"--\")\n\
445 to mark the end of option processing."),
446 def_group);
448 static const std::string help_unknown_is_error_str
449 = gdb::option::build_help (_("\
450 Command used for testing options processing.\n\
451 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
453 Options:\n\
454 %OPTIONS%"),
455 def_group);
457 static const std::string help_unknown_is_operand_str
458 = gdb::option::build_help (_("\
459 Command used for testing options processing.\n\
460 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
462 Options:\n\
463 %OPTIONS%"),
464 def_group);
466 cmd = add_cmd ("require-delimiter", class_maintenance,
467 maintenance_test_options_require_delimiter_command,
468 help_require_delim_str.c_str (),
469 &maintenance_test_options_list);
470 set_cmd_completer_handle_brkchars
471 (cmd, maintenance_test_options_require_delimiter_command_completer);
473 cmd = add_cmd ("unknown-is-error", class_maintenance,
474 maintenance_test_options_unknown_is_error_command,
475 help_unknown_is_error_str.c_str (),
476 &maintenance_test_options_list);
477 set_cmd_completer_handle_brkchars
478 (cmd, maintenance_test_options_unknown_is_error_command_completer);
480 cmd = add_cmd ("unknown-is-operand", class_maintenance,
481 maintenance_test_options_unknown_is_operand_command,
482 help_unknown_is_operand_str.c_str (),
483 &maintenance_test_options_list);
484 set_cmd_completer_handle_brkchars
485 (cmd, maintenance_test_options_unknown_is_operand_command_completer);
487 add_cmd ("test-options-completion-result", class_maintenance,
488 maintenance_show_test_options_completion_result,
489 _("\
490 Show maintenance test-options completion result.\n\
491 Shows the results of completing\n\
492 \"maint test-options require-delimiter\",\n\
493 \"maint test-options unknown-is-error\", or\n\
494 \"maint test-options unknown-is-operand\"."),
495 &maintenance_show_cmdlist);