14808972467ed284d756be6fce2477c5fe71fb61
[binutils-gdb.git] / gdb / maint-test-options.c
1 /* Maintenance commands for testing the options framework.
2
3 Copyright (C) 2019-2022 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20 #include "defs.h"
21 #include "gdbcmd.h"
22 #include "cli/cli-option.h"
23
24 /* This file defines three "maintenance test-options" subcommands to
25 exercise TAB-completion and option processing:
26
27 (gdb) maint test-options require-delimiter
28 (gdb) maint test-options unknown-is-error
29 (gdb) maint test-options unknown-is-operand
30
31 And a fourth one to help with TAB-completion testing.
32
33 (gdb) maint show test-options-completion-result
34
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:
38
39 - "print" and "compile print", are like "require-delimiter",
40 because they accept random expressions as argument.
41
42 - "backtrace" and "frame/thread apply" are like
43 "unknown-is-operand", because "-" is a valid command.
44
45 - "compile file" and "compile code" are like "unknown-is-error".
46
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.
59
60 These maintenance commands support options of all the different
61 available kinds of commands (boolean, enum, flag, string, uinteger):
62
63 (gdb) maint test-options require-delimiter -[TAB]
64 -bool -enum -flag -string -uinteger -xx1 -xx2
65
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
72
73 '-xx1' and '-xx2' are flag options too. They exist in order to
74 test ambiguous option names, like '-xx'.
75
76 Invoking the commands makes them print out the options parsed:
77
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
80
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
87
88 The "maint show test-options-completion-result" command exists in
89 order to do something similar for completion:
90
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
94
95 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
96 (gdb) maint show test-options-completion-result
97 1
98
99 (gdb) maint test-options require-dash -unknown[TAB]
100 (gdb) maint show test-options-completion-result
101 1
102
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.
107
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. */
112
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[] =
118 {
119 test_options_enum_values_xxx,
120 test_options_enum_values_yyy,
121 test_options_enum_values_zzz,
122 NULL
123 };
124
125 /* Option data for the "maintenance test-options" commands. */
126
127 struct test_options_opts
128 {
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;
137
138 test_options_opts () = default;
139
140 DISABLE_COPY_AND_ASSIGN (test_options_opts);
141
142 /* Dump the options to FILE. ARGS is the remainder unprocessed
143 arguments. */
144 void dump (ui_file *file, const char *args) const
145 {
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);
162 }
163 };
164
165 /* Option definitions for the "maintenance test-options" commands. */
166
167 static const gdb::option::option_def test_options_option_defs[] = {
168
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."),
174 },
175
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."),
182 },
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."),
187 },
188
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."),
195 },
196
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."),
204 },
205
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."),
214 },
215
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 */
224 },
225
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."),
232 },
233 };
234
235 /* Create an option_def_group for the test_options_opts options, with
236 OPTS as context. */
237
238 static inline gdb::option::option_def_group
239 make_test_options_options_def_group (test_options_opts *opts)
240 {
241 return {{test_options_option_defs}, opts};
242 }
243
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. */
249
250 static void
251 maintenance_test_options_command_mode (const char *args,
252 gdb::option::process_options_mode mode)
253 {
254 test_options_opts opts;
255
256 gdb::option::process_options (&args, mode,
257 make_test_options_options_def_group (&opts));
258
259 if (args == nullptr)
260 args = "";
261 else
262 args = skip_spaces (args);
263
264 opts.dump (gdb_stdout, args);
265 }
266
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.
270
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;
275
276 /* The "maintenance show test-options-completion-result" command. */
277
278 static void
279 maintenance_show_test_options_completion_result (const char *args,
280 int from_tty)
281 {
282 gdb_puts (maintenance_test_options_command_completion_text.c_str ());
283 }
284
285 /* Save the completion result in the global variables read by the
286 "maintenance test-options require-delimiter" command. */
287
288 static void
289 save_completion_result (const test_options_opts &opts, bool res,
290 const char *text)
291 {
292 if (res)
293 {
294 string_file stream;
295
296 stream.puts ("1 ");
297 opts.dump (&stream, text);
298 maintenance_test_options_command_completion_text = stream.release ();
299 }
300 else
301 {
302 maintenance_test_options_command_completion_text
303 = string_printf ("0 %s\n", text);
304 }
305 }
306
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. */
311
312 static void
313 maintenance_test_options_completer_mode (completion_tracker &tracker,
314 const char *text,
315 gdb::option::process_options_mode mode)
316 {
317 test_options_opts opts;
318
319 try
320 {
321 bool res = (gdb::option::complete_options
322 (tracker, &text, mode,
323 make_test_options_options_def_group (&opts)));
324
325 save_completion_result (opts, res, text);
326 }
327 catch (const gdb_exception_error &ex)
328 {
329 save_completion_result (opts, true, text);
330 throw;
331 }
332 }
333
334 /* Implementation of the "maintenance test-options require-delimiter"
335 command. */
336
337 static void
338 maintenance_test_options_require_delimiter_command (const char *args,
339 int from_tty)
340 {
341 maintenance_test_options_command_mode
342 (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
343 }
344
345 /* Implementation of the "maintenance test-options
346 unknown-is-error" command. */
347
348 static void
349 maintenance_test_options_unknown_is_error_command (const char *args,
350 int from_tty)
351 {
352 maintenance_test_options_command_mode
353 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
354 }
355
356 /* Implementation of the "maintenance test-options
357 unknown-is-operand" command. */
358
359 static void
360 maintenance_test_options_unknown_is_operand_command (const char *args,
361 int from_tty)
362 {
363 maintenance_test_options_command_mode
364 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
365 }
366
367 /* Completer for the "maintenance test-options require-delimiter"
368 command. */
369
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)
374 {
375 maintenance_test_options_completer_mode
376 (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
377 }
378
379 /* Completer for the "maintenance test-options unknown-is-error"
380 command. */
381
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)
386 {
387 maintenance_test_options_completer_mode
388 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
389 }
390
391 /* Completer for the "maintenance test-options unknown-is-operand"
392 command. */
393
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)
398 {
399 maintenance_test_options_completer_mode
400 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
401 }
402
403 /* Command list for maint test-options. */
404 static cmd_list_element *maintenance_test_options_list;
405
406 \f
407 void _initialize_maint_test_options ();
408 void
409 _initialize_maint_test_options ()
410 {
411 cmd_list_element *cmd;
412
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);
418
419 const auto def_group = make_test_options_options_def_group (nullptr);
420
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\
425 \n\
426 Options:\n\
427 %OPTIONS%\n\
428 \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);
432
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\
437 \n\
438 Options:\n\
439 %OPTIONS%"),
440 def_group);
441
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\
446 \n\
447 Options:\n\
448 %OPTIONS%"),
449 def_group);
450
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);
457
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);
464
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);
471
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);
481 }