8f2844610b56d55ae95be5d08beb2cd0910a59c2
[deliverable/binutils-gdb.git] / gdb / cli / cli-option.c
1 /* CLI options framework, for GDB.
2
3 Copyright (C) 2017-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 "cli/cli-option.h"
22 #include "cli/cli-decode.h"
23 #include "cli/cli-utils.h"
24 #include "cli/cli-setshow.h"
25 #include "command.h"
26 #include <vector>
27
28 namespace gdb {
29 namespace option {
30
31 /* An option's value. Which field is active depends on the option's
32 type. */
33 union option_value
34 {
35 /* For var_boolean options. */
36 bool boolean;
37
38 /* For var_uinteger options. */
39 unsigned int uinteger;
40
41 /* For var_zuinteger_unlimited options. */
42 int integer;
43
44 /* For var_enum options. */
45 const char *enumeration;
46 };
47
48 /* Holds an options definition and its value. */
49 struct option_def_and_value
50 {
51 /* The option definition. */
52 const option_def &option;
53
54 /* A context. */
55 void *ctx;
56
57 /* The option's value, if any. */
58 gdb::optional<option_value> value;
59 };
60
61 static void save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov);
62
63 /* Info passed around when handling completion. */
64 struct parse_option_completion_info
65 {
66 /* The completion word. */
67 const char *word;
68
69 /* The tracker. */
70 completion_tracker &tracker;
71 };
72
73 /* If ARGS starts with "-", look for a "--" delimiter. If one is
74 found, then interpret everything up until the "--" as command line
75 options. Otherwise, interpret unknown input as the beginning of
76 the command's operands. */
77
78 static const char *
79 find_end_options_delimiter (const char *args)
80 {
81 if (args[0] == '-')
82 {
83 const char *p = args;
84
85 p = skip_spaces (p);
86 while (*p)
87 {
88 if (check_for_argument (&p, "--"))
89 return p;
90 else
91 p = skip_to_space (p);
92 p = skip_spaces (p);
93 }
94 }
95
96 return nullptr;
97 }
98
99 /* Complete TEXT/WORD on all options in OPTIONS_GROUP. */
100
101 static void
102 complete_on_options (gdb::array_view<const option_def_group> options_group,
103 completion_tracker &tracker,
104 const char *text, const char *word)
105 {
106 size_t textlen = strlen (text);
107 for (const auto &grp : options_group)
108 for (const auto &opt : grp.options)
109 if (strncmp (opt.name, text, textlen) == 0)
110 {
111 tracker.add_completion
112 (make_completion_match_str (opt.name, text, word));
113 }
114 }
115
116 /* See cli-option.h. */
117
118 void
119 complete_on_all_options (completion_tracker &tracker,
120 gdb::array_view<const option_def_group> options_group)
121 {
122 static const char opt[] = "-";
123 complete_on_options (options_group, tracker, opt + 1, opt);
124 }
125
126 /* Parse ARGS, guided by OPTIONS_GROUP. HAVE_DELIMITER is true if the
127 whole ARGS line included the "--" options-terminator delimiter. */
128
129 static gdb::optional<option_def_and_value>
130 parse_option (gdb::array_view<const option_def_group> options_group,
131 process_options_mode mode,
132 bool have_delimiter,
133 const char **args,
134 parse_option_completion_info *completion = nullptr)
135 {
136 if (*args == nullptr)
137 return {};
138 else if (**args != '-')
139 {
140 if (have_delimiter)
141 error (_("Unrecognized option at: %s"), *args);
142 return {};
143 }
144 else if (check_for_argument (args, "--"))
145 return {};
146
147 /* Skip the initial '-'. */
148 const char *arg = *args + 1;
149
150 const char *after = skip_to_space (arg);
151 size_t len = after - arg;
152 const option_def *match = nullptr;
153 void *match_ctx = nullptr;
154
155 for (const auto &grp : options_group)
156 {
157 for (const auto &o : grp.options)
158 {
159 if (strncmp (o.name, arg, len) == 0)
160 {
161 if (match != nullptr)
162 {
163 if (completion != nullptr && arg[len] == '\0')
164 {
165 complete_on_options (options_group,
166 completion->tracker,
167 arg, completion->word);
168 return {};
169 }
170
171 error (_("Ambiguous option at: -%s"), arg);
172 }
173
174 match = &o;
175 match_ctx = grp.ctx;
176
177 if ((isspace (arg[len]) || arg[len] == '\0')
178 && strlen (o.name) == len)
179 break; /* Exact match. */
180 }
181 }
182 }
183
184 if (match == nullptr)
185 {
186 if (have_delimiter || mode != PROCESS_OPTIONS_UNKNOWN_IS_OPERAND)
187 error (_("Unrecognized option at: %s"), *args);
188
189 return {};
190 }
191
192 if (completion != nullptr && arg[len] == '\0')
193 {
194 complete_on_options (options_group, completion->tracker,
195 arg, completion->word);
196 return {};
197 }
198
199 *args += 1 + len;
200 *args = skip_spaces (*args);
201 if (completion != nullptr)
202 completion->word = *args;
203
204 switch (match->type)
205 {
206 case var_boolean:
207 {
208 if (!match->have_argument)
209 {
210 option_value val;
211 val.boolean = true;
212 return option_def_and_value {*match, match_ctx, val};
213 }
214
215 const char *val_str = *args;
216 int res;
217
218 if (**args == '\0' && completion != nullptr)
219 {
220 /* Complete on both "on/off" and more options. */
221
222 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER)
223 {
224 complete_on_enum (completion->tracker,
225 boolean_enums, val_str, val_str);
226 complete_on_all_options (completion->tracker, options_group);
227 }
228 return option_def_and_value {*match, match_ctx};
229 }
230 else if (**args == '-')
231 {
232 /* Treat:
233 "cmd -boolean-option -another-opt..."
234 as:
235 "cmd -boolean-option on -another-opt..."
236 */
237 res = 1;
238 }
239 else if (**args == '\0')
240 {
241 /* Treat:
242 (1) "cmd -boolean-option "
243 as:
244 (1) "cmd -boolean-option on"
245 */
246 res = 1;
247 }
248 else
249 {
250 res = parse_cli_boolean_value (args);
251 if (res < 0)
252 {
253 const char *end = skip_to_space (*args);
254 if (completion != nullptr)
255 {
256 if (*end == '\0')
257 {
258 complete_on_enum (completion->tracker,
259 boolean_enums, val_str, val_str);
260 return option_def_and_value {*match, match_ctx};
261 }
262 }
263
264 if (have_delimiter)
265 error (_("Value given for `-%s' is not a boolean: %.*s"),
266 match->name, (int) (end - val_str), val_str);
267 /* The user didn't separate options from operands
268 using "--", so treat this unrecognized value as the
269 start of the operands. This makes "frame apply all
270 -past-main CMD" work. */
271 return option_def_and_value {*match, match_ctx};
272 }
273 else if (completion != nullptr && **args == '\0')
274 {
275 /* While "cmd -boolean [TAB]" only offers "on" and
276 "off", the boolean option actually accepts "1",
277 "yes", etc. as boolean values. We complete on all
278 of those instead of BOOLEAN_ENUMS here to make
279 these work:
280
281 "p -object 1[TAB]" -> "p -object 1 "
282 "p -object ye[TAB]" -> "p -object yes "
283
284 Etc. Note that it's important that the space is
285 auto-appended. Otherwise, if we only completed on
286 on/off here, then it might look to the user like
287 "1" isn't valid, like:
288 "p -object 1[TAB]" -> "p -object 1" (i.e., nothing happens).
289 */
290 static const char *const all_boolean_enums[] = {
291 "on", "off",
292 "yes", "no",
293 "enable", "disable",
294 "0", "1",
295 nullptr,
296 };
297 complete_on_enum (completion->tracker, all_boolean_enums,
298 val_str, val_str);
299 return {};
300 }
301 }
302
303 option_value val;
304 val.boolean = res;
305 return option_def_and_value {*match, match_ctx, val};
306 }
307 case var_uinteger:
308 case var_zuinteger_unlimited:
309 {
310 if (completion != nullptr)
311 {
312 if (**args == '\0')
313 {
314 /* Convenience to let the user know what the option
315 can accept. Note there's no common prefix between
316 the strings on purpose, so that readline doesn't do
317 a partial match. */
318 completion->tracker.add_completion
319 (make_unique_xstrdup ("NUMBER"));
320 completion->tracker.add_completion
321 (make_unique_xstrdup ("unlimited"));
322 return {};
323 }
324 else if (startswith ("unlimited", *args))
325 {
326 completion->tracker.add_completion
327 (make_unique_xstrdup ("unlimited"));
328 return {};
329 }
330 }
331
332 if (match->type == var_zuinteger_unlimited)
333 {
334 option_value val;
335 val.integer = parse_cli_var_zuinteger_unlimited (args, false);
336 return option_def_and_value {*match, match_ctx, val};
337 }
338 else
339 {
340 option_value val;
341 val.uinteger = parse_cli_var_uinteger (match->type, args, false);
342 return option_def_and_value {*match, match_ctx, val};
343 }
344 }
345 case var_enum:
346 {
347 if (completion != nullptr)
348 {
349 const char *after_arg = skip_to_space (*args);
350 if (*after_arg == '\0')
351 {
352 complete_on_enum (completion->tracker,
353 match->enums, *args, *args);
354 if (completion->tracker.have_completions ())
355 return {};
356
357 /* If we don't have completions, let the
358 non-completion path throw on invalid enum value
359 below, so that completion processing stops. */
360 }
361 }
362
363 if (check_for_argument (args, "--"))
364 {
365 /* Treat e.g., "backtrace -entry-values --" as if there
366 was no argument after "-entry-values". This makes
367 parse_cli_var_enum throw an error with a suggestion of
368 what are the valid options. */
369 args = nullptr;
370 }
371
372 option_value val;
373 val.enumeration = parse_cli_var_enum (args, match->enums);
374 return option_def_and_value {*match, match_ctx, val};
375 }
376
377 default:
378 /* Not yet. */
379 gdb_assert_not_reached (_("option type not supported"));
380 }
381
382 return {};
383 }
384
385 /* See cli-option.h. */
386
387 bool
388 complete_options (completion_tracker &tracker,
389 const char **args,
390 process_options_mode mode,
391 gdb::array_view<const option_def_group> options_group)
392 {
393 const char *text = *args;
394
395 tracker.set_use_custom_word_point (true);
396
397 const char *delimiter = find_end_options_delimiter (text);
398 bool have_delimiter = delimiter != nullptr;
399
400 if (text[0] == '-' && (!have_delimiter || *delimiter == '\0'))
401 {
402 parse_option_completion_info completion_info {nullptr, tracker};
403
404 while (1)
405 {
406 *args = skip_spaces (*args);
407 completion_info.word = *args;
408
409 if (strcmp (*args, "-") == 0)
410 {
411 complete_on_options (options_group, tracker, *args + 1,
412 completion_info.word);
413 }
414 else if (strcmp (*args, "--") == 0)
415 {
416 tracker.add_completion (make_unique_xstrdup (*args));
417 }
418 else if (**args == '-')
419 {
420 gdb::optional<option_def_and_value> ov
421 = parse_option (options_group, mode, have_delimiter,
422 args, &completion_info);
423 if (!ov && !tracker.have_completions ())
424 {
425 tracker.advance_custom_word_point_by (*args - text);
426 return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER;
427 }
428
429 if (ov
430 && ov->option.type == var_boolean
431 && !ov->value.has_value ())
432 {
433 /* Looked like a boolean option, but we failed to
434 parse the value. If this command requires a
435 delimiter, this value can't be the start of the
436 operands, so return true. Otherwise, if the
437 command doesn't require a delimiter return false
438 so that the caller tries to complete on the
439 operand. */
440 tracker.advance_custom_word_point_by (*args - text);
441 return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER;
442 }
443
444 /* If we parsed an option with an argument, and reached
445 the end of the input string with no trailing space,
446 return true, so that our callers don't try to
447 complete anything by themselves. E.g., this makes it
448 so that with:
449
450 (gdb) frame apply all -limit 10[TAB]
451
452 we don't try to complete on command names. */
453 if (ov
454 && !tracker.have_completions ()
455 && **args == '\0'
456 && *args > text && !isspace ((*args)[-1]))
457 {
458 tracker.advance_custom_word_point_by
459 (*args - text);
460 return true;
461 }
462
463 /* If the caller passed in a context, then it is
464 interested in the option argument values. */
465 if (ov && ov->ctx != nullptr)
466 save_option_value_in_ctx (ov);
467 }
468 else
469 {
470 tracker.advance_custom_word_point_by
471 (completion_info.word - text);
472
473 /* If the command requires a delimiter, but we haven't
474 seen one, then return true, so that the caller
475 doesn't try to complete on whatever follows options,
476 which for these commands should only be done if
477 there's a delimiter. */
478 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER
479 && !have_delimiter)
480 {
481 /* If we reached the end of the input string, then
482 offer all options, since that's all the user can
483 type (plus "--"). */
484 if (completion_info.word[0] == '\0')
485 complete_on_all_options (tracker, options_group);
486 return true;
487 }
488 else
489 return false;
490 }
491
492 if (tracker.have_completions ())
493 {
494 tracker.advance_custom_word_point_by
495 (completion_info.word - text);
496 return true;
497 }
498 }
499 }
500 else if (delimiter != nullptr)
501 {
502 tracker.advance_custom_word_point_by (delimiter - text);
503 *args = delimiter;
504 return false;
505 }
506
507 return false;
508 }
509
510 /* Save the parsed value in the option's context. */
511
512 static void
513 save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov)
514 {
515 switch (ov->option.type)
516 {
517 case var_boolean:
518 {
519 bool value = ov->value.has_value () ? ov->value->boolean : true;
520 *ov->option.var_address.boolean (ov->option, ov->ctx) = value;
521 }
522 break;
523 case var_uinteger:
524 *ov->option.var_address.uinteger (ov->option, ov->ctx)
525 = ov->value->uinteger;
526 break;
527 case var_zuinteger_unlimited:
528 *ov->option.var_address.integer (ov->option, ov->ctx)
529 = ov->value->integer;
530 break;
531 case var_enum:
532 *ov->option.var_address.enumeration (ov->option, ov->ctx)
533 = ov->value->enumeration;
534 break;
535 default:
536 gdb_assert_not_reached ("unhandled option type");
537 }
538 }
539
540 /* See cli-option.h. */
541
542 bool
543 process_options (const char **args,
544 process_options_mode mode,
545 gdb::array_view<const option_def_group> options_group)
546 {
547 if (*args == nullptr)
548 return false;
549
550 /* If ARGS starts with "-", look for a "--" sequence. If one is
551 found, then interpret everything up until the "--" as
552 'gdb::option'-style command line options. Otherwise, interpret
553 ARGS as possibly the command's operands. */
554 bool have_delimiter = find_end_options_delimiter (*args) != nullptr;
555
556 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER && !have_delimiter)
557 return false;
558
559 bool processed_any = false;
560
561 while (1)
562 {
563 *args = skip_spaces (*args);
564
565 auto ov = parse_option (options_group, mode, have_delimiter, args);
566 if (!ov)
567 {
568 if (processed_any)
569 return true;
570 return false;
571 }
572
573 processed_any = true;
574
575 save_option_value_in_ctx (ov);
576 }
577 }
578
579 /* Helper for build_help. Return a fragment of a help string showing
580 OPT's possible values. Returns NULL if OPT doesn't take an
581 argument. */
582
583 static const char *
584 get_val_type_str (const option_def &opt, std::string &buffer)
585 {
586 if (!opt.have_argument)
587 return nullptr;
588
589 switch (opt.type)
590 {
591 case var_boolean:
592 return "[on|off]";
593 case var_uinteger:
594 case var_zuinteger_unlimited:
595 return "NUMBER|unlimited";
596 case var_enum:
597 {
598 buffer = "";
599 for (size_t i = 0; opt.enums[i] != nullptr; i++)
600 {
601 if (i != 0)
602 buffer += "|";
603 buffer += opt.enums[i];
604 }
605 return buffer.c_str ();
606 }
607 default:
608 return nullptr;
609 }
610 }
611
612 /* Helper for build_help. Appends an indented version of DOC into
613 HELP. */
614
615 static void
616 append_indented_doc (const char *doc, std::string &help)
617 {
618 const char *p = doc;
619 const char *n = strchr (p, '\n');
620
621 while (n != nullptr)
622 {
623 help += " ";
624 help.append (p, n - p + 1);
625 p = n + 1;
626 n = strchr (p, '\n');
627 }
628 help += " ";
629 help += p;
630 help += '\n';
631 }
632
633 /* Fill HELP with an auto-generated "help" string fragment for
634 OPTIONS. */
635
636 static void
637 build_help_option (gdb::array_view<const option_def> options,
638 std::string &help)
639 {
640 std::string buffer;
641
642 for (const auto &o : options)
643 {
644 if (o.set_doc == nullptr)
645 continue;
646
647 help += " -";
648 help += o.name;
649
650 const char *val_type_str = get_val_type_str (o, buffer);
651 if (val_type_str != nullptr)
652 {
653 help += ' ';
654 help += val_type_str;
655 }
656 help += "\n";
657 append_indented_doc (o.set_doc, help);
658 if (o.help_doc != nullptr)
659 append_indented_doc (o.help_doc, help);
660 help += '\n';
661 }
662 }
663
664 /* See cli-option.h. */
665
666 std::string
667 build_help (const char *help_tmpl,
668 gdb::array_view<const option_def_group> options_group)
669 {
670 std::string help_str;
671
672 const char *p = strstr (help_tmpl, "%OPTIONS%");
673 help_str.assign (help_tmpl, p);
674
675 for (const auto &grp : options_group)
676 for (const auto &opt : grp.options)
677 build_help_option (opt, help_str);
678
679 p += strlen ("%OPTIONS%");
680 help_str.append (p);
681
682 return help_str;
683 }
684
685 /* See cli-option.h. */
686
687 void
688 add_setshow_cmds_for_options (command_class cmd_class,
689 void *data,
690 gdb::array_view<const option_def> options,
691 struct cmd_list_element **set_list,
692 struct cmd_list_element **show_list)
693 {
694 for (const auto &option : options)
695 {
696 if (option.type == var_boolean)
697 {
698 add_setshow_boolean_cmd (option.name, cmd_class,
699 option.var_address.boolean (option, data),
700 option.set_doc, option.show_doc,
701 option.help_doc,
702 nullptr, option.show_cmd_cb,
703 set_list, show_list);
704 }
705 else if (option.type == var_uinteger)
706 {
707 add_setshow_uinteger_cmd (option.name, cmd_class,
708 option.var_address.uinteger (option, data),
709 option.set_doc, option.show_doc,
710 option.help_doc,
711 nullptr, option.show_cmd_cb,
712 set_list, show_list);
713 }
714 else if (option.type == var_zuinteger_unlimited)
715 {
716 add_setshow_zuinteger_unlimited_cmd
717 (option.name, cmd_class,
718 option.var_address.integer (option, data),
719 option.set_doc, option.show_doc,
720 option.help_doc,
721 nullptr, option.show_cmd_cb,
722 set_list, show_list);
723 }
724 else if (option.type == var_enum)
725 {
726 add_setshow_enum_cmd (option.name, cmd_class,
727 option.enums,
728 option.var_address.enumeration (option, data),
729 option.set_doc, option.show_doc,
730 option.help_doc,
731 nullptr, option.show_cmd_cb,
732 set_list, show_list);
733 }
734 else
735 gdb_assert_not_reached (_("option type not handled"));
736 }
737 }
738
739 } /* namespace option */
740 } /* namespace gdb */
This page took 0.050447 seconds and 4 git commands to generate.