]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/maint-test-options.c
sim: bfin: initial bf60x support
[thirdparty/binutils-gdb.git] / gdb / maint-test-options.c
1 /* Maintenance commands for testing the options framework.
2
3 Copyright (C) 2019-2023 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 -pinteger-unlimited -xx1
65 -enum -string -xx2
66 -flag -uinteger-unlimited
67
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
74
75 '-xx1' and '-xx2' are flag options too. They exist in order to
76 test ambiguous option names, like '-xx'.
77
78 Invoking the commands makes them print out the options parsed:
79
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 '' -- cmdarg
82
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 '' -- -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 '' -- cmdarg
89
90 The "maint show test-options-completion-result" command exists in
91 order to do something similar for completion:
92
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
96
97 (gdb) maint test-options unknown-is-error -flag -b 0 -enum yyy[TAB]
98 (gdb) maint show test-options-completion-result
99 1
100
101 (gdb) maint test-options require-dash -unknown[TAB]
102 (gdb) maint show test-options-completion-result
103 1
104
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.
109
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. */
114
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[] =
120 {
121 test_options_enum_values_xxx,
122 test_options_enum_values_yyy,
123 test_options_enum_values_zzz,
124 NULL
125 };
126
127 /* Option data for the "maintenance test-options" commands. */
128
129 struct test_options_opts
130 {
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
140 test_options_opts () = default;
141
142 DISABLE_COPY_AND_ASSIGN (test_options_opts);
143
144 /* Dump the options to FILE. ARGS is the remainder unprocessed
145 arguments. */
146 void dump (ui_file *file, const char *args) const
147 {
148 gdb_printf (file,
149 _("-flag %d -xx1 %d -xx2 %d -bool %d "
150 "-enum %s -uint-unl %s -pint-unl %s -string '%s' -- %s\n"),
151 flag_opt,
152 xx1_opt,
153 xx2_opt,
154 boolean_opt,
155 enum_opt,
156 (uint_unl_opt == UINT_MAX
157 ? "unlimited"
158 : pulongest (uint_unl_opt)),
159 (pint_unl_opt == -1
160 ? "unlimited"
161 : plongest (pint_unl_opt)),
162 string_opt.c_str (),
163 args);
164 }
165 };
166
167 /* Option definitions for the "maintenance test-options" commands. */
168
169 static const gdb::option::option_def test_options_option_defs[] = {
170
171 /* A flag option. */
172 gdb::option::flag_option_def<test_options_opts> {
173 "flag",
174 [] (test_options_opts *opts) { return &opts->flag_opt; },
175 N_("A flag option."),
176 },
177
178 /* A couple flags with similar names, for "ambiguous option names"
179 testing. */
180 gdb::option::flag_option_def<test_options_opts> {
181 "xx1",
182 [] (test_options_opts *opts) { return &opts->xx1_opt; },
183 N_("A flag option."),
184 },
185 gdb::option::flag_option_def<test_options_opts> {
186 "xx2",
187 [] (test_options_opts *opts) { return &opts->xx2_opt; },
188 N_("A flag option."),
189 },
190
191 /* A boolean option. */
192 gdb::option::boolean_option_def<test_options_opts> {
193 "bool",
194 [] (test_options_opts *opts) { return &opts->boolean_opt; },
195 nullptr, /* show_cmd_cb */
196 N_("A boolean option."),
197 },
198
199 /* An enum option. */
200 gdb::option::enum_option_def<test_options_opts> {
201 "enum",
202 test_options_enum_values_choices,
203 [] (test_options_opts *opts) { return &opts->enum_opt; },
204 nullptr, /* show_cmd_cb */
205 N_("An enum option."),
206 },
207
208 /* A uinteger + "unlimited" option. */
209 gdb::option::uinteger_option_def<test_options_opts> {
210 "uinteger-unlimited",
211 [] (test_options_opts *opts) { return &opts->uint_unl_opt; },
212 uinteger_unlimited_literals,
213 nullptr, /* show_cmd_cb */
214 N_("A uinteger option."),
215 nullptr, /* show_doc */
216 N_("A help doc that spawns\nmultiple lines."),
217 },
218
219 /* A pinteger + "unlimited" option. */
220 gdb::option::pinteger_option_def<test_options_opts> {
221 "pinteger-unlimited",
222 [] (test_options_opts *opts) { return &opts->pint_unl_opt; },
223 pinteger_unlimited_literals,
224 nullptr, /* show_cmd_cb */
225 N_("A pinteger-unlimited option."),
226 nullptr, /* show_doc */
227 nullptr, /* help_doc */
228 },
229
230 /* A string option. */
231 gdb::option::string_option_def<test_options_opts> {
232 "string",
233 [] (test_options_opts *opts) { return &opts->string_opt; },
234 nullptr, /* show_cmd_cb */
235 N_("A string option."),
236 },
237 };
238
239 /* Create an option_def_group for the test_options_opts options, with
240 OPTS as context. */
241
242 static inline gdb::option::option_def_group
243 make_test_options_options_def_group (test_options_opts *opts)
244 {
245 return {{test_options_option_defs}, opts};
246 }
247
248 /* Implementation of the "maintenance test-options
249 require-delimiter/unknown-is-error/unknown-is-operand" commands.
250 Each of the commands maps to a different enum process_options_mode
251 enumerator. The test strategy is simply processing the options in
252 a number of scenarios, and printing back the parsed result. */
253
254 static void
255 maintenance_test_options_command_mode (const char *args,
256 gdb::option::process_options_mode mode)
257 {
258 test_options_opts opts;
259
260 gdb::option::process_options (&args, mode,
261 make_test_options_options_def_group (&opts));
262
263 if (args == nullptr)
264 args = "";
265 else
266 args = skip_spaces (args);
267
268 opts.dump (gdb_stdout, args);
269 }
270
271 /* Variable used by the "maintenance show
272 test-options-completion-result" command. This variable is stored
273 by the completer of the "maint test-options" subcommands.
274
275 If the completer returned false, this includes the text at the word
276 point after gdb::option::complete_options returns. If true, then
277 this includes a dump of the processed options. */
278 static std::string maintenance_test_options_command_completion_text;
279
280 /* The "maintenance show test-options-completion-result" command. */
281
282 static void
283 maintenance_show_test_options_completion_result (const char *args,
284 int from_tty)
285 {
286 gdb_puts (maintenance_test_options_command_completion_text.c_str ());
287 }
288
289 /* Save the completion result in the global variables read by the
290 "maintenance test-options require-delimiter" command. */
291
292 static void
293 save_completion_result (const test_options_opts &opts, bool res,
294 const char *text)
295 {
296 if (res)
297 {
298 string_file stream;
299
300 stream.puts ("1 ");
301 opts.dump (&stream, text);
302 maintenance_test_options_command_completion_text = stream.release ();
303 }
304 else
305 {
306 maintenance_test_options_command_completion_text
307 = string_printf ("0 %s\n", text);
308 }
309 }
310
311 /* Implementation of completer for the "maintenance test-options
312 require-delimiter/unknown-is-error/unknown-is-operand" commands.
313 Each of the commands maps to a different enum process_options_mode
314 enumerator. */
315
316 static void
317 maintenance_test_options_completer_mode (completion_tracker &tracker,
318 const char *text,
319 gdb::option::process_options_mode mode)
320 {
321 test_options_opts opts;
322
323 try
324 {
325 bool res = (gdb::option::complete_options
326 (tracker, &text, mode,
327 make_test_options_options_def_group (&opts)));
328
329 save_completion_result (opts, res, text);
330 }
331 catch (const gdb_exception_error &ex)
332 {
333 save_completion_result (opts, true, text);
334 throw;
335 }
336 }
337
338 /* Implementation of the "maintenance test-options require-delimiter"
339 command. */
340
341 static void
342 maintenance_test_options_require_delimiter_command (const char *args,
343 int from_tty)
344 {
345 maintenance_test_options_command_mode
346 (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
347 }
348
349 /* Implementation of the "maintenance test-options
350 unknown-is-error" command. */
351
352 static void
353 maintenance_test_options_unknown_is_error_command (const char *args,
354 int from_tty)
355 {
356 maintenance_test_options_command_mode
357 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
358 }
359
360 /* Implementation of the "maintenance test-options
361 unknown-is-operand" command. */
362
363 static void
364 maintenance_test_options_unknown_is_operand_command (const char *args,
365 int from_tty)
366 {
367 maintenance_test_options_command_mode
368 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
369 }
370
371 /* Completer for the "maintenance test-options require-delimiter"
372 command. */
373
374 static void
375 maintenance_test_options_require_delimiter_command_completer
376 (cmd_list_element *ignore, completion_tracker &tracker,
377 const char *text, const char *word)
378 {
379 maintenance_test_options_completer_mode
380 (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
381 }
382
383 /* Completer for the "maintenance test-options unknown-is-error"
384 command. */
385
386 static void
387 maintenance_test_options_unknown_is_error_command_completer
388 (cmd_list_element *ignore, completion_tracker &tracker,
389 const char *text, const char *word)
390 {
391 maintenance_test_options_completer_mode
392 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
393 }
394
395 /* Completer for the "maintenance test-options unknown-is-operand"
396 command. */
397
398 static void
399 maintenance_test_options_unknown_is_operand_command_completer
400 (cmd_list_element *ignore, completion_tracker &tracker,
401 const char *text, const char *word)
402 {
403 maintenance_test_options_completer_mode
404 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
405 }
406
407 /* Command list for maint test-options. */
408 static cmd_list_element *maintenance_test_options_list;
409
410 \f
411 void _initialize_maint_test_options ();
412 void
413 _initialize_maint_test_options ()
414 {
415 cmd_list_element *cmd;
416
417 add_basic_prefix_cmd ("test-options", no_class,
418 _("\
419 Generic command for testing the options infrastructure."),
420 &maintenance_test_options_list,
421 0, &maintenancelist);
422
423 const auto def_group = make_test_options_options_def_group (nullptr);
424
425 static const std::string help_require_delim_str
426 = gdb::option::build_help (_("\
427 Command used for testing options processing.\n\
428 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
429 \n\
430 Options:\n\
431 %OPTIONS%\n\
432 \n\
433 If you specify any command option, you must use a double dash (\"--\")\n\
434 to mark the end of option processing."),
435 def_group);
436
437 static const std::string help_unknown_is_error_str
438 = gdb::option::build_help (_("\
439 Command used for testing options processing.\n\
440 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
441 \n\
442 Options:\n\
443 %OPTIONS%"),
444 def_group);
445
446 static const std::string help_unknown_is_operand_str
447 = gdb::option::build_help (_("\
448 Command used for testing options processing.\n\
449 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
450 \n\
451 Options:\n\
452 %OPTIONS%"),
453 def_group);
454
455 cmd = add_cmd ("require-delimiter", class_maintenance,
456 maintenance_test_options_require_delimiter_command,
457 help_require_delim_str.c_str (),
458 &maintenance_test_options_list);
459 set_cmd_completer_handle_brkchars
460 (cmd, maintenance_test_options_require_delimiter_command_completer);
461
462 cmd = add_cmd ("unknown-is-error", class_maintenance,
463 maintenance_test_options_unknown_is_error_command,
464 help_unknown_is_error_str.c_str (),
465 &maintenance_test_options_list);
466 set_cmd_completer_handle_brkchars
467 (cmd, maintenance_test_options_unknown_is_error_command_completer);
468
469 cmd = add_cmd ("unknown-is-operand", class_maintenance,
470 maintenance_test_options_unknown_is_operand_command,
471 help_unknown_is_operand_str.c_str (),
472 &maintenance_test_options_list);
473 set_cmd_completer_handle_brkchars
474 (cmd, maintenance_test_options_unknown_is_operand_command_completer);
475
476 add_cmd ("test-options-completion-result", class_maintenance,
477 maintenance_show_test_options_completion_result,
478 _("\
479 Show maintenance test-options completion result.\n\
480 Shows the results of completing\n\
481 \"maint test-options require-delimiter\",\n\
482 \"maint test-options unknown-is-error\", or\n\
483 \"maint test-options unknown-is-operand\"."),
484 &maintenance_show_cmdlist);
485 }