Make gdb::option::complete_options save processed arguments too
[external/binutils.git] / gdb / maint-test-options.c
1 /* Maintenance commands for testing the options framework.
2
3    Copyright (C) 2019 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, uinteger):
62
63     (gdb) maint test-options require-delimiter -[TAB]
64     -bool      -enum      -flag      -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   int flag_opt = 0;
130   int xx1_opt = 0;
131   int xx2_opt = 0;
132   int boolean_opt = 0;
133   const char *enum_opt = test_options_enum_values_xxx;
134   unsigned int uint_opt = 0;
135   int zuint_unl_opt = 0;
136
137   /* Dump the options to FILE.  ARGS is the remainder unprocessed
138      arguments.  */
139   void dump (ui_file *file, const char *args) const
140   {
141     fprintf_unfiltered (file,
142                         _("-flag %d -xx1 %d -xx2 %d -bool %d "
143                           "-enum %s -uint %s -zuint-unl %s -- %s\n"),
144                         flag_opt,
145                         xx1_opt,
146                         xx2_opt,
147                         boolean_opt,
148                         enum_opt,
149                         (uint_opt == UINT_MAX
150                          ? "unlimited"
151                          : pulongest (uint_opt)),
152                         (zuint_unl_opt == -1
153                          ? "unlimited"
154                          : plongest (zuint_unl_opt)),
155                         args);
156   }
157 };
158
159 /* Option definitions for the "maintenance test-options" commands.  */
160
161 static const gdb::option::option_def test_options_option_defs[] = {
162
163   /* A flag option.  */
164   gdb::option::flag_option_def<test_options_opts> {
165     "flag",
166     [] (test_options_opts *opts) { return &opts->flag_opt; },
167     N_("A flag option."),
168   },
169
170   /* A couple flags with similar names, for "ambiguous option names"
171      testing.  */
172   gdb::option::flag_option_def<test_options_opts> {
173     "xx1",
174     [] (test_options_opts *opts) { return &opts->xx1_opt; },
175     N_("A flag option."),
176   },
177   gdb::option::flag_option_def<test_options_opts> {
178     "xx2",
179     [] (test_options_opts *opts) { return &opts->xx2_opt; },
180     N_("A flag option."),
181   },
182
183   /* A boolean option.  */
184   gdb::option::boolean_option_def<test_options_opts> {
185     "bool",
186     [] (test_options_opts *opts) { return &opts->boolean_opt; },
187     nullptr, /* show_cmd_cb */
188     N_("A boolean option."),
189   },
190
191   /* An enum option.  */
192   gdb::option::enum_option_def<test_options_opts> {
193     "enum",
194     test_options_enum_values_choices,
195     [] (test_options_opts *opts) { return &opts->enum_opt; },
196     nullptr, /* show_cmd_cb */
197     N_("An enum option."),
198   },
199
200   /* A uinteger option.  */
201   gdb::option::uinteger_option_def<test_options_opts> {
202     "uinteger",
203     [] (test_options_opts *opts) { return &opts->uint_opt; },
204     nullptr, /* show_cmd_cb */
205     N_("A uinteger option."),
206     nullptr, /* show_doc */
207     N_("A help doc that spawns\nmultiple lines."),
208   },
209
210   /* A zuinteger_unlimited option.  */
211   gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
212     "zuinteger-unlimited",
213     [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
214     nullptr, /* show_cmd_cb */
215     N_("A zuinteger-unlimited option."),
216     nullptr, /* show_doc */
217     nullptr, /* help_doc */
218   },
219 };
220
221 /* Create an option_def_group for the test_options_opts options, with
222    OPTS as context.  */
223
224 static inline gdb::option::option_def_group
225 make_test_options_options_def_group (test_options_opts *opts)
226 {
227   return {{test_options_option_defs}, opts};
228 }
229
230 /* Implementation of the "maintenance test-options
231    require-delimiter/unknown-is-error/unknown-is-operand" commands.
232    Each of the commands maps to a different enum process_options_mode
233    enumerator.  The test strategy is simply processing the options in
234    a number of scenarios, and printing back the parsed result.  */
235
236 static void
237 maintenance_test_options_command_mode (const char *args,
238                                        gdb::option::process_options_mode mode)
239 {
240   test_options_opts opts;
241
242   gdb::option::process_options (&args, mode,
243                                 make_test_options_options_def_group (&opts));
244
245   if (args == nullptr)
246     args = "";
247   else
248     args = skip_spaces (args);
249
250   opts.dump (gdb_stdout, args);
251 }
252
253 /* Variable used by the "maintenance show
254    test-options-completion-result" command.  This variable is stored
255    by the completer of the "maint test-options" subcommands.
256
257    If the completer returned false, this includes the text at the word
258    point after gdb::option::complete_options returns.  If true, then
259    this includes a dump of the processed options.  */
260 static std::string maintenance_test_options_command_completion_text;
261
262 /* The "maintenance show test-options-completion-result" command.  */
263
264 static void
265 maintenance_show_test_options_completion_result (const char *args,
266                                                  int from_tty)
267 {
268   puts_filtered (maintenance_test_options_command_completion_text.c_str ());
269 }
270
271 /* Save the completion result in the global variables read by the
272    "maintenance test-options require-delimiter" command.  */
273
274 static void
275 save_completion_result (const test_options_opts &opts, bool res,
276                         const char *text)
277 {
278   if (res)
279     {
280       string_file stream;
281
282       stream.puts ("1 ");
283       opts.dump (&stream, text);
284       maintenance_test_options_command_completion_text
285         = std::move (stream.string ());
286     }
287   else
288     {
289       maintenance_test_options_command_completion_text
290         = string_printf ("0 %s\n", text);
291     }
292 }
293
294 /* Implementation of completer for the "maintenance test-options
295    require-delimiter/unknown-is-error/unknown-is-operand" commands.
296    Each of the commands maps to a different enum process_options_mode
297    enumerator.  */
298
299 static void
300 maintenance_test_options_completer_mode (completion_tracker &tracker,
301                                          const char *text,
302                                          gdb::option::process_options_mode mode)
303 {
304   test_options_opts opts;
305
306   try
307     {
308       bool res = (gdb::option::complete_options
309                   (tracker, &text, mode,
310                    make_test_options_options_def_group (&opts)));
311
312       save_completion_result (opts, res, text);
313     }
314   catch (const gdb_exception_error &ex)
315     {
316       save_completion_result (opts, true, text);
317       throw;
318     }
319 }
320
321 /* Implementation of the "maintenance test-options require-delimiter"
322    command.  */
323
324 static void
325 maintenance_test_options_require_delimiter_command (const char *args,
326                                                     int from_tty)
327 {
328   maintenance_test_options_command_mode
329     (args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
330 }
331
332 /* Implementation of the "maintenance test-options
333    unknown-is-error" command.  */
334
335 static void
336 maintenance_test_options_unknown_is_error_command (const char *args,
337                                                    int from_tty)
338 {
339   maintenance_test_options_command_mode
340     (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
341 }
342
343 /* Implementation of the "maintenance test-options
344    unknown-is-operand" command.  */
345
346 static void
347 maintenance_test_options_unknown_is_operand_command (const char *args,
348                                                      int from_tty)
349 {
350   maintenance_test_options_command_mode
351     (args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
352 }
353
354 /* Completer for the "maintenance test-options require-delimiter"
355    command.  */
356
357 static void
358 maintenance_test_options_require_delimiter_command_completer
359   (cmd_list_element *ignore, completion_tracker &tracker,
360    const char *text, const char *word)
361 {
362   maintenance_test_options_completer_mode
363     (tracker, text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER);
364 }
365
366 /* Completer for the "maintenance test-options unknown-is-error"
367    command.  */
368
369 static void
370 maintenance_test_options_unknown_is_error_command_completer
371   (cmd_list_element *ignore, completion_tracker &tracker,
372    const char *text, const char *word)
373 {
374   maintenance_test_options_completer_mode
375     (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR);
376 }
377
378 /* Completer for the "maintenance test-options unknown-is-operand"
379    command.  */
380
381 static void
382 maintenance_test_options_unknown_is_operand_command_completer
383   (cmd_list_element *ignore, completion_tracker &tracker,
384    const char *text, const char *word)
385 {
386   maintenance_test_options_completer_mode
387     (tracker, text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND);
388 }
389
390 /* Command list for maint test-options.  */
391 struct cmd_list_element *maintenance_test_options_list;
392
393 /* The "maintenance test-options" prefix command.  */
394
395 static void
396 maintenance_test_options_command (const char *arg, int from_tty)
397 {
398   printf_unfiltered
399     (_("\"maintenance test-options\" must be followed "
400        "by the name of a subcommand.\n"));
401   help_list (maintenance_test_options_list, "maintenance test-options ",
402              all_commands, gdb_stdout);
403 }
404
405 \f
406 void
407 _initialize_maint_test_options ()
408 {
409   cmd_list_element *cmd;
410
411   add_prefix_cmd ("test-options", no_class, maintenance_test_options_command,
412                   _("\
413 Generic command for testing the options infrastructure."),
414                   &maintenance_test_options_list,
415                   "maintenance test-options ", 0,
416                   &maintenancelist);
417
418   const auto def_group = make_test_options_options_def_group (nullptr);
419
420   static const std::string help_require_delim_str
421     = gdb::option::build_help (_("\
422 Command used for testing options processing.\n\
423 Usage: maint test-options require-delimiter [[OPTION]... --] [OPERAND]...\n\
424 \n\
425 Options:\n\
426 \n\
427 %OPTIONS%\n\
428 If you specify any command option, you must use a double dash (\"--\")\n\
429 to mark the end of option processing."),
430                                def_group);
431
432   static const std::string help_unknown_is_error_str
433     = gdb::option::build_help (_("\
434 Command used for testing options processing.\n\
435 Usage: maint test-options unknown-is-error [OPTION]... [OPERAND]...\n\
436 \n\
437 Options:\n\
438 \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 \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 }