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