gdb: make string-like set show commands use std::string variable
[binutils-gdb.git] / gdb / maint-test-options.c
1 /* Maintenance commands for testing the options framework.
2
3 Copyright (C) 2019-2021 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 fprintf_unfiltered (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 puts_filtered (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
299 = std::move (stream.string ());
300 }
301 else
302 {
303 maintenance_test_options_command_completion_text
304 = string_printf ("0 %s\n", text);
305 }
306 }
307
308 /* Implementation of completer for the "maintenance test-options
309 require-delimiter/unknown-is-error/unknown-is-operand" commands.
310 Each of the commands maps to a different enum process_options_mode
311 enumerator. */
312
313 static void
314 maintenance_test_options_completer_mode (completion_tracker &tracker,
315 const char *text,
316 gdb::option::process_options_mode mode)
317 {
318 test_options_opts opts;
319
320 try
321 {
322 bool res = (gdb::option::complete_options
323 (tracker, &text, mode,
324 make_test_options_options_def_group (&opts)));
325
326 save_completion_result (opts, res, text);
327 }
328 catch (const gdb_exception_error &ex)
329 {
330 save_completion_result (opts, true, text);
331 throw;
332 }
333 }
334
335 /* Implementation of the "maintenance test-options require-delimiter"
336 command. */
337
338 static void
339 maintenance_test_options_require_delimiter_command (const char *args,
340 int from_tty)
341 {
342 maintenance_test_options_command_mode
343 (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
344 }
345
346 /* Implementation of the "maintenance test-options
347 unknown-is-error" command. */
348
349 static void
350 maintenance_test_options_unknown_is_error_command (const char *args,
351 int from_tty)
352 {
353 maintenance_test_options_command_mode
354 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
355 }
356
357 /* Implementation of the "maintenance test-options
358 unknown-is-operand" command. */
359
360 static void
361 maintenance_test_options_unknown_is_operand_command (const char *args,
362 int from_tty)
363 {
364 maintenance_test_options_command_mode
365 (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
366 }
367
368 /* Completer for the "maintenance test-options require-delimiter"
369 command. */
370
371 static void
372 maintenance_test_options_require_delimiter_command_completer
373 (cmd_list_element *ignore, completion_tracker &tracker,
374 const char *text, const char *word)
375 {
376 maintenance_test_options_completer_mode
377 (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
378 }
379
380 /* Completer for the "maintenance test-options unknown-is-error"
381 command. */
382
383 static void
384 maintenance_test_options_unknown_is_error_command_completer
385 (cmd_list_element *ignore, completion_tracker &tracker,
386 const char *text, const char *word)
387 {
388 maintenance_test_options_completer_mode
389 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
390 }
391
392 /* Completer for the "maintenance test-options unknown-is-operand"
393 command. */
394
395 static void
396 maintenance_test_options_unknown_is_operand_command_completer
397 (cmd_list_element *ignore, completion_tracker &tracker,
398 const char *text, const char *word)
399 {
400 maintenance_test_options_completer_mode
401 (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
402 }
403
404 /* Command list for maint test-options. */
405 static cmd_list_element *maintenance_test_options_list;
406
407 \f
408 void _initialize_maint_test_options ();
409 void
410 _initialize_maint_test_options ()
411 {
412 cmd_list_element *cmd;
413
414 add_basic_prefix_cmd ("test-options", no_class,
415 _("\
416 Generic command for testing the options infrastructure."),
417 &maintenance_test_options_list,
418 0, &maintenancelist);
419
420 const auto def_group = make_test_options_options_def_group (nullptr);
421
422 static const std::string help_require_delim_str
423 = gdb::option::build_help (_("\
424 Command used for testing options processing.\n\
425 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
426 \n\
427 Options:\n\
428 %OPTIONS%\n\
429 \n\
430 If you specify any command option, you must use a double dash (\"--\")\n\
431 to mark the end of option processing."),
432 def_group);
433
434 static const std::string help_unknown_is_error_str
435 = gdb::option::build_help (_("\
436 Command used for testing options processing.\n\
437 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
438 \n\
439 Options:\n\
440 %OPTIONS%"),
441 def_group);
442
443 static const std::string help_unknown_is_operand_str
444 = gdb::option::build_help (_("\
445 Command used for testing options processing.\n\
446 Usage: maint test-options unknown-is-operand [OPTION]... [OPERAND]...\n\
447 \n\
448 Options:\n\
449 %OPTIONS%"),
450 def_group);
451
452 cmd = add_cmd ("require-delimiter", class_maintenance,
453 maintenance_test_options_require_delimiter_command,
454 help_require_delim_str.c_str (),
455 &maintenance_test_options_list);
456 set_cmd_completer_handle_brkchars
457 (cmd, maintenance_test_options_require_delimiter_command_completer);
458
459 cmd = add_cmd ("unknown-is-error", class_maintenance,
460 maintenance_test_options_unknown_is_error_command,
461 help_unknown_is_error_str.c_str (),
462 &maintenance_test_options_list);
463 set_cmd_completer_handle_brkchars
464 (cmd, maintenance_test_options_unknown_is_error_command_completer);
465
466 cmd = add_cmd ("unknown-is-operand", class_maintenance,
467 maintenance_test_options_unknown_is_operand_command,
468 help_unknown_is_operand_str.c_str (),
469 &maintenance_test_options_list);
470 set_cmd_completer_handle_brkchars
471 (cmd, maintenance_test_options_unknown_is_operand_command_completer);
472
473 add_cmd ("test-options-completion-result", class_maintenance,
474 maintenance_show_test_options_completion_result,
475 _("\
476 Show maintenance test-options completion result.\n\
477 Shows the results of completing\n\
478 \"maint test-options require-delimiter\",\n\
479 \"maint test-options unknown-is-error\", or\n\
480 \"maint test-options unknown-is-operand\"."),
481 &maintenance_show_cmdlist);
482 }