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