Automatic date update in version.in
[binutils-gdb.git] / gdb / maint-test-options.c
blob14808972467ed284d756be6fce2477c5fe71fb61
1 /* Maintenance commands for testing the options framework.
3 Copyright (C) 2019-2022 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 "defs.h"
21 #include "gdbcmd.h"
22 #include "cli/cli-option.h"
24 /* This file defines three "maintenance test-options" subcommands to
25 exercise TAB-completion and option processing:
27 (gdb) maint test-options require-delimiter
28 (gdb) maint test-options unknown-is-error
29 (gdb) maint test-options unknown-is-operand
31 And a fourth one to help with TAB-completion testing.
33 (gdb) maint show test-options-completion-result
35 Each of the test-options subcommands exercise
36 gdb::option::process_options with a different enum
37 process_options_mode value. Examples for commands they model:
39 - "print" and "compile print", are like "require-delimiter",
40 because they accept random expressions as argument.
42 - "backtrace" and "frame/thread apply" are like
43 "unknown-is-operand", because "-" is a valid command.
45 - "compile file" and "compile code" are like "unknown-is-error".
47 These commands allow exercising all aspects of option processing
48 without having to pick some existing command. That should be more
49 stable going forward than relying on an existing user command,
50 since if we picked say "print", that command or its options could
51 change in future, and then we'd be left with having to pick some
52 other command or option to exercise some non-command-specific
53 option processing detail. Also, actual user commands have side
54 effects that we're not interested in when we're focusing on unit
55 testing the options machinery. BTW, a maintenance command is used
56 as a sort of unit test driver instead of actual "maint selftest"
57 unit tests, since we need to go all the way via gdb including
58 readline, for proper testing of TAB completion.
60 These maintenance commands support options of all the different
61 available kinds of commands (boolean, enum, flag, string, uinteger):
63 (gdb) maint test-options require-delimiter -[TAB]
64 -bool -enum -flag -string -uinteger -xx1 -xx2
66 (gdb) maint test-options require-delimiter -bool o[TAB]
67 off on
68 (gdb) maint test-options require-delimiter -enum [TAB]
69 xxx yyy zzz
70 (gdb) maint test-options require-delimiter -uinteger [TAB]
71 NUMBER unlimited
73 '-xx1' and '-xx2' are flag options too. They exist in order to
74 test ambiguous option names, like '-xx'.
76 Invoking the commands makes them print out the options parsed:
78 (gdb) maint test-options unknown-is-error -flag -enum yyy cmdarg
79 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
81 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg
82 -flag 0 -xx1 0 -xx2 0 -bool 0 -enum xxx -uint 0 -zuint-unl 0 -- -flag -enum yyy cmdarg
83 (gdb) maint test-options require-delimiter -flag -enum yyy cmdarg --
84 Unrecognized option at: cmdarg --
85 (gdb) maint test-options require-delimiter -flag -enum yyy -- cmdarg
86 -flag 1 -xx1 0 -xx2 0 -bool 0 -enum yyy -uint 0 -zuint-unl 0 -- cmdarg
88 The "maint show test-options-completion-result" command exists in
89 order to do something similar for completion:
91 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy OPERAND[TAB]
92 (gdb) maint show test-options-completion-result
93 0 OPERAND
95 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
96 (gdb) maint show test-options-completion-result
99 (gdb) maint test-options require-dash -unknown[TAB]
100 (gdb) maint show test-options-completion-result
103 Here, "1" means the completion function processed the whole input
104 line, and that the command shouldn't do anything with the arguments,
105 since there are no operands. While "0" indicates that there are
106 operands after options. The text after "0" is the operands.
108 This level of detail is particularly important because getting the
109 completion function's entry point to return back to the caller the
110 right pointer into the operand is quite tricky in several
111 scenarios. */
113 /* Enum values for the "maintenance test-options" commands. */
114 const char test_options_enum_values_xxx[] = "xxx";
115 const char test_options_enum_values_yyy[] = "yyy";
116 const char test_options_enum_values_zzz[] = "zzz";
117 static const char *const test_options_enum_values_choices[] =
119 test_options_enum_values_xxx,
120 test_options_enum_values_yyy,
121 test_options_enum_values_zzz,
122 NULL
125 /* Option data for the "maintenance test-options" commands. */
127 struct test_options_opts
129 bool flag_opt = false;
130 bool xx1_opt = false;
131 bool xx2_opt = false;
132 bool boolean_opt = false;
133 const char *enum_opt = test_options_enum_values_xxx;
134 unsigned int uint_opt = 0;
135 int zuint_unl_opt = 0;
136 std::string string_opt;
138 test_options_opts () = default;
140 DISABLE_COPY_AND_ASSIGN (test_options_opts);
142 /* Dump the options to FILE. ARGS is the remainder unprocessed
143 arguments. */
144 void dump (ui_file *file, const char *args) const
146 gdb_printf (file,
147 _("-flag %d -xx1 %d -xx2 %d -bool %d "
148 "-enum %s -uint %s -zuint-unl %s -string '%s' -- %s\n"),
149 flag_opt,
150 xx1_opt,
151 xx2_opt,
152 boolean_opt,
153 enum_opt,
154 (uint_opt == UINT_MAX
155 ? "unlimited"
156 : pulongest (uint_opt)),
157 (zuint_unl_opt == -1
158 ? "unlimited"
159 : plongest (zuint_unl_opt)),
160 string_opt.c_str (),
161 args);
165 /* Option definitions for the "maintenance test-options" commands. */
167 static const gdb::option::option_def test_options_option_defs[] = {
169 /* A flag option. */
170 gdb::option::flag_option_def<test_options_opts> {
171 "flag",
172 [] (test_options_opts *opts) { return &opts->flag_opt; },
173 N_("A flag option."),
176 /* A couple flags with similar names, for "ambiguous option names"
177 testing. */
178 gdb::option::flag_option_def<test_options_opts> {
179 "xx1",
180 [] (test_options_opts *opts) { return &opts->xx1_opt; },
181 N_("A flag option."),
183 gdb::option::flag_option_def<test_options_opts> {
184 "xx2",
185 [] (test_options_opts *opts) { return &opts->xx2_opt; },
186 N_("A flag option."),
189 /* A boolean option. */
190 gdb::option::boolean_option_def<test_options_opts> {
191 "bool",
192 [] (test_options_opts *opts) { return &opts->boolean_opt; },
193 nullptr, /* show_cmd_cb */
194 N_("A boolean option."),
197 /* An enum option. */
198 gdb::option::enum_option_def<test_options_opts> {
199 "enum",
200 test_options_enum_values_choices,
201 [] (test_options_opts *opts) { return &opts->enum_opt; },
202 nullptr, /* show_cmd_cb */
203 N_("An enum option."),
206 /* A uinteger option. */
207 gdb::option::uinteger_option_def<test_options_opts> {
208 "uinteger",
209 [] (test_options_opts *opts) { return &opts->uint_opt; },
210 nullptr, /* show_cmd_cb */
211 N_("A uinteger option."),
212 nullptr, /* show_doc */
213 N_("A help doc that spawns\nmultiple lines."),
216 /* A zuinteger_unlimited option. */
217 gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
218 "zuinteger-unlimited",
219 [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
220 nullptr, /* show_cmd_cb */
221 N_("A zuinteger-unlimited option."),
222 nullptr, /* show_doc */
223 nullptr, /* help_doc */
226 /* A string option. */
227 gdb::option::string_option_def<test_options_opts> {
228 "string",
229 [] (test_options_opts *opts) { return &opts->string_opt; },
230 nullptr, /* show_cmd_cb */
231 N_("A string option."),
235 /* Create an option_def_group for the test_options_opts options, with
236 OPTS as context. */
238 static inline gdb::option::option_def_group
239 make_test_options_options_def_group (test_options_opts *opts)
241 return {{test_options_option_defs}, opts};
244 /* Implementation of the "maintenance test-options
245 require-delimiter/unknown-is-error/unknown-is-operand" commands.
246 Each of the commands maps to a different enum process_options_mode
247 enumerator. The test strategy is simply processing the options in
248 a number of scenarios, and printing back the parsed result. */
250 static void
251 maintenance_test_options_command_mode (const char *args,
252 gdb::option::process_options_mode mode)
254 test_options_opts opts;
256 gdb::option::process_options (&args, mode,
257 make_test_options_options_def_group (&opts));
259 if (args == nullptr)
260 args = "";
261 else
262 args = skip_spaces (args);
264 opts.dump (gdb_stdout, args);
267 /* Variable used by the "maintenance show
268 test-options-completion-result" command. This variable is stored
269 by the completer of the "maint test-options" subcommands.
271 If the completer returned false, this includes the text at the word
272 point after gdb::option::complete_options returns. If true, then
273 this includes a dump of the processed options. */
274 static std::string maintenance_test_options_command_completion_text;
276 /* The "maintenance show test-options-completion-result" command. */
278 static void
279 maintenance_show_test_options_completion_result (const char *args,
280 int from_tty)
282 gdb_puts (maintenance_test_options_command_completion_text.c_str ());
285 /* Save the completion result in the global variables read by the
286 "maintenance test-options require-delimiter" command. */
288 static void
289 save_completion_result (const test_options_opts &opts, bool res,
290 const char *text)
292 if (res)
294 string_file stream;
296 stream.puts ("1 ");
297 opts.dump (&stream, text);
298 maintenance_test_options_command_completion_text = stream.release ();
300 else
302 maintenance_test_options_command_completion_text
303 = string_printf ("0 %s\n", text);
307 /* Implementation of completer for the "maintenance test-options
308 require-delimiter/unknown-is-error/unknown-is-operand" commands.
309 Each of the commands maps to a different enum process_options_mode
310 enumerator. */
312 static void
313 maintenance_test_options_completer_mode (completion_tracker &tracker,
314 const char *text,
315 gdb::option::process_options_mode mode)
317 test_options_opts opts;
321 bool res = (gdb::option::complete_options
322 (tracker, &text, mode,
323 make_test_options_options_def_group (&opts)));
325 save_completion_result (opts, res, text);
327 catch (const gdb_exception_error &ex)
329 save_completion_result (opts, true, text);
330 throw;
334 /* Implementation of the "maintenance test-options require-delimiter"
335 command. */
337 static void
338 maintenance_test_options_require_delimiter_command (const char *args,
339 int from_tty)
341 maintenance_test_options_command_mode
342 (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
345 /* Implementation of the "maintenance test-options
346 unknown-is-error" command. */
348 static void
349 maintenance_test_options_unknown_is_error_command (const char *args,
350 int from_tty)
352 maintenance_test_options_command_mode
353 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
356 /* Implementation of the "maintenance test-options
357 unknown-is-operand" command. */
359 static void
360 maintenance_test_options_unknown_is_operand_command (const char *args,
361 int from_tty)
363 maintenance_test_options_command_mode
364 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
367 /* Completer for the "maintenance test-options require-delimiter"
368 command. */
370 static void
371 maintenance_test_options_require_delimiter_command_completer
372 (cmd_list_element *ignore, completion_tracker &tracker,
373 const char *text, const char *word)
375 maintenance_test_options_completer_mode
376 (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
379 /* Completer for the "maintenance test-options unknown-is-error"
380 command. */
382 static void
383 maintenance_test_options_unknown_is_error_command_completer
384 (cmd_list_element *ignore, completion_tracker &tracker,
385 const char *text, const char *word)
387 maintenance_test_options_completer_mode
388 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
391 /* Completer for the "maintenance test-options unknown-is-operand"
392 command. */
394 static void
395 maintenance_test_options_unknown_is_operand_command_completer
396 (cmd_list_element *ignore, completion_tracker &tracker,
397 const char *text, const char *word)
399 maintenance_test_options_completer_mode
400 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
403 /* Command list for maint test-options. */
404 static cmd_list_element *maintenance_test_options_list;
407 void _initialize_maint_test_options ();
408 void
409 _initialize_maint_test_options ()
411 cmd_list_element *cmd;
413 add_basic_prefix_cmd ("test-options", no_class,
414 _("\
415 Generic command for testing the options infrastructure."),
416 &maintenance_test_options_list,
417 0, &maintenancelist);
419 const auto def_group = make_test_options_options_def_group (nullptr);
421 static const std::string help_require_delim_str
422 = gdb::option::build_help (_("\
423 Command used for testing options processing.\n\
424 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
426 Options:\n\
427 %OPTIONS%\n\
429 If you specify any command option, you must use a double dash (\"--\")\n\
430 to mark the end of option processing."),
431 def_group);
433 static const std::string help_unknown_is_error_str
434 = gdb::option::build_help (_("\
435 Command used for testing options processing.\n\
436 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
438 Options:\n\
439 %OPTIONS%"),
440 def_group);
442 static const std::string help_unknown_is_operand_str
443 = gdb::option::build_help (_("\
444 Command used for testing options processing.\n\
445 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
447 Options:\n\
448 %OPTIONS%"),
449 def_group);
451 cmd = add_cmd ("require-delimiter", class_maintenance,
452 maintenance_test_options_require_delimiter_command,
453 help_require_delim_str.c_str (),
454 &maintenance_test_options_list);
455 set_cmd_completer_handle_brkchars
456 (cmd, maintenance_test_options_require_delimiter_command_completer);
458 cmd = add_cmd ("unknown-is-error", class_maintenance,
459 maintenance_test_options_unknown_is_error_command,
460 help_unknown_is_error_str.c_str (),
461 &maintenance_test_options_list);
462 set_cmd_completer_handle_brkchars
463 (cmd, maintenance_test_options_unknown_is_error_command_completer);
465 cmd = add_cmd ("unknown-is-operand", class_maintenance,
466 maintenance_test_options_unknown_is_operand_command,
467 help_unknown_is_operand_str.c_str (),
468 &maintenance_test_options_list);
469 set_cmd_completer_handle_brkchars
470 (cmd, maintenance_test_options_unknown_is_operand_command_completer);
472 add_cmd ("test-options-completion-result", class_maintenance,
473 maintenance_show_test_options_completion_result,
474 _("\
475 Show maintenance test-options completion result.\n\
476 Shows the results of completing\n\
477 \"maint test-options require-delimiter\",\n\
478 \"maint test-options unknown-is-error\", or\n\
479 \"maint test-options unknown-is-operand\"."),
480 &maintenance_show_cmdlist);