1 /* CLI options framework, for GDB.
3 Copyright (C) 2017-2019 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
21 #include "cli/cli-option.h"
22 #include "cli/cli-decode.h"
23 #include "cli/cli-utils.h"
24 #include "cli/cli-setshow.h"
31 /* An option's value. Which field is active depends on the option's
35 /* For var_boolean options. */
38 /* For var_uinteger options. */
39 unsigned int uinteger
;
41 /* For var_zuinteger_unlimited options. */
44 /* For var_enum options. */
45 const char *enumeration
;
48 /* Holds an options definition and its value. */
49 struct option_def_and_value
51 /* The option definition. */
52 const option_def
&option
;
57 /* The option's value, if any. */
58 gdb::optional
<option_value
> value
;
61 static void save_option_value_in_ctx (gdb::optional
<option_def_and_value
> &ov
);
63 /* Info passed around when handling completion. */
64 struct parse_option_completion_info
66 /* The completion word. */
70 completion_tracker
&tracker
;
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. */
79 find_end_options_delimiter (const char *args
)
88 if (check_for_argument (&p
, "--"))
91 p
= skip_to_space (p
);
99 /* Complete TEXT/WORD on all options in OPTIONS_GROUP. */
102 complete_on_options (gdb::array_view
<const option_def_group
> options_group
,
103 completion_tracker
&tracker
,
104 const char *text
, const char *word
)
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)
111 tracker
.add_completion
112 (make_completion_match_str (opt
.name
, text
, word
));
116 /* See cli-option.h. */
119 complete_on_all_options (completion_tracker
&tracker
,
120 gdb::array_view
<const option_def_group
> options_group
)
122 static const char opt
[] = "-";
123 complete_on_options (options_group
, tracker
, opt
+ 1, opt
);
126 /* Parse ARGS, guided by OPTIONS_GROUP. HAVE_DELIMITER is true if the
127 whole ARGS line included the "--" options-terminator delimiter. */
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
,
134 parse_option_completion_info
*completion
= nullptr)
136 if (*args
== nullptr)
138 else if (**args
!= '-')
141 error (_("Unrecognized option at: %s"), *args
);
144 else if (check_for_argument (args
, "--"))
147 /* Skip the initial '-'. */
148 const char *arg
= *args
+ 1;
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;
155 for (const auto &grp
: options_group
)
157 for (const auto &o
: grp
.options
)
159 if (strncmp (o
.name
, arg
, len
) == 0)
161 if (match
!= nullptr)
163 if (completion
!= nullptr && arg
[len
] == '\0')
165 complete_on_options (options_group
,
167 arg
, completion
->word
);
171 error (_("Ambiguous option at: -%s"), arg
);
177 if ((isspace (arg
[len
]) || arg
[len
] == '\0')
178 && strlen (o
.name
) == len
)
179 break; /* Exact match. */
184 if (match
== nullptr)
186 if (have_delimiter
|| mode
!= PROCESS_OPTIONS_UNKNOWN_IS_OPERAND
)
187 error (_("Unrecognized option at: %s"), *args
);
192 if (completion
!= nullptr && arg
[len
] == '\0')
194 complete_on_options (options_group
, completion
->tracker
,
195 arg
, completion
->word
);
200 *args
= skip_spaces (*args
);
201 if (completion
!= nullptr)
202 completion
->word
= *args
;
208 if (!match
->have_argument
)
212 return option_def_and_value
{*match
, match_ctx
, val
};
215 const char *val_str
= *args
;
218 if (**args
== '\0' && completion
!= nullptr)
220 /* Complete on both "on/off" and more options. */
222 if (mode
== PROCESS_OPTIONS_REQUIRE_DELIMITER
)
224 complete_on_enum (completion
->tracker
,
225 boolean_enums
, val_str
, val_str
);
226 complete_on_all_options (completion
->tracker
, options_group
);
228 return option_def_and_value
{*match
, match_ctx
};
230 else if (**args
== '-')
233 "cmd -boolean-option -another-opt..."
235 "cmd -boolean-option on -another-opt..."
239 else if (**args
== '\0')
242 (1) "cmd -boolean-option "
244 (1) "cmd -boolean-option on"
250 res
= parse_cli_boolean_value (args
);
253 const char *end
= skip_to_space (*args
);
254 if (completion
!= nullptr)
258 complete_on_enum (completion
->tracker
,
259 boolean_enums
, val_str
, val_str
);
260 return option_def_and_value
{*match
, match_ctx
};
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
};
273 else if (completion
!= nullptr && **args
== '\0')
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
281 "p -object 1[TAB]" -> "p -object 1 "
282 "p -object ye[TAB]" -> "p -object yes "
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).
290 static const char *const all_boolean_enums
[] = {
297 complete_on_enum (completion
->tracker
, all_boolean_enums
,
305 return option_def_and_value
{*match
, match_ctx
, val
};
308 case var_zuinteger_unlimited
:
310 if (completion
!= nullptr)
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
318 completion
->tracker
.add_completion
319 (make_unique_xstrdup ("NUMBER"));
320 completion
->tracker
.add_completion
321 (make_unique_xstrdup ("unlimited"));
324 else if (startswith ("unlimited", *args
))
326 completion
->tracker
.add_completion
327 (make_unique_xstrdup ("unlimited"));
332 if (match
->type
== var_zuinteger_unlimited
)
335 val
.integer
= parse_cli_var_zuinteger_unlimited (args
, false);
336 return option_def_and_value
{*match
, match_ctx
, val
};
341 val
.uinteger
= parse_cli_var_uinteger (match
->type
, args
, false);
342 return option_def_and_value
{*match
, match_ctx
, val
};
347 if (completion
!= nullptr)
349 const char *after_arg
= skip_to_space (*args
);
350 if (*after_arg
== '\0')
352 complete_on_enum (completion
->tracker
,
353 match
->enums
, *args
, *args
);
354 if (completion
->tracker
.have_completions ())
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. */
363 if (check_for_argument (args
, "--"))
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. */
373 val
.enumeration
= parse_cli_var_enum (args
, match
->enums
);
374 return option_def_and_value
{*match
, match_ctx
, val
};
379 gdb_assert_not_reached (_("option type not supported"));
385 /* See cli-option.h. */
388 complete_options (completion_tracker
&tracker
,
390 process_options_mode mode
,
391 gdb::array_view
<const option_def_group
> options_group
)
393 const char *text
= *args
;
395 tracker
.set_use_custom_word_point (true);
397 const char *delimiter
= find_end_options_delimiter (text
);
398 bool have_delimiter
= delimiter
!= nullptr;
400 if (text
[0] == '-' && (!have_delimiter
|| *delimiter
== '\0'))
402 parse_option_completion_info completion_info
{nullptr, tracker
};
406 *args
= skip_spaces (*args
);
407 completion_info
.word
= *args
;
409 if (strcmp (*args
, "-") == 0)
411 complete_on_options (options_group
, tracker
, *args
+ 1,
412 completion_info
.word
);
414 else if (strcmp (*args
, "--") == 0)
416 tracker
.add_completion (make_unique_xstrdup (*args
));
418 else if (**args
== '-')
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 ())
425 tracker
.advance_custom_word_point_by (*args
- text
);
426 return mode
== PROCESS_OPTIONS_REQUIRE_DELIMITER
;
430 && ov
->option
.type
== var_boolean
431 && !ov
->value
.has_value ())
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
440 tracker
.advance_custom_word_point_by (*args
- text
);
441 return mode
== PROCESS_OPTIONS_REQUIRE_DELIMITER
;
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
450 (gdb) frame apply all -limit 10[TAB]
452 we don't try to complete on command names. */
454 && !tracker
.have_completions ()
456 && *args
> text
&& !isspace ((*args
)[-1]))
458 tracker
.advance_custom_word_point_by
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
);
470 tracker
.advance_custom_word_point_by
471 (completion_info
.word
- text
);
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
481 /* If we reached the end of the input string, then
482 offer all options, since that's all the user can
484 if (completion_info
.word
[0] == '\0')
485 complete_on_all_options (tracker
, options_group
);
492 if (tracker
.have_completions ())
494 tracker
.advance_custom_word_point_by
495 (completion_info
.word
- text
);
500 else if (delimiter
!= nullptr)
502 tracker
.advance_custom_word_point_by (delimiter
- text
);
510 /* Save the parsed value in the option's context. */
513 save_option_value_in_ctx (gdb::optional
<option_def_and_value
> &ov
)
515 switch (ov
->option
.type
)
519 bool value
= ov
->value
.has_value () ? ov
->value
->boolean
: true;
520 *ov
->option
.var_address
.boolean (ov
->option
, ov
->ctx
) = value
;
524 *ov
->option
.var_address
.uinteger (ov
->option
, ov
->ctx
)
525 = ov
->value
->uinteger
;
527 case var_zuinteger_unlimited
:
528 *ov
->option
.var_address
.integer (ov
->option
, ov
->ctx
)
529 = ov
->value
->integer
;
532 *ov
->option
.var_address
.enumeration (ov
->option
, ov
->ctx
)
533 = ov
->value
->enumeration
;
536 gdb_assert_not_reached ("unhandled option type");
540 /* See cli-option.h. */
543 process_options (const char **args
,
544 process_options_mode mode
,
545 gdb::array_view
<const option_def_group
> options_group
)
547 if (*args
== nullptr)
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;
556 if (mode
== PROCESS_OPTIONS_REQUIRE_DELIMITER
&& !have_delimiter
)
559 bool processed_any
= false;
563 *args
= skip_spaces (*args
);
565 auto ov
= parse_option (options_group
, mode
, have_delimiter
, args
);
573 processed_any
= true;
575 save_option_value_in_ctx (ov
);
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
584 get_val_type_str (const option_def
&opt
, std::string
&buffer
)
586 if (!opt
.have_argument
)
594 case var_zuinteger_unlimited
:
595 return "NUMBER|unlimited";
599 for (size_t i
= 0; opt
.enums
[i
] != nullptr; i
++)
603 buffer
+= opt
.enums
[i
];
605 return buffer
.c_str ();
612 /* Helper for build_help. Appends an indented version of DOC into
616 append_indented_doc (const char *doc
, std::string
&help
)
619 const char *n
= strchr (p
, '\n');
624 help
.append (p
, n
- p
+ 1);
626 n
= strchr (p
, '\n');
633 /* Fill HELP with an auto-generated "help" string fragment for
637 build_help_option (gdb::array_view
<const option_def
> options
,
642 for (const auto &o
: options
)
644 if (o
.set_doc
== nullptr)
650 const char *val_type_str
= get_val_type_str (o
, buffer
);
651 if (val_type_str
!= nullptr)
654 help
+= val_type_str
;
657 append_indented_doc (o
.set_doc
, help
);
658 if (o
.help_doc
!= nullptr)
659 append_indented_doc (o
.help_doc
, help
);
664 /* See cli-option.h. */
667 build_help (const char *help_tmpl
,
668 gdb::array_view
<const option_def_group
> options_group
)
670 std::string help_str
;
672 const char *p
= strstr (help_tmpl
, "%OPTIONS%");
673 help_str
.assign (help_tmpl
, p
);
675 for (const auto &grp
: options_group
)
676 for (const auto &opt
: grp
.options
)
677 build_help_option (opt
, help_str
);
679 p
+= strlen ("%OPTIONS%");
685 /* See cli-option.h. */
688 add_setshow_cmds_for_options (command_class cmd_class
,
690 gdb::array_view
<const option_def
> options
,
691 struct cmd_list_element
**set_list
,
692 struct cmd_list_element
**show_list
)
694 for (const auto &option
: options
)
696 if (option
.type
== var_boolean
)
698 add_setshow_boolean_cmd (option
.name
, cmd_class
,
699 option
.var_address
.boolean (option
, data
),
700 option
.set_doc
, option
.show_doc
,
702 nullptr, option
.show_cmd_cb
,
703 set_list
, show_list
);
705 else if (option
.type
== var_uinteger
)
707 add_setshow_uinteger_cmd (option
.name
, cmd_class
,
708 option
.var_address
.uinteger (option
, data
),
709 option
.set_doc
, option
.show_doc
,
711 nullptr, option
.show_cmd_cb
,
712 set_list
, show_list
);
714 else if (option
.type
== var_zuinteger_unlimited
)
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
,
721 nullptr, option
.show_cmd_cb
,
722 set_list
, show_list
);
724 else if (option
.type
== var_enum
)
726 add_setshow_enum_cmd (option
.name
, cmd_class
,
728 option
.var_address
.enumeration (option
, data
),
729 option
.set_doc
, option
.show_doc
,
731 nullptr, option
.show_cmd_cb
,
732 set_list
, show_list
);
735 gdb_assert_not_reached (_("option type not handled"));
739 } /* namespace option */
740 } /* namespace gdb */