mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-16 14:45:06 +08:00

This commit adds a generic command options framework, that makes it easy enough to add '-'-style options to commands in a uniform way, instead of each command implementing option parsing in its own way. Options are defined in arrays of option_def objects (for option definition), and the same options definitions are used for supporting TAB completion, and also for generating the relevant help fragment of the "help" command. See the gdb::options::build_help function, which returns a string with the result of replacing %OPTIONS% in a template string with an auto-generated "help" string fragment for all the passed-in options. Since most options in GDB are in the form of "-OPT", with a single dash, this is the format that the framework supports. I like to think of gdb's "-OPT" as the equivalent to getopt's long options format ("--OPT"), and gdb's "/" as the equivalent to getopt's short options format. getopt's short options format allows mixing several one-character options, like "ls -als", kind of similar to gdb's "x /FMT" and "disassemble /MOD", etc. While with gdb's "-" options, the option is expected to have a full name, and to be abbreviatable. E.g., "watch -location", "break -function main", etc. This patch only deals with "-" options. The above comment serves more to disclose why I don't think we should support mixing several unrelated options in a single "-" option invocation, like "thread apply -qcs" instead of "thread apply -q -c -s". The following patches will add uses of the infrastructure to several key commands. Most notably, "print", "compile print", "backtrace", "frame apply" and "thread apply". I tried to add options to several commands in order to make sure the framework didn't leave that many open holes open. Options use the same type as set commands -- enum var_types. So boolean options are var_boolean, enum options are var_enum, etc. The idea is to share code between settings commands and command options. The "print" options will be based on the "set print" commands, and their names will be the same. Actually, their definitions will be the same too. There is a function to create "set/show" commands from an array for option definitions: /* Install set/show commands for options defined in OPTIONS. DATA is a pointer to the structure that holds the data associated with the OPTIONS array. */ extern void add_setshow_cmds_for_options (command_class cmd_class, void *data, gdb::array_view<const option_def> options, struct cmd_list_element **set_list, struct cmd_list_element **show_list); That will be used by several following patches. Other features: - You can use the "--" delimiter to explicitly indicate end of options. Several existing commands use this token sequence for this effect already, so this just standardizes it. - You can shorten option names, as long as unambiguous. Currently, some commands allow this (e.g., break -function), while others do not (thread apply all -ascending). As GDB allows abbreviating command names and other things, it feels more GDB-ish to allow abbreviating option names too, to me. - For boolean options, 0/1 stands for off/on, just like with boolean "set" commands. - For boolean options, "true" is implied, just like with boolean "set commands. These are the option types supported, with a few examples: - boolean options (var_boolean). The option's argument is optional. (gdb) print -pretty on -- *obj (gdb) print -pretty off -- *obj (gdb) print -p -- *obj (gdb) print -p 0 -- *obj - flag options (like var_boolean, but no option argument (on/off)) (gdb) thread apply all -s COMMAND - enum options (var_enum) (gdb) bt -entry-values compact (gdb) bt -e c - uinteger options (var_uinteger) (gdb) print -elements 100 -- *obj (gdb) print -e 100 -- *obj (gdb) print -elements unlimited -- *obj (gdb) print -e u -- *obj - zuinteger-unlimited options (var_zuinteger_unlimited) (gdb) print -max-depth 100 -- obj (gdb) print -max-depth -1 -- obj (gdb) print -max-depth unlimited -- obj Other var_types could be supported, of course. These were just the types that I needed for the commands that I ported over, in the following patches. It was interesting (and unfortunate) to find that we need at least 3 different modes to cover the existing commands: - Commands that require ending options with "--" if you specify any option: "print" and "compile print". - Commands that do not want to require "--", and want to error out if you specify an unknown option (i.e., an unknown argument that starts with '-'): "compile code" / "compile file". - Commands that do not want to require "--", and want to process unknown options themselves: "bt", because of "bt -COUNT", "thread/frame apply", because "-" is a valid command. The different behavior is encoded in the process_options_mode enum, passed to process_options/complete_options. For testing, this patch adds one representative maintenance command for each of the process_options_mode values, that are used by the testsuite to exercise the options framework: (gdb) maint test-options require-delimiter (gdb) maint test-options unknown-is-error (gdb) maint test-options unknown-is-operand and adds another command to help with TAB-completion testing: (gdb) maint show test-options-completion-result See their description at the top of the maint-test-options.c file. Docs/NEWS are in a patch later in the series. gdb/ChangeLog: 2019-06-13 Pedro Alves <palves@redhat.com> * Makefile.in (SUBDIR_CLI_SRCS): Add cli/cli-option.c. (COMMON_SFILES): Add maint-test-settings.c. * cli/cli-decode.c (boolean_enums): New global, factored out from ... (add_setshow_boolean_cmd): ... here. * cli/cli-decode.h (boolean_enums): Declare. * cli/cli-option.c: New file. * cli/cli-option.h: New file. * cli/cli-setshow.c (parse_cli_boolean_value(const char **)): New, factored out from ... (parse_cli_boolean_value(const char *)): ... this. (is_unlimited_literal): Change parameter type to pointer to pointer. Adjust and advance ARG pointer. (parse_cli_var_uinteger, parse_cli_var_zuinteger_unlimited) (parse_cli_var_enum): New, factored out from ... (do_set_command): ... this. Adjust. * cli/cli-setshow.h (parse_cli_boolean_value) (parse_cli_var_uinteger, parse_cli_var_zuinteger_unlimited) (parse_cli_var_enum): Declare. * cli/cli-utils.c: Include "cli/cli-option.h". (get_ulongest): New. * cli/cli-utils.h (get_ulongest): Declare. (check_for_argument): New overloads. * maint-test-options.c: New file. gdb/testsuite/ChangeLog: 2019-06-13 Pedro Alves <palves@redhat.com> * gdb.base/options.c: New file. * gdb.base/options.exp: New file.
263 lines
8.6 KiB
C++
263 lines
8.6 KiB
C++
/* CLI utilities.
|
|
|
|
Copyright (C) 2011-2019 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef CLI_CLI_UTILS_H
|
|
#define CLI_CLI_UTILS_H
|
|
|
|
/* *PP is a string denoting a number. Get the number. Advance *PP
|
|
after the string and any trailing whitespace.
|
|
|
|
The string can either be a number, or "$" followed by the name of a
|
|
convenience variable, or ("$" or "$$") followed by digits.
|
|
|
|
TRAILER is a character which can be found after the number; most
|
|
commonly this is `-'. If you don't want a trailer, use \0. */
|
|
|
|
extern int get_number_trailer (const char **pp, int trailer);
|
|
|
|
/* Convenience. Like get_number_trailer, but with no TRAILER. */
|
|
|
|
extern int get_number (const char **);
|
|
|
|
/* Like the above, but takes a non-const "char **". */
|
|
|
|
extern int get_number (char **);
|
|
|
|
/* Like get_number_trailer, but works with ULONGEST, and throws on
|
|
error instead of returning 0. */
|
|
extern ULONGEST get_ulongest (const char **pp, int trailer = '\0');
|
|
|
|
/* Extract from ARGS the arguments [-q] [-t TYPEREGEXP] [--] NAMEREGEXP.
|
|
|
|
The caller is responsible to initialize *QUIET to false, *REGEXP
|
|
and *T_REGEXP to "".
|
|
extract_info_print_args can then be called iteratively to search
|
|
for valid arguments, as part of a 'main parsing loop' searching for
|
|
-q/-t/-- arguments together with other flags and options.
|
|
|
|
Returns true and updates *ARGS + one of *QUIET, *REGEXP, *T_REGEXP if
|
|
it finds a valid argument.
|
|
Returns false if no valid argument is found at the beginning of ARGS. */
|
|
|
|
extern bool extract_info_print_args (const char **args,
|
|
bool *quiet,
|
|
std::string *regexp,
|
|
std::string *t_regexp);
|
|
|
|
/* Throws an error telling the user that ARGS starts with an option
|
|
unrecognized by COMMAND. */
|
|
|
|
extern void report_unrecognized_option_error (const char *command,
|
|
const char *args);
|
|
|
|
|
|
/* Builds the help string for a command documented by PREFIX,
|
|
followed by the extract_info_print_args help for ENTITY_KIND. */
|
|
|
|
const char *info_print_args_help (const char *prefix,
|
|
const char *entity_kind);
|
|
|
|
/* Parse a number or a range.
|
|
A number will be of the form handled by get_number.
|
|
A range will be of the form <number1> - <number2>, and
|
|
will represent all the integers between number1 and number2,
|
|
inclusive. */
|
|
|
|
class number_or_range_parser
|
|
{
|
|
public:
|
|
/* Default construction. Must call init before calling
|
|
get_next. */
|
|
number_or_range_parser () {}
|
|
|
|
/* Calls init automatically. */
|
|
number_or_range_parser (const char *string);
|
|
|
|
/* STRING is the string to be parsed. */
|
|
void init (const char *string);
|
|
|
|
/* While processing a range, this fuction is called iteratively; At
|
|
each call it will return the next value in the range.
|
|
|
|
At the beginning of parsing a range, the char pointer
|
|
STATE->m_cur_tok will be advanced past <number1> and left
|
|
pointing at the '-' token. Subsequent calls will not advance the
|
|
pointer until the range is completed. The call that completes
|
|
the range will advance the pointer past <number2>. */
|
|
int get_number ();
|
|
|
|
/* Setup internal state such that get_next() returns numbers in the
|
|
START_VALUE to END_VALUE range. END_PTR is where the string is
|
|
advanced to when get_next() returns END_VALUE. */
|
|
void setup_range (int start_value, int end_value,
|
|
const char *end_ptr);
|
|
|
|
/* Returns true if parsing has completed. */
|
|
bool finished () const;
|
|
|
|
/* Return the string being parsed. When parsing has finished, this
|
|
points past the last parsed token. */
|
|
const char *cur_tok () const
|
|
{ return m_cur_tok; }
|
|
|
|
/* True when parsing a range. */
|
|
bool in_range () const
|
|
{ return m_in_range; }
|
|
|
|
/* When parsing a range, the final value in the range. */
|
|
int end_value () const
|
|
{ return m_end_value; }
|
|
|
|
/* When parsing a range, skip past the final token in the range. */
|
|
void skip_range ()
|
|
{
|
|
gdb_assert (m_in_range);
|
|
m_cur_tok = m_end_ptr;
|
|
m_in_range = false;
|
|
}
|
|
|
|
private:
|
|
/* No need for these. They are intentionally not defined anywhere. */
|
|
number_or_range_parser (const number_or_range_parser &);
|
|
number_or_range_parser &operator= (const number_or_range_parser &);
|
|
|
|
/* The string being parsed. When parsing has finished, this points
|
|
past the last parsed token. */
|
|
const char *m_cur_tok;
|
|
|
|
/* Last value returned. */
|
|
int m_last_retval;
|
|
|
|
/* When parsing a range, the final value in the range. */
|
|
int m_end_value;
|
|
|
|
/* When parsing a range, a pointer past the final token in the
|
|
range. */
|
|
const char *m_end_ptr;
|
|
|
|
/* True when parsing a range. */
|
|
bool m_in_range;
|
|
};
|
|
|
|
/* Accept a number and a string-form list of numbers such as is
|
|
accepted by get_number_or_range. Return TRUE if the number is
|
|
in the list.
|
|
|
|
By definition, an empty list includes all numbers. This is to
|
|
be interpreted as typing a command such as "delete break" with
|
|
no arguments. */
|
|
|
|
extern int number_is_in_list (const char *list, int number);
|
|
|
|
/* Reverse S to the last non-whitespace character without skipping past
|
|
START. */
|
|
|
|
extern const char *remove_trailing_whitespace (const char *start,
|
|
const char *s);
|
|
|
|
/* Same, for non-const S. */
|
|
|
|
static inline char *
|
|
remove_trailing_whitespace (const char *start, char *s)
|
|
{
|
|
return (char *) remove_trailing_whitespace (start, (const char *) s);
|
|
}
|
|
|
|
/* A helper function to extract an argument from *ARG. An argument is
|
|
delimited by whitespace. The return value is empty if no argument
|
|
was found. */
|
|
|
|
extern std::string extract_arg (char **arg);
|
|
|
|
/* A const-correct version of the above. */
|
|
|
|
extern std::string extract_arg (const char **arg);
|
|
|
|
/* A helper function that looks for an argument at the start of a
|
|
string. The argument must also either be at the end of the string,
|
|
or be followed by whitespace. Returns 1 if it finds the argument,
|
|
0 otherwise. If the argument is found, it updates *STR to point
|
|
past the argument and past any whitespace following the
|
|
argument. */
|
|
extern int check_for_argument (const char **str, const char *arg, int arg_len);
|
|
|
|
/* Same as above, but ARG's length is computed. */
|
|
|
|
static inline int
|
|
check_for_argument (const char **str, const char *arg)
|
|
{
|
|
return check_for_argument (str, arg, strlen (arg));
|
|
}
|
|
|
|
/* Same, for non-const STR. */
|
|
|
|
static inline int
|
|
check_for_argument (char **str, const char *arg, int arg_len)
|
|
{
|
|
return check_for_argument (const_cast<const char **> (str),
|
|
arg, arg_len);
|
|
}
|
|
|
|
static inline int
|
|
check_for_argument (char **str, const char *arg)
|
|
{
|
|
return check_for_argument (str, arg, strlen (arg));
|
|
}
|
|
|
|
/* A helper function that looks for a set of flags at the start of a
|
|
string. The possible flags are given as a null terminated string.
|
|
A flag in STR must either be at the end of the string,
|
|
or be followed by whitespace.
|
|
Returns 0 if no valid flag is found at the start of STR.
|
|
Otherwise updates *STR, and returns N (which is > 0),
|
|
such that FLAGS [N - 1] is the valid found flag. */
|
|
extern int parse_flags (const char **str, const char *flags);
|
|
|
|
/* qcs_flags struct regroups the flags parsed by parse_flags_qcs. */
|
|
|
|
struct qcs_flags
|
|
{
|
|
bool quiet = false;
|
|
bool cont = false;
|
|
bool silent = false;
|
|
};
|
|
|
|
/* A helper function that uses parse_flags to handle the flags qcs :
|
|
A flag -q sets FLAGS->QUIET to true.
|
|
A flag -c sets FLAGS->CONT to true.
|
|
A flag -s sets FLAGS->SILENT to true.
|
|
|
|
The caller is responsible to initialize *FLAGS to false before the (first)
|
|
call to parse_flags_qcs.
|
|
parse_flags_qcs can then be called iteratively to search for more
|
|
valid flags, as part of a 'main parsing loop' searching for -q/-c/-s
|
|
flags together with other flags and options.
|
|
|
|
Returns true and updates *STR and one of FLAGS->QUIET, FLAGS->CONT,
|
|
FLAGS->SILENT if it finds a valid flag.
|
|
Returns false if no valid flag is found at the beginning of STR.
|
|
|
|
Throws an error if a flag is found such that both FLAGS->CONT and
|
|
FLAGS->SILENT are true. */
|
|
|
|
extern bool parse_flags_qcs (const char *which_command, const char **str,
|
|
qcs_flags *flags);
|
|
|
|
#endif /* CLI_CLI_UTILS_H */
|