|  | /* Handle lists of commands, their decoding and documentation, for GDB. | 
|  |  | 
|  | Copyright (C) 1986-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | 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/>.  */ | 
|  |  | 
|  | #include "symtab.h" | 
|  | #include <ctype.h> | 
|  | #include "gdbsupport/gdb_regex.h" | 
|  | #include "completer.h" | 
|  | #include "ui-out.h" | 
|  | #include "cli/cli-cmds.h" | 
|  | #include "cli/cli-decode.h" | 
|  | #include "cli/cli-style.h" | 
|  | #include "cli/cli-utils.h" | 
|  | #include <optional> | 
|  |  | 
|  | /* Prototypes for local functions.  */ | 
|  |  | 
|  | static void undef_cmd_error (const char *, const char *); | 
|  |  | 
|  | static cmd_list_element::aliases_list_type delete_cmd | 
|  | (const char *name, cmd_list_element **list, cmd_list_element **prehook, | 
|  | cmd_list_element **prehookee, cmd_list_element **posthook, | 
|  | cmd_list_element **posthookee); | 
|  |  | 
|  | static struct cmd_list_element *find_cmd (const char *command, | 
|  | int len, | 
|  | struct cmd_list_element *clist, | 
|  | int ignore_help_classes, | 
|  | int *nfound); | 
|  |  | 
|  | static void help_cmd_list (struct cmd_list_element *list, | 
|  | enum command_class theclass, | 
|  | bool recurse, | 
|  | struct ui_file *stream); | 
|  |  | 
|  | static void help_all (struct ui_file *stream); | 
|  |  | 
|  | static int lookup_cmd_composition_1 (const char *text, | 
|  | struct cmd_list_element **alias, | 
|  | struct cmd_list_element **prefix_cmd, | 
|  | struct cmd_list_element **cmd, | 
|  | struct cmd_list_element *cur_list); | 
|  |  | 
|  | /* Look up a command whose 'subcommands' field is SUBCOMMANDS.  Return the | 
|  | command if found, otherwise return NULL.  */ | 
|  |  | 
|  | static struct cmd_list_element * | 
|  | lookup_cmd_with_subcommands (cmd_list_element **subcommands, | 
|  | cmd_list_element *list) | 
|  | { | 
|  | struct cmd_list_element *p = NULL; | 
|  |  | 
|  | for (p = list; p != NULL; p = p->next) | 
|  | { | 
|  | struct cmd_list_element *q; | 
|  |  | 
|  | if (!p->is_prefix ()) | 
|  | continue; | 
|  |  | 
|  | else if (p->subcommands == subcommands) | 
|  | { | 
|  | /* If we found an alias, we must return the aliased | 
|  | command.  */ | 
|  | return p->is_alias () ? p->alias_target : p; | 
|  | } | 
|  |  | 
|  | q = lookup_cmd_with_subcommands (subcommands, *(p->subcommands)); | 
|  | if (q != NULL) | 
|  | return q; | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void | 
|  | print_help_for_command (const cmd_list_element &c, | 
|  | bool recurse, struct ui_file *stream); | 
|  |  | 
|  | static void | 
|  | do_simple_func (const char *args, int from_tty, cmd_list_element *c) | 
|  | { | 
|  | c->function.simple_func (args, from_tty); | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_cmd_simple_func (struct cmd_list_element *cmd, cmd_simple_func_ftype *simple_func) | 
|  | { | 
|  | if (simple_func == NULL) | 
|  | cmd->func = NULL; | 
|  | else | 
|  | cmd->func = do_simple_func; | 
|  |  | 
|  | cmd->function.simple_func = simple_func; | 
|  | } | 
|  |  | 
|  | int | 
|  | cmd_simple_func_eq (struct cmd_list_element *cmd, cmd_simple_func_ftype *simple_func) | 
|  | { | 
|  | return (cmd->func == do_simple_func | 
|  | && cmd->function.simple_func == simple_func); | 
|  | } | 
|  |  | 
|  | void | 
|  | set_cmd_completer (struct cmd_list_element *cmd, completer_ftype *completer) | 
|  | { | 
|  | cmd->completer = completer; /* Ok.  */ | 
|  | } | 
|  |  | 
|  | /* See definition in commands.h.  */ | 
|  |  | 
|  | void | 
|  | set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd, | 
|  | completer_handle_brkchars_ftype *func) | 
|  | { | 
|  | cmd->completer_handle_brkchars = func; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | std::string | 
|  | cmd_list_element::prefixname_no_space () const | 
|  | { | 
|  | if (!this->is_prefix ()) | 
|  | /* Not a prefix command.  */ | 
|  | return ""; | 
|  |  | 
|  | std::string prefixname; | 
|  | if (this->prefix != nullptr) | 
|  | { | 
|  | prefixname = this->prefix->prefixname_no_space (); | 
|  | prefixname += " "; | 
|  | } | 
|  |  | 
|  | prefixname += this->name; | 
|  |  | 
|  | return prefixname; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | std::string | 
|  | cmd_list_element::prefixname () const | 
|  | { | 
|  | std::string result = prefixname_no_space (); | 
|  | if (!result.empty ()) | 
|  | result += " "; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* See cli/cli-decode.h.  */ | 
|  |  | 
|  | std::vector<std::string> | 
|  | cmd_list_element::command_components () const | 
|  | { | 
|  | std::vector<std::string> result; | 
|  |  | 
|  | if (this->prefix != nullptr) | 
|  | result = this->prefix->command_components (); | 
|  |  | 
|  | result.emplace_back (this->name); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME. | 
|  | Space for NAME and DOC must be allocated by the caller. | 
|  | THECLASS is the top level category into which commands are broken down | 
|  | for "help" purposes. | 
|  | FUN should be the function to execute the command; | 
|  | it will get a character string as argument, with leading | 
|  | and trailing blanks already eliminated. | 
|  |  | 
|  | DOC is a documentation string for the command. | 
|  | Its first line should be a complete sentence. | 
|  | It should start with ? for a command that is an abbreviation | 
|  | or with * for a command that most users don't need to know about. | 
|  |  | 
|  | Add this command to command list *LIST. | 
|  |  | 
|  | Returns a pointer to the added command (not necessarily the head | 
|  | of *LIST).  */ | 
|  |  | 
|  | static struct cmd_list_element * | 
|  | do_add_cmd (const char *name, enum command_class theclass, | 
|  | const char *doc, struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *c = new struct cmd_list_element (name, theclass, | 
|  | doc); | 
|  |  | 
|  | /* Turn each alias of the old command into an alias of the new | 
|  | command.  */ | 
|  | c->aliases = delete_cmd (name, list, &c->hook_pre, &c->hookee_pre, | 
|  | &c->hook_post, &c->hookee_post); | 
|  |  | 
|  | for (cmd_list_element &alias : c->aliases) | 
|  | alias.alias_target = c; | 
|  |  | 
|  | if (c->hook_pre) | 
|  | c->hook_pre->hookee_pre = c; | 
|  |  | 
|  | if (c->hookee_pre) | 
|  | c->hookee_pre->hook_pre = c; | 
|  |  | 
|  | if (c->hook_post) | 
|  | c->hook_post->hookee_post = c; | 
|  |  | 
|  | if (c->hookee_post) | 
|  | c->hookee_post->hook_post = c; | 
|  |  | 
|  | if (*list == NULL || strcmp ((*list)->name, name) >= 0) | 
|  | { | 
|  | c->next = *list; | 
|  | *list = c; | 
|  | } | 
|  | else | 
|  | { | 
|  | cmd_list_element *p = *list; | 
|  | while (p->next && strcmp (p->next->name, name) <= 0) | 
|  | { | 
|  | p = p->next; | 
|  | } | 
|  | c->next = p->next; | 
|  | p->next = c; | 
|  | } | 
|  |  | 
|  | /* Search the prefix cmd of C, and assigns it to C->prefix. | 
|  | See also add_prefix_cmd and update_prefix_field_of_prefixed_commands.  */ | 
|  | cmd_list_element *prefixcmd = lookup_cmd_with_subcommands (list, cmdlist); | 
|  | c->prefix = prefixcmd; | 
|  |  | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_cmd (const char *name, enum command_class theclass, | 
|  | const char *doc, struct cmd_list_element **list) | 
|  | { | 
|  | cmd_list_element *result = do_add_cmd (name, theclass, doc, list); | 
|  | result->func = NULL; | 
|  | result->function.simple_func = NULL; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_cmd (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, | 
|  | const char *doc, struct cmd_list_element **list) | 
|  | { | 
|  | cmd_list_element *result = do_add_cmd (name, theclass, doc, list); | 
|  | set_cmd_simple_func (result, fun); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Add an element with a suppress notification to the LIST of commands.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_cmd_suppress_notification (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, const char *doc, | 
|  | struct cmd_list_element **list, | 
|  | bool *suppress_notification) | 
|  | { | 
|  | struct cmd_list_element *element; | 
|  |  | 
|  | element = add_cmd (name, theclass, fun, doc, list); | 
|  | element->suppress_notification = suppress_notification; | 
|  |  | 
|  | return element; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Deprecates a command CMD. | 
|  | REPLACEMENT is the name of the command which should be used in | 
|  | place of this command, or NULL if no such command exists. | 
|  |  | 
|  | This function does not check to see if command REPLACEMENT exists | 
|  | since gdb may not have gotten around to adding REPLACEMENT when | 
|  | this function is called. | 
|  |  | 
|  | Returns a pointer to the deprecated command.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | deprecate_cmd (struct cmd_list_element *cmd, const char *replacement) | 
|  | { | 
|  | cmd->cmd_deprecated = 1; | 
|  | cmd->deprecated_warn_user = 1; | 
|  |  | 
|  | if (replacement != NULL) | 
|  | cmd->replacement = replacement; | 
|  | else | 
|  | cmd->replacement = NULL; | 
|  |  | 
|  | return cmd; | 
|  | } | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_alias_cmd (const char *name, cmd_list_element *target, | 
|  | enum command_class theclass, int abbrev_flag, | 
|  | struct cmd_list_element **list) | 
|  | { | 
|  | gdb_assert (target != nullptr); | 
|  |  | 
|  | struct cmd_list_element *c = add_cmd (name, theclass, target->doc, list); | 
|  |  | 
|  | /* If TARGET->DOC can be freed, we should make another copy.  */ | 
|  | if (target->doc_allocated) | 
|  | { | 
|  | c->doc = xstrdup (target->doc); | 
|  | c->doc_allocated = 1; | 
|  | } | 
|  | /* NOTE: Both FUNC and all the FUNCTIONs need to be copied.  */ | 
|  | c->func = target->func; | 
|  | c->function = target->function; | 
|  | c->subcommands = target->subcommands; | 
|  | c->allow_unknown = target->allow_unknown; | 
|  | c->abbrev_flag = abbrev_flag; | 
|  | c->alias_target = target; | 
|  | target->aliases.push_front (*c); | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  | /* Update the prefix field of all sub-commands of the prefix command C. | 
|  | We must do this when a prefix command is defined as the GDB init sequence | 
|  | does not guarantee that a prefix command is created before its sub-commands. | 
|  | For example, break-catch-sig.c initialization runs before breakpoint.c | 
|  | initialization, but it is breakpoint.c that creates the "catch" command used | 
|  | by the "catch signal" command created by break-catch-sig.c.  */ | 
|  |  | 
|  | static void | 
|  | update_prefix_field_of_prefixed_commands (struct cmd_list_element *c) | 
|  | { | 
|  | for (cmd_list_element *p = *c->subcommands; p != NULL; p = p->next) | 
|  | { | 
|  | p->prefix = c; | 
|  |  | 
|  | /* We must recursively update the prefix field to cover | 
|  | e.g.  'info auto-load libthread-db' where the creation | 
|  | order was: | 
|  | libthread-db | 
|  | auto-load | 
|  | info | 
|  | In such a case, when 'auto-load' was created by do_add_cmd, | 
|  | the 'libthread-db' prefix field could not be updated, as the | 
|  | 'auto-load' command was not yet reachable by | 
|  | lookup_cmd_for_subcommands (list, cmdlist) | 
|  | that searches from the top level 'cmdlist'.  */ | 
|  | if (p->is_prefix ()) | 
|  | update_prefix_field_of_prefixed_commands (p); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Like add_cmd but adds an element for a command prefix: a name that | 
|  | should be followed by a subcommand to be looked up in another | 
|  | command list.  SUBCOMMANDS should be the address of the variable | 
|  | containing that list.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_prefix_cmd (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, | 
|  | const char *doc, struct cmd_list_element **subcommands, | 
|  | int allow_unknown, struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list); | 
|  |  | 
|  | c->subcommands = subcommands; | 
|  | c->allow_unknown = allow_unknown; | 
|  |  | 
|  | /* Now that prefix command C is defined, we need to set the prefix field | 
|  | of all prefixed commands that were defined before C itself was defined.  */ | 
|  | update_prefix_field_of_prefixed_commands (c); | 
|  |  | 
|  | return c; | 
|  | } | 
|  |  | 
|  | /* A helper function for add_basic_prefix_cmd.  This is a command | 
|  | function that just forwards to help_list.  */ | 
|  |  | 
|  | static void | 
|  | do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | /* Look past all aliases.  */ | 
|  | while (c->is_alias ()) | 
|  | c = c->alias_target; | 
|  |  | 
|  | help_list (*c->subcommands, c->prefixname_no_space ().c_str (), | 
|  | all_commands, gdb_stdout); | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_basic_prefix_cmd (const char *name, enum command_class theclass, | 
|  | const char *doc, struct cmd_list_element **subcommands, | 
|  | int allow_unknown, struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr, | 
|  | doc, subcommands, | 
|  | allow_unknown, list); | 
|  | cmd->func = do_prefix_cmd; | 
|  | return cmd; | 
|  | } | 
|  |  | 
|  | /* A helper function for add_show_prefix_cmd.  This is a command | 
|  | function that just forwards to cmd_show_list.  */ | 
|  |  | 
|  | static void | 
|  | do_show_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | cmd_show_list (*c->subcommands, from_tty); | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_show_prefix_cmd (const char *name, enum command_class theclass, | 
|  | const char *doc, struct cmd_list_element **subcommands, | 
|  | int allow_unknown, struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *cmd = add_prefix_cmd (name, theclass, nullptr, | 
|  | doc, subcommands, | 
|  | allow_unknown, list); | 
|  | cmd->func = do_show_prefix_cmd; | 
|  | return cmd; | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_prefix_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | cmd_list_element **set_subcommands_list, | 
|  | cmd_list_element **show_subcommands_list, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands cmds; | 
|  |  | 
|  | cmds.set = add_basic_prefix_cmd (name, theclass, set_doc, | 
|  | set_subcommands_list, 0, | 
|  | set_list); | 
|  | cmds.show = add_show_prefix_cmd (name, theclass, show_doc, | 
|  | show_subcommands_list, 0, | 
|  | show_list); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Like ADD_PREFIX_CMD but sets the suppress_notification pointer on the | 
|  | new command list element.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_prefix_cmd_suppress_notification | 
|  | (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, | 
|  | const char *doc, struct cmd_list_element **subcommands, | 
|  | int allow_unknown, struct cmd_list_element **list, | 
|  | bool *suppress_notification) | 
|  | { | 
|  | struct cmd_list_element *element | 
|  | = add_prefix_cmd (name, theclass, fun, doc, subcommands, | 
|  | allow_unknown, list); | 
|  | element->suppress_notification = suppress_notification; | 
|  | return element; | 
|  | } | 
|  |  | 
|  | /* Like add_prefix_cmd but sets the abbrev_flag on the new command.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_abbrev_prefix_cmd (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, const char *doc, | 
|  | struct cmd_list_element **subcommands, | 
|  | int allow_unknown, struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *c = add_cmd (name, theclass, fun, doc, list); | 
|  |  | 
|  | c->subcommands = subcommands; | 
|  | c->allow_unknown = allow_unknown; | 
|  | c->abbrev_flag = 1; | 
|  | return c; | 
|  | } | 
|  |  | 
|  | /* This is an empty "simple func".  */ | 
|  | void | 
|  | not_just_help_class_command (const char *args, int from_tty) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* This is an empty cmd func.  */ | 
|  |  | 
|  | static void | 
|  | empty_func (const char *args, int from_tty, cmd_list_element *c) | 
|  | { | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to command list LIST (the list for set/show | 
|  | or some sublist thereof). | 
|  | TYPE is set_cmd or show_cmd. | 
|  | THECLASS is as in add_cmd. | 
|  | VAR_TYPE is the kind of thing we are setting. | 
|  | EXTRA_LITERALS if non-NULL define extra literals to be accepted in lieu of | 
|  | a number for integer variables. | 
|  | ARGS is a pre-validated type-erased reference to the variable being | 
|  | controlled by this command. | 
|  | DOC is the documentation string.  */ | 
|  |  | 
|  | static struct cmd_list_element * | 
|  | add_set_or_show_cmd (const char *name, | 
|  | enum cmd_types type, | 
|  | enum command_class theclass, | 
|  | var_types var_type, | 
|  | const literal_def *extra_literals, | 
|  | const setting::erased_args &arg, | 
|  | const char *doc, | 
|  | struct cmd_list_element **list) | 
|  | { | 
|  | struct cmd_list_element *c = add_cmd (name, theclass, doc, list); | 
|  |  | 
|  | gdb_assert (type == set_cmd || type == show_cmd); | 
|  | c->type = type; | 
|  | c->var.emplace (var_type, extra_literals, arg); | 
|  |  | 
|  | /* This needs to be something besides NULL so that this isn't | 
|  | treated as a help class.  */ | 
|  | c->func = empty_func; | 
|  | return c; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. | 
|  | THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are | 
|  | setting.  EXTRA_LITERALS if non-NULL define extra literals to be | 
|  | accepted in lieu of a number for integer variables.  ARGS is a | 
|  | pre-validated type-erased reference to the variable being controlled | 
|  | by this command.  SET_FUNC and SHOW_FUNC are the callback functions | 
|  | (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the documentation | 
|  | strings. | 
|  |  | 
|  | Return the newly created set and show commands.  */ | 
|  |  | 
|  | static set_show_commands | 
|  | add_setshow_cmd_full_erased (const char *name, | 
|  | enum command_class theclass, | 
|  | var_types var_type, | 
|  | const literal_def *extra_literals, | 
|  | const setting::erased_args &args, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | struct cmd_list_element *set; | 
|  | struct cmd_list_element *show; | 
|  | gdb::unique_xmalloc_ptr<char> full_set_doc; | 
|  | gdb::unique_xmalloc_ptr<char> full_show_doc; | 
|  |  | 
|  | if (help_doc != NULL) | 
|  | { | 
|  | full_set_doc = xstrprintf ("%s\n%s", set_doc, help_doc); | 
|  | full_show_doc = xstrprintf ("%s\n%s", show_doc, help_doc); | 
|  | } | 
|  | else | 
|  | { | 
|  | full_set_doc = make_unique_xstrdup (set_doc); | 
|  | full_show_doc = make_unique_xstrdup (show_doc); | 
|  | } | 
|  | set = add_set_or_show_cmd (name, set_cmd, theclass, var_type, | 
|  | extra_literals, args, | 
|  | full_set_doc.release (), set_list); | 
|  | set->doc_allocated = 1; | 
|  |  | 
|  | if (set_func != NULL) | 
|  | set->func = set_func; | 
|  |  | 
|  | show = add_set_or_show_cmd (name, show_cmd, theclass, var_type, | 
|  | extra_literals, args, | 
|  | full_show_doc.release (), show_list); | 
|  | show->doc_allocated = 1; | 
|  | show->show_value_func = show_func; | 
|  | /* Disable the default symbol completer.  Doesn't make much sense | 
|  | for the "show" command to complete on anything.  */ | 
|  | set_cmd_completer (show, nullptr); | 
|  |  | 
|  | return {set, show}; | 
|  | } | 
|  |  | 
|  | /* Completes on integer commands that support extra literals.  */ | 
|  |  | 
|  | static void | 
|  | integer_literals_completer (struct cmd_list_element *c, | 
|  | completion_tracker &tracker, | 
|  | const char *text, const char *word) | 
|  | { | 
|  | const literal_def *extra_literals = c->var->extra_literals (); | 
|  |  | 
|  | if (*text == '\0') | 
|  | { | 
|  | tracker.add_completion (make_unique_xstrdup ("NUMBER")); | 
|  | for (const literal_def *l = extra_literals; | 
|  | l->literal != nullptr; | 
|  | l++) | 
|  | tracker.add_completion (make_unique_xstrdup (l->literal)); | 
|  | } | 
|  | else | 
|  | for (const literal_def *l = extra_literals; | 
|  | l->literal != nullptr; | 
|  | l++) | 
|  | if (startswith (l->literal, text)) | 
|  | tracker.add_completion (make_unique_xstrdup (l->literal)); | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both command lists SET_LIST and SHOW_LIST. | 
|  | THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are | 
|  | setting.  VAR is address of the variable being controlled by this | 
|  | command.  EXTRA_LITERALS if non-NULL define extra literals to be | 
|  | accepted in lieu of a number for integer variables.  If nullptr is | 
|  | given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must | 
|  | be provided.  SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks | 
|  | used to access and modify the underlying property, whatever its | 
|  | storage is.  SET_FUNC and SHOW_FUNC are the callback functions | 
|  | (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the | 
|  | documentation strings. | 
|  |  | 
|  | Return the newly created set and show commands.  */ | 
|  |  | 
|  | template<typename T> | 
|  | static set_show_commands | 
|  | add_setshow_cmd_full (const char *name, | 
|  | enum command_class theclass, | 
|  | var_types var_type, T *var, | 
|  | const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | typename setting_func_types<T>::set set_setting_func, | 
|  | typename setting_func_types<T>::get get_setting_func, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | auto erased_args | 
|  | = setting::erase_args (var_type, var, | 
|  | set_setting_func, get_setting_func); | 
|  | auto cmds = add_setshow_cmd_full_erased (name, | 
|  | theclass, | 
|  | var_type, extra_literals, | 
|  | erased_args, | 
|  | set_doc, show_doc, | 
|  | help_doc, | 
|  | set_func, | 
|  | show_func, | 
|  | set_list, | 
|  | show_list); | 
|  |  | 
|  | if (extra_literals != nullptr) | 
|  | set_cmd_completer (cmds.set, integer_literals_completer); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Same as above but omitting EXTRA_LITERALS.  */ | 
|  |  | 
|  | template<typename T> | 
|  | static set_show_commands | 
|  | add_setshow_cmd_full (const char *name, | 
|  | enum command_class theclass, | 
|  | var_types var_type, T *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | typename setting_func_types<T>::set set_setting_func, | 
|  | typename setting_func_types<T>::get get_setting_func, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | return add_setshow_cmd_full (name, theclass, var_type, var, nullptr, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_setting_func, get_setting_func, | 
|  | set_func, show_func, set_list, show_list); | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to command list LIST (the list for set or | 
|  | some sublist thereof).  THECLASS is as in add_cmd.  ENUMLIST is a list | 
|  | of strings which may follow NAME.  VAR is address of the variable | 
|  | which will contain the matching string (from ENUMLIST).  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_enum_cmd (const char *name, | 
|  | enum command_class theclass, | 
|  | const char *const *enumlist, | 
|  | const char **var, | 
|  | const char *set_doc, | 
|  | const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | /* We require *VAR to be initialized before this call, and | 
|  | furthermore it must be == to one of the values in ENUMLIST.  */ | 
|  | gdb_assert (var != nullptr && *var != nullptr); | 
|  | for (int i = 0; ; ++i) | 
|  | { | 
|  | gdb_assert (enumlist[i] != nullptr); | 
|  | if (*var == enumlist[i]) | 
|  | break; | 
|  | } | 
|  |  | 
|  | set_show_commands commands | 
|  | =  add_setshow_cmd_full<const char *> (name, theclass, var_enum, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | commands.set->enums = enumlist; | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_enum_cmd (const char *name, command_class theclass, | 
|  | const char *const *enumlist, const char *set_doc, | 
|  | const char *show_doc, const char *help_doc, | 
|  | setting_func_types<const char *>::set set_func, | 
|  | setting_func_types<const char *>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<const char *> (name, theclass, var_enum, | 
|  | nullptr, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, | 
|  | nullptr, show_func, set_list, | 
|  | show_list); | 
|  |  | 
|  | cmds.set->enums = enumlist; | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | void | 
|  | complete_on_color (completion_tracker &tracker, | 
|  | const char *text, const char *word) | 
|  | { | 
|  | complete_on_enum (tracker, ui_file_style::basic_color_enums.data (), | 
|  | text, word); | 
|  | if (*text == '\0') | 
|  | { | 
|  | /* Convenience to let the user know what the option | 
|  | can accept.  Note there's no common prefix between | 
|  | the strings on purpose, so that complete_on_enum doesn't do | 
|  | a partial match.  */ | 
|  | tracker.add_completion (make_unique_xstrdup ("NUMBER")); | 
|  | tracker.add_completion (make_unique_xstrdup ("#RRGGBB")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Completer used in color commands.  */ | 
|  |  | 
|  | static void | 
|  | color_completer (struct cmd_list_element *ignore, | 
|  | completion_tracker &tracker, | 
|  | const char *text, const char *word) | 
|  | { | 
|  | complete_on_color (tracker, text, word); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Add element named NAME to command list LIST (the list for set or | 
|  | some sublist thereof).  CLASS is as in add_cmd.  VAR is address | 
|  | of the variable which will contain the color.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_color_cmd (const char *name, | 
|  | enum command_class theclass, | 
|  | ui_file_style::color *var, | 
|  | const char *set_doc, | 
|  | const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands = add_setshow_cmd_full<ui_file_style::color> | 
|  | (name, theclass, var_color, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | set_cmd_completer (commands.set, color_completer); | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_color_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<ui_file_style::color>::set set_func, | 
|  | setting_func_types<ui_file_style::color>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<ui_file_style::color> | 
|  | (name, theclass, var_color, nullptr, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_func, get_func, nullptr, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | set_cmd_completer (cmds.set, color_completer); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  | const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; | 
|  |  | 
|  | /* Add an auto-boolean command named NAME to both the set and show | 
|  | command list lists.  THECLASS is as in add_cmd.  VAR is address of the | 
|  | variable which will contain the value.  DOC is the documentation | 
|  | string.  FUNC is the corresponding callback.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_auto_boolean_cmd (const char *name, | 
|  | enum command_class theclass, | 
|  | enum auto_boolean *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<enum auto_boolean> (name, theclass, var_auto_boolean, | 
|  | var, set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  |  | 
|  | commands.set->enums = auto_boolean_enums; | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_auto_boolean_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<enum auto_boolean>::set set_func, | 
|  | setting_func_types<enum auto_boolean>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<enum auto_boolean> (name, theclass, | 
|  | var_auto_boolean, | 
|  | nullptr, set_doc, | 
|  | show_doc, help_doc, | 
|  | set_func, get_func, | 
|  | nullptr, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | cmds.set->enums = auto_boolean_enums; | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  | const char * const boolean_enums[] = { "on", "off", NULL }; | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  THECLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings. | 
|  | Returns the new command element.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_boolean_cmd (const char *name, enum command_class theclass, bool *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<bool> (name, theclass, var_boolean, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | commands.set->enums = boolean_enums; | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_boolean_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<bool>::set set_func, | 
|  | setting_func_types<bool>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<bool> (name, theclass, var_boolean, nullptr, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_func, get_func, nullptr, | 
|  | show_func, set_list, show_list); | 
|  |  | 
|  | cmds.set->enums = boolean_enums; | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_filename_cmd (const char *name, enum command_class theclass, | 
|  | std::string *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<std::string> (name, theclass, var_filename, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  |  | 
|  | set_cmd_completer (commands.set, deprecated_filename_completer); | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_filename_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<std::string>::set set_func, | 
|  | setting_func_types<std::string>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, var_filename, | 
|  | nullptr, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, | 
|  | nullptr, show_func, set_list, | 
|  | show_list); | 
|  |  | 
|  | set_cmd_completer (cmds.set, deprecated_filename_completer); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_string_cmd (const char *name, enum command_class theclass, | 
|  | std::string *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<std::string> (name, theclass, var_string, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  |  | 
|  | /* Disable the default symbol completer.  */ | 
|  | set_cmd_completer (commands.set, nullptr); | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_string_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<std::string>::set set_func, | 
|  | setting_func_types<std::string>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, var_string, | 
|  | nullptr, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, | 
|  | nullptr, show_func, set_list, | 
|  | show_list); | 
|  |  | 
|  | /* Disable the default symbol completer.  */ | 
|  | set_cmd_completer (cmds.set, nullptr); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_string_noescape_cmd (const char *name, enum command_class theclass, | 
|  | std::string *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<std::string> (name, theclass, var_string_noescape, | 
|  | var, set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | /* Disable the default symbol completer.  */ | 
|  | set_cmd_completer (commands.set, nullptr); | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_string_noescape_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<std::string>::set set_func, | 
|  | setting_func_types<std::string>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<std::string> (name, theclass, | 
|  | var_string_noescape, nullptr, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_func, get_func, | 
|  | nullptr, show_func, set_list, | 
|  | show_list); | 
|  |  | 
|  | /* Disable the default symbol completer.  */ | 
|  | set_cmd_completer (cmds.set, nullptr); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_optional_filename_cmd (const char *name, enum command_class theclass, | 
|  | std::string *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<std::string> (name, theclass, var_optional_filename, | 
|  | var, set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, show_func, | 
|  | set_list, show_list); | 
|  |  | 
|  | set_cmd_completer (commands.set, deprecated_filename_completer); | 
|  |  | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_optional_filename_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<std::string>::set set_func, | 
|  | setting_func_types<std::string>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = | 
|  | add_setshow_cmd_full<std::string> (name, theclass, var_optional_filename, | 
|  | nullptr, set_doc, show_doc, help_doc, | 
|  | set_func, get_func, nullptr, show_func, | 
|  | set_list,show_list); | 
|  |  | 
|  | set_cmd_completer (cmds.set, deprecated_filename_completer); | 
|  |  | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  THECLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings.  This | 
|  | function is only used in Python API.  Please don't use it elsewhere.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_integer_cmd (const char *name, enum command_class theclass, | 
|  | int *var, const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<int> (name, theclass, var_integer, var, | 
|  | extra_literals, set_doc, show_doc, | 
|  | help_doc, nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_integer_cmd (const char *name, command_class theclass, | 
|  | const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<int>::set set_func, | 
|  | setting_func_types<int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | 
|  | extra_literals, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, nullptr, | 
|  | show_func, set_list, show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Accept `unlimited' or 0, translated internally to INT_MAX.  */ | 
|  | const literal_def integer_unlimited_literals[] = | 
|  | { | 
|  | { "unlimited", INT_MAX, 0 }, | 
|  | { nullptr } | 
|  | }; | 
|  |  | 
|  | /* Same as above but using `integer_unlimited_literals', with a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_integer_cmd (const char *name, enum command_class theclass, | 
|  | int *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<int> (name, theclass, var_integer, var, | 
|  | integer_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_integer_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<int>::set set_func, | 
|  | setting_func_types<int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | 
|  | integer_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, set_func, | 
|  | get_func, nullptr, show_func, set_list, | 
|  | show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  CLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_pinteger_cmd (const char *name, enum command_class theclass, | 
|  | int *var, const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, | 
|  | extra_literals, set_doc, show_doc, | 
|  | help_doc, nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_pinteger_cmd (const char *name, command_class theclass, | 
|  | const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<int>::set set_func, | 
|  | setting_func_types<int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, | 
|  | extra_literals, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, nullptr, | 
|  | show_func, set_list, show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  THECLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_uinteger_cmd (const char *name, enum command_class theclass, | 
|  | unsigned int *var, const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, | 
|  | extra_literals, set_doc, show_doc, | 
|  | help_doc, nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_uinteger_cmd (const char *name, command_class theclass, | 
|  | const literal_def *extra_literals, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<unsigned int>::set set_func, | 
|  | setting_func_types<unsigned int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | 
|  | nullptr, extra_literals, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_func, get_func, nullptr, | 
|  | show_func, set_list, | 
|  | show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Accept `unlimited' or 0, translated internally to UINT_MAX.  */ | 
|  | const literal_def uinteger_unlimited_literals[] = | 
|  | { | 
|  | { "unlimited", UINT_MAX, 0 }, | 
|  | { nullptr } | 
|  | }; | 
|  |  | 
|  | /* Same as above but using `uinteger_unlimited_literals', with a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_uinteger_cmd (const char *name, enum command_class theclass, | 
|  | unsigned int *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var, | 
|  | uinteger_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, nullptr, | 
|  | nullptr, set_func, show_func, | 
|  | set_list, show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_uinteger_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<unsigned int>::set set_func, | 
|  | setting_func_types<unsigned int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | 
|  | nullptr, | 
|  | uinteger_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, | 
|  | set_func, get_func, nullptr, | 
|  | show_func, set_list, | 
|  | show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  THECLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zinteger_cmd (const char *name, enum command_class theclass, | 
|  | int *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | return add_setshow_cmd_full<int> (name, theclass, var_integer, var, | 
|  | set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zinteger_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<int>::set set_func, | 
|  | setting_func_types<int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr, | 
|  | set_doc, show_doc, help_doc, set_func, | 
|  | get_func, nullptr, show_func, set_list, | 
|  | show_list); | 
|  | } | 
|  |  | 
|  | /* Accept `unlimited' or -1, using -1 internally.  */ | 
|  | const literal_def pinteger_unlimited_literals[] = | 
|  | { | 
|  | { "unlimited", -1, -1 }, | 
|  | { nullptr } | 
|  | }; | 
|  |  | 
|  | /* Same as above but using `pinteger_unlimited_literals', with a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zuinteger_unlimited_cmd (const char *name, | 
|  | enum command_class theclass, | 
|  | int *var, | 
|  | const char *set_doc, | 
|  | const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | set_show_commands commands | 
|  | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var, | 
|  | pinteger_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, nullptr, | 
|  | nullptr, set_func, show_func, set_list, | 
|  | show_list); | 
|  | return commands; | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zuinteger_unlimited_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<int>::set set_func, | 
|  | setting_func_types<int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | auto cmds | 
|  | = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr, | 
|  | pinteger_unlimited_literals, | 
|  | set_doc, show_doc, help_doc, set_func, | 
|  | get_func, nullptr, show_func, set_list, | 
|  | show_list); | 
|  | return cmds; | 
|  | } | 
|  |  | 
|  | /* Add element named NAME to both the set and show command LISTs (the | 
|  | list for set/show or some sublist thereof).  THECLASS is as in | 
|  | add_cmd.  VAR is address of the variable which will contain the | 
|  | value.  SET_DOC and SHOW_DOC are the documentation strings.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zuinteger_cmd (const char *name, enum command_class theclass, | 
|  | unsigned int *var, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | cmd_func_ftype *set_func, | 
|  | show_value_ftype *show_func, | 
|  | struct cmd_list_element **set_list, | 
|  | struct cmd_list_element **show_list) | 
|  | { | 
|  | return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | 
|  | var, set_doc, show_doc, help_doc, | 
|  | nullptr, nullptr, set_func, | 
|  | show_func, set_list, show_list); | 
|  | } | 
|  |  | 
|  | /* Same as above but using a getter and a setter function instead of a pointer | 
|  | to a global storage buffer.  */ | 
|  |  | 
|  | set_show_commands | 
|  | add_setshow_zuinteger_cmd (const char *name, command_class theclass, | 
|  | const char *set_doc, const char *show_doc, | 
|  | const char *help_doc, | 
|  | setting_func_types<unsigned int>::set set_func, | 
|  | setting_func_types<unsigned int>::get get_func, | 
|  | show_value_ftype *show_func, | 
|  | cmd_list_element **set_list, | 
|  | cmd_list_element **show_list) | 
|  | { | 
|  | return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, | 
|  | nullptr, set_doc, show_doc, | 
|  | help_doc, set_func, get_func, | 
|  | nullptr, show_func, set_list, | 
|  | show_list); | 
|  | } | 
|  |  | 
|  | /* Remove the command named NAME from the command list.  Return the list | 
|  | commands which were aliased to the deleted command.  The various *HOOKs are | 
|  | set to the pre- and post-hook commands for the deleted command.  If the | 
|  | command does not have a hook, the corresponding out parameter is set to | 
|  | NULL.  */ | 
|  |  | 
|  | static cmd_list_element::aliases_list_type | 
|  | delete_cmd (const char *name, struct cmd_list_element **list, | 
|  | struct cmd_list_element **prehook, | 
|  | struct cmd_list_element **prehookee, | 
|  | struct cmd_list_element **posthook, | 
|  | struct cmd_list_element **posthookee) | 
|  | { | 
|  | struct cmd_list_element *iter; | 
|  | struct cmd_list_element **previous_chain_ptr; | 
|  | cmd_list_element::aliases_list_type aliases; | 
|  |  | 
|  | *prehook = NULL; | 
|  | *prehookee = NULL; | 
|  | *posthook = NULL; | 
|  | *posthookee = NULL; | 
|  | previous_chain_ptr = list; | 
|  |  | 
|  | for (iter = *previous_chain_ptr; iter; iter = *previous_chain_ptr) | 
|  | { | 
|  | if (strcmp (iter->name, name) == 0) | 
|  | { | 
|  | if (iter->destroyer) | 
|  | iter->destroyer (iter, iter->context ()); | 
|  |  | 
|  | if (iter->hookee_pre) | 
|  | iter->hookee_pre->hook_pre = 0; | 
|  | *prehook = iter->hook_pre; | 
|  | *prehookee = iter->hookee_pre; | 
|  | if (iter->hookee_post) | 
|  | iter->hookee_post->hook_post = 0; | 
|  | *posthook = iter->hook_post; | 
|  | *posthookee = iter->hookee_post; | 
|  |  | 
|  | /* Update the link.  */ | 
|  | *previous_chain_ptr = iter->next; | 
|  |  | 
|  | aliases = std::move (iter->aliases); | 
|  |  | 
|  | /* If this command was an alias, remove it from the list of | 
|  | aliases.  */ | 
|  | if (iter->is_alias ()) | 
|  | { | 
|  | auto it = iter->alias_target->aliases.iterator_to (*iter); | 
|  | iter->alias_target->aliases.erase (it); | 
|  | } | 
|  |  | 
|  | delete iter; | 
|  |  | 
|  | /* We won't see another command with the same name.  */ | 
|  | break; | 
|  | } | 
|  | else | 
|  | previous_chain_ptr = &iter->next; | 
|  | } | 
|  |  | 
|  | return aliases; | 
|  | } | 
|  |  | 
|  | /* Shorthands to the commands above.  */ | 
|  |  | 
|  | /* Add an element to the list of info subcommands.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_info (const char *name, cmd_simple_func_ftype *fun, const char *doc) | 
|  | { | 
|  | return add_cmd (name, class_info, fun, doc, &infolist); | 
|  | } | 
|  |  | 
|  | /* Add an alias to the list of info subcommands.  */ | 
|  |  | 
|  | cmd_list_element * | 
|  | add_info_alias (const char *name, cmd_list_element *target, int abbrev_flag) | 
|  | { | 
|  | return add_alias_cmd (name, target, class_run, abbrev_flag, &infolist); | 
|  | } | 
|  |  | 
|  | /* Add an element to the list of commands.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_com (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, | 
|  | const char *doc) | 
|  | { | 
|  | return add_cmd (name, theclass, fun, doc, &cmdlist); | 
|  | } | 
|  |  | 
|  | /* Add an alias or abbreviation command to the list of commands. | 
|  | For aliases predefined by GDB (such as bt), THECLASS must be | 
|  | different of class_alias, as class_alias is used to identify | 
|  | user defined aliases.  */ | 
|  |  | 
|  | cmd_list_element * | 
|  | add_com_alias (const char *name, cmd_list_element *target, | 
|  | command_class theclass, int abbrev_flag) | 
|  | { | 
|  | return add_alias_cmd (name, target, theclass, abbrev_flag, &cmdlist); | 
|  | } | 
|  |  | 
|  | /* Add an element with a suppress notification to the list of commands.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | add_com_suppress_notification (const char *name, enum command_class theclass, | 
|  | cmd_simple_func_ftype *fun, const char *doc, | 
|  | bool *suppress_notification) | 
|  | { | 
|  | return add_cmd_suppress_notification (name, theclass, fun, doc, | 
|  | &cmdlist, suppress_notification); | 
|  | } | 
|  |  | 
|  | /* Print the prefix of C followed by name of C in command style.  */ | 
|  |  | 
|  | static void | 
|  | fput_command_name_styled (const cmd_list_element &c, struct ui_file *stream) | 
|  | { | 
|  | std::string prefixname | 
|  | = c.prefix == nullptr ? "" : c.prefix->prefixname (); | 
|  |  | 
|  | fprintf_styled (stream, command_style.style (), "%s%s", | 
|  | prefixname.c_str (), c.name); | 
|  | } | 
|  |  | 
|  | /* True if ALIAS has a user-defined documentation.  */ | 
|  |  | 
|  | static bool | 
|  | user_documented_alias (const cmd_list_element &alias) | 
|  | { | 
|  | gdb_assert (alias.is_alias ()); | 
|  | /* Alias is user documented if it has an allocated documentation | 
|  | that differs from the aliased command.  */ | 
|  | return (alias.doc_allocated | 
|  | && strcmp (alias.doc, alias.alias_target->doc) != 0); | 
|  | } | 
|  |  | 
|  | /* Print the definition of alias C using title style for alias | 
|  | and aliased command.  */ | 
|  |  | 
|  | static void | 
|  | fput_alias_definition_styled (const cmd_list_element &c, | 
|  | struct ui_file *stream) | 
|  | { | 
|  | gdb_assert (c.is_alias ()); | 
|  | gdb_puts ("  alias ", stream); | 
|  | fput_command_name_styled (c, stream); | 
|  | gdb_printf (stream, " = "); | 
|  | fput_command_name_styled (*c.alias_target, stream); | 
|  | gdb_printf (stream, " %s\n", c.default_args.c_str ()); | 
|  | } | 
|  |  | 
|  | /* Print the definition of CMD aliases not deprecated and having default args | 
|  | and not specifically documented by the user.  */ | 
|  |  | 
|  | static void | 
|  | fput_aliases_definition_styled (const cmd_list_element &cmd, | 
|  | struct ui_file *stream) | 
|  | { | 
|  | for (const cmd_list_element &alias : cmd.aliases) | 
|  | if (!alias.cmd_deprecated | 
|  | && !user_documented_alias (alias) | 
|  | && !alias.default_args.empty ()) | 
|  | fput_alias_definition_styled (alias, stream); | 
|  | } | 
|  |  | 
|  | /* If C has one or more aliases, style print the name of C and the name of its | 
|  | aliases not documented specifically by the user, separated by commas. | 
|  | If ALWAYS_FPUT_C_NAME, print the name of C even if it has no aliases. | 
|  | If one or more names are printed, POSTFIX is printed after the last name. | 
|  | */ | 
|  |  | 
|  | static void | 
|  | fput_command_names_styled (const cmd_list_element &c, | 
|  | bool always_fput_c_name, const char *postfix, | 
|  | struct ui_file *stream) | 
|  | { | 
|  | /* First, check if we are going to print something.  That is, either if | 
|  | ALWAYS_FPUT_C_NAME is true or if there exists at least one non-deprecated | 
|  | alias not documented specifically by the user.  */ | 
|  |  | 
|  | auto print_alias = [] (const cmd_list_element &alias) | 
|  | { | 
|  | return !alias.cmd_deprecated && !user_documented_alias (alias); | 
|  | }; | 
|  |  | 
|  | bool print_something = always_fput_c_name; | 
|  | if (!print_something) | 
|  | for (const cmd_list_element &alias : c.aliases) | 
|  | { | 
|  | if (!print_alias (alias)) | 
|  | continue; | 
|  |  | 
|  | print_something = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (print_something) | 
|  | fput_command_name_styled (c, stream); | 
|  |  | 
|  | for (const cmd_list_element &alias : c.aliases) | 
|  | { | 
|  | if (!print_alias (alias)) | 
|  | continue; | 
|  |  | 
|  | gdb_puts (", ", stream); | 
|  | stream->wrap_here (3); | 
|  | fput_command_name_styled (alias, stream); | 
|  | } | 
|  |  | 
|  | if (print_something) | 
|  | gdb_puts (postfix, stream); | 
|  | } | 
|  |  | 
|  | /* If VERBOSE, print the full help for command C and highlight the | 
|  | documentation parts matching HIGHLIGHT, | 
|  | otherwise print only one-line help for command C.  */ | 
|  |  | 
|  | static void | 
|  | print_doc_of_command (const cmd_list_element &c, bool verbose, | 
|  | compiled_regex &highlight, struct ui_file *stream) | 
|  | { | 
|  | /* When printing the full documentation, add a line to separate | 
|  | this documentation from the previous command help, in the likely | 
|  | case that apropos finds several commands.  */ | 
|  | if (verbose) | 
|  | gdb_puts ("\n", stream); | 
|  |  | 
|  | fput_command_names_styled (c, true, | 
|  | verbose ? "" : " -- ", stream); | 
|  | if (verbose) | 
|  | { | 
|  | gdb_puts ("\n", stream); | 
|  | fput_aliases_definition_styled (c, stream); | 
|  | fputs_highlighted (c.doc, highlight, stream); | 
|  | gdb_puts ("\n", stream); | 
|  | } | 
|  | else | 
|  | { | 
|  | print_doc_line (stream, c.doc, false); | 
|  | gdb_puts ("\n", stream); | 
|  | fput_aliases_definition_styled (c, stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Recursively walk the commandlist structures, and print out the | 
|  | documentation of commands that match our regex in either their | 
|  | name, or their documentation. | 
|  | If VERBOSE, prints the complete documentation and highlight the | 
|  | documentation parts matching REGEX, otherwise prints only | 
|  | the first line. | 
|  | */ | 
|  | void | 
|  | apropos_cmd (struct ui_file *stream, | 
|  | struct cmd_list_element *commandlist, | 
|  | bool verbose, compiled_regex ®ex) | 
|  | { | 
|  | struct cmd_list_element *c; | 
|  | int returnvalue; | 
|  |  | 
|  | /* Walk through the commands.  */ | 
|  | for (c=commandlist;c;c=c->next) | 
|  | { | 
|  | if (c->is_alias () && !user_documented_alias (*c)) | 
|  | { | 
|  | /* Command aliases/abbreviations not specifically documented by the | 
|  | user are skipped to ensure we print the doc of a command only once, | 
|  | when encountering the aliased command.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | returnvalue = -1; /* Needed to avoid double printing.  */ | 
|  | if (c->name != NULL) | 
|  | { | 
|  | size_t name_len = strlen (c->name); | 
|  |  | 
|  | /* Try to match against the name.  */ | 
|  | returnvalue = regex.search (c->name, name_len, 0, name_len, NULL); | 
|  | if (returnvalue >= 0) | 
|  | print_doc_of_command (*c, verbose, regex, stream); | 
|  |  | 
|  | /* Try to match against the name of the aliases.  */ | 
|  | for (const cmd_list_element &alias : c->aliases) | 
|  | { | 
|  | name_len = strlen (alias.name); | 
|  | returnvalue = regex.search (alias.name, name_len, 0, name_len, NULL); | 
|  | if (returnvalue >= 0) | 
|  | { | 
|  | print_doc_of_command (*c, verbose, regex, stream); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (c->doc != NULL && returnvalue < 0) | 
|  | { | 
|  | size_t doc_len = strlen (c->doc); | 
|  |  | 
|  | /* Try to match against documentation.  */ | 
|  | if (regex.search (c->doc, doc_len, 0, doc_len, NULL) >= 0) | 
|  | print_doc_of_command (*c, verbose, regex, stream); | 
|  | } | 
|  | /* Check if this command has subcommands.  */ | 
|  | if (c->is_prefix ()) | 
|  | { | 
|  | /* Recursively call ourselves on the subcommand list, | 
|  | passing the right prefix in.  */ | 
|  | apropos_cmd (stream, *c->subcommands, verbose, regex); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This command really has to deal with two things: | 
|  | 1) I want documentation on *this string* (usually called by | 
|  | "help commandname"). | 
|  |  | 
|  | 2) I want documentation on *this list* (usually called by giving a | 
|  | command that requires subcommands.  Also called by saying just | 
|  | "help".) | 
|  |  | 
|  | I am going to split this into two separate commands, help_cmd and | 
|  | help_list.  */ | 
|  |  | 
|  | void | 
|  | help_cmd (const char *command, struct ui_file *stream) | 
|  | { | 
|  | struct cmd_list_element *c, *alias, *prefix_cmd, *c_cmd; | 
|  |  | 
|  | if (!command) | 
|  | { | 
|  | help_list (cmdlist, "", all_classes, stream); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (strcmp (command, "all") == 0) | 
|  | { | 
|  | help_all (stream); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const char *orig_command = command; | 
|  | c = lookup_cmd (&command, cmdlist, "", NULL, 0, 0); | 
|  |  | 
|  | if (c == 0) | 
|  | return; | 
|  |  | 
|  | lookup_cmd_composition (orig_command, &alias, &prefix_cmd, &c_cmd); | 
|  |  | 
|  | /* There are three cases here. | 
|  | If c->subcommands is nonzero, we have a prefix command. | 
|  | Print its documentation, then list its subcommands. | 
|  |  | 
|  | If c->func is non NULL, we really have a command.  Print its | 
|  | documentation and return. | 
|  |  | 
|  | If c->func is NULL, we have a class name.  Print its | 
|  | documentation (as if it were a command) and then set class to the | 
|  | number of this class so that the commands in the class will be | 
|  | listed.  */ | 
|  |  | 
|  | if (alias == nullptr || !user_documented_alias (*alias)) | 
|  | { | 
|  | /* Case of a normal command, or an alias not explicitly | 
|  | documented by the user.  */ | 
|  | /* If the user asked 'help somecommand' and there is no alias, | 
|  | the false indicates to not output the (single) command name.  */ | 
|  | fput_command_names_styled (*c, false, "\n", stream); | 
|  | fput_aliases_definition_styled (*c, stream); | 
|  | gdb_puts (c->doc, stream); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Case of an alias explicitly documented by the user. | 
|  | Only output the alias definition and its explicit documentation.  */ | 
|  | fput_alias_definition_styled (*alias, stream); | 
|  | fput_command_names_styled (*alias, false, "\n", stream); | 
|  | gdb_puts (alias->doc, stream); | 
|  | } | 
|  | gdb_puts ("\n", stream); | 
|  |  | 
|  | if (!c->is_prefix () && !c->is_command_class_help ()) | 
|  | return; | 
|  |  | 
|  | gdb_printf (stream, "\n"); | 
|  |  | 
|  | /* If this is a prefix command, print it's subcommands.  */ | 
|  | if (c->is_prefix ()) | 
|  | help_list (*c->subcommands, c->prefixname_no_space ().c_str (), | 
|  | all_commands, stream); | 
|  |  | 
|  | /* If this is a class name, print all of the commands in the class.  */ | 
|  | if (c->is_command_class_help ()) | 
|  | help_list (cmdlist, "", c->theclass, stream); | 
|  |  | 
|  | if (c->hook_pre || c->hook_post) | 
|  | gdb_printf (stream, | 
|  | "\nThis command has a hook (or hooks) defined:\n"); | 
|  |  | 
|  | if (c->hook_pre) | 
|  | gdb_printf (stream, | 
|  | "\tThis command is run after  : %s (pre hook)\n", | 
|  | c->hook_pre->name); | 
|  | if (c->hook_post) | 
|  | gdb_printf (stream, | 
|  | "\tThis command is run before : %s (post hook)\n", | 
|  | c->hook_post->name); | 
|  | } | 
|  |  | 
|  | /* Get a specific kind of help on a command list. | 
|  |  | 
|  | LIST is the list. | 
|  | CMDTYPE is the prefix to use in the title string.  It should not | 
|  | end in a space. | 
|  | THECLASS is the class with which to list the nodes of this list (see | 
|  | documentation for help_cmd_list below),  As usual, ALL_COMMANDS for | 
|  | everything, ALL_CLASSES for just classes, and non-negative for only things | 
|  | in a specific class. | 
|  | and STREAM is the output stream on which to print things. | 
|  | If you call this routine with a class >= 0, it recurses.  */ | 
|  | void | 
|  | help_list (struct cmd_list_element *list, const char *cmdtype, | 
|  | enum command_class theclass, struct ui_file *stream) | 
|  | { | 
|  | int len = strlen (cmdtype); | 
|  | const char *space = ""; | 
|  | const char *prefix = ""; | 
|  | if (len > 0) | 
|  | { | 
|  | prefix = "sub"; | 
|  | space = " "; | 
|  | } | 
|  |  | 
|  | if (theclass == all_classes) | 
|  | gdb_printf (stream, "List of classes of %scommands:\n\n", | 
|  | prefix); | 
|  | else if (len == 0) | 
|  | gdb_printf (stream, "List of commands:\n\n"); | 
|  | else | 
|  | gdb_printf (stream, "List of \"%ps\" %scommands:\n\n", | 
|  | styled_string (command_style.style (), cmdtype), | 
|  | prefix); | 
|  |  | 
|  | help_cmd_list (list, theclass, theclass >= 0, stream); | 
|  |  | 
|  | if (theclass == all_classes) | 
|  | { | 
|  | gdb_printf (stream, "\n\ | 
|  | Type \"%p[help%s%s%p]\" followed by a class name for a list of commands in ", | 
|  | command_style.style ().ptr (), | 
|  | space, cmdtype, | 
|  | nullptr); | 
|  | stream->wrap_here (0); | 
|  | gdb_printf (stream, "that class."); | 
|  |  | 
|  | gdb_printf (stream, "\n\ | 
|  | Type \"%ps\" for the list of all commands.", | 
|  | styled_string (command_style.style (), "help all")); | 
|  | } | 
|  |  | 
|  | gdb_printf (stream, "\nType \"%p[help%s%s%p]\" followed by %scommand name ", | 
|  | command_style.style ().ptr (), space, cmdtype, nullptr, | 
|  | prefix); | 
|  | stream->wrap_here (0); | 
|  | gdb_puts ("for ", stream); | 
|  | stream->wrap_here (0); | 
|  | gdb_puts ("full ", stream); | 
|  | stream->wrap_here (0); | 
|  | gdb_puts ("documentation.\n", stream); | 
|  | gdb_printf (stream, | 
|  | "Type \"%ps\" to search " | 
|  | "for commands related to \"word\".\n", | 
|  | styled_string (command_style.style (), "apropos word")); | 
|  | gdb_printf (stream, "Type \"%ps\" for full documentation", | 
|  | styled_string (command_style.style (), "apropos -v word")); | 
|  | stream->wrap_here (0); | 
|  | gdb_puts (" of commands related to \"word\".\n", stream); | 
|  | gdb_puts ("Command name abbreviations are allowed if unambiguous.\n", | 
|  | stream); | 
|  | } | 
|  |  | 
|  | static void | 
|  | help_all (struct ui_file *stream) | 
|  | { | 
|  | struct cmd_list_element *c; | 
|  | int seen_unclassified = 0; | 
|  |  | 
|  | for (c = cmdlist; c; c = c->next) | 
|  | { | 
|  | if (c->abbrev_flag) | 
|  | continue; | 
|  | /* If this is a class name, print all of the commands in the | 
|  | class.  */ | 
|  |  | 
|  | if (c->is_command_class_help ()) | 
|  | { | 
|  | gdb_printf (stream, "\nCommand class: %s\n\n", c->name); | 
|  | help_cmd_list (cmdlist, c->theclass, true, stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* While it's expected that all commands are in some class, | 
|  | as a safety measure, we'll print commands outside of any | 
|  | class at the end.  */ | 
|  |  | 
|  | for (c = cmdlist; c; c = c->next) | 
|  | { | 
|  | if (c->abbrev_flag) | 
|  | continue; | 
|  |  | 
|  | if (c->theclass == no_class) | 
|  | { | 
|  | if (!seen_unclassified) | 
|  | { | 
|  | gdb_printf (stream, "\nUnclassified commands\n\n"); | 
|  | seen_unclassified = 1; | 
|  | } | 
|  | print_help_for_command (*c, true, stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | void | 
|  | print_doc_line (struct ui_file *stream, const char *str, | 
|  | bool for_value_prefix) | 
|  | { | 
|  | static char *line_buffer = 0; | 
|  | static int line_size; | 
|  | const char *p; | 
|  |  | 
|  | if (!line_buffer) | 
|  | { | 
|  | line_size = 80; | 
|  | line_buffer = (char *) xmalloc (line_size); | 
|  | } | 
|  |  | 
|  | /* Searches for the first end of line or the end of STR.  */ | 
|  | p = str; | 
|  | while (*p && *p != '\n') | 
|  | p++; | 
|  | if (p - str > line_size - 1) | 
|  | { | 
|  | line_size = p - str + 1; | 
|  | xfree (line_buffer); | 
|  | line_buffer = (char *) xmalloc (line_size); | 
|  | } | 
|  | strncpy (line_buffer, str, p - str); | 
|  | if (for_value_prefix) | 
|  | { | 
|  | if (islower (line_buffer[0])) | 
|  | line_buffer[0] = toupper (line_buffer[0]); | 
|  | gdb_assert (p > str); | 
|  | if (line_buffer[p - str - 1] == '.') | 
|  | line_buffer[p - str - 1] = '\0'; | 
|  | else | 
|  | line_buffer[p - str] = '\0'; | 
|  | } | 
|  | else | 
|  | line_buffer[p - str] = '\0'; | 
|  | gdb_puts (line_buffer, stream); | 
|  | } | 
|  |  | 
|  | /* Print one-line help for command C. | 
|  | If RECURSE is non-zero, also print one-line descriptions | 
|  | of all prefixed subcommands.  */ | 
|  | static void | 
|  | print_help_for_command (const cmd_list_element &c, | 
|  | bool recurse, struct ui_file *stream) | 
|  | { | 
|  | fput_command_names_styled (c, true, " -- ", stream); | 
|  | print_doc_line (stream, c.doc, false); | 
|  | gdb_puts ("\n", stream); | 
|  | if (!c.default_args.empty ()) | 
|  | fput_alias_definition_styled (c, stream); | 
|  | fput_aliases_definition_styled (c, stream); | 
|  |  | 
|  | if (recurse | 
|  | && c.is_prefix () | 
|  | && c.abbrev_flag == 0) | 
|  | /* Subcommands of a prefix command typically have 'all_commands' | 
|  | as class.  If we pass CLASS to recursive invocation, | 
|  | most often we won't see anything.  */ | 
|  | help_cmd_list (*c.subcommands, all_commands, true, stream); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Implement a help command on command list LIST. | 
|  | * RECURSE should be non-zero if this should be done recursively on | 
|  | * all sublists of LIST. | 
|  | * STREAM is the stream upon which the output should be written. | 
|  | * THECLASS should be: | 
|  | *      A non-negative class number to list only commands in that | 
|  | *      ALL_COMMANDS to list all commands in list. | 
|  | *      ALL_CLASSES  to list all classes in list. | 
|  | * | 
|  | *   Note that aliases are only shown when THECLASS is class_alias. | 
|  | *   In the other cases, the aliases will be shown together with their | 
|  | *   aliased command. | 
|  | * | 
|  | *   Note that RECURSE will be active on *all* sublists, not just the | 
|  | * ones selected by the criteria above (ie. the selection mechanism | 
|  | * is at the low level, not the high-level). | 
|  | */ | 
|  |  | 
|  | static void | 
|  | help_cmd_list (struct cmd_list_element *list, enum command_class theclass, | 
|  | bool recurse, struct ui_file *stream) | 
|  | { | 
|  | struct cmd_list_element *c; | 
|  |  | 
|  | for (c = list; c; c = c->next) | 
|  | { | 
|  | if (c->abbrev_flag == 1 || c->cmd_deprecated) | 
|  | { | 
|  | /* Do not show abbreviations or deprecated commands.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (c->is_alias () && theclass != class_alias) | 
|  | { | 
|  | /* Do not show an alias, unless specifically showing the | 
|  | list of aliases:  for all other classes, an alias is | 
|  | shown (if needed) together with its aliased command.  */ | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (theclass == all_commands | 
|  | || (theclass == all_classes && c->is_command_class_help ()) | 
|  | || (theclass == c->theclass && !c->is_command_class_help ())) | 
|  | { | 
|  | /* show C when | 
|  | - showing all commands | 
|  | - showing all classes and C is a help class | 
|  | - showing commands of THECLASS and C is not the help class  */ | 
|  |  | 
|  | /* If we show the class_alias and C is an alias, do not recurse, | 
|  | as this would show the (possibly very long) not very useful | 
|  | list of sub-commands of the aliased command.  */ | 
|  | print_help_for_command | 
|  | (*c, | 
|  | recurse && (theclass != class_alias || !c->is_alias ()), | 
|  | stream); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (recurse | 
|  | && (theclass == class_user || theclass == class_alias) | 
|  | && c->is_prefix ()) | 
|  | { | 
|  | /* User-defined commands or aliases may be subcommands.  */ | 
|  | help_cmd_list (*c->subcommands, theclass, recurse, stream); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Do not show C or recurse on C, e.g. because C does not belong to | 
|  | THECLASS or because C is a help class.  */ | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Search the input clist for 'command'.  Return the command if | 
|  | found (or NULL if not), and return the number of commands | 
|  | found in nfound.  */ | 
|  |  | 
|  | static struct cmd_list_element * | 
|  | find_cmd (const char *command, int len, struct cmd_list_element *clist, | 
|  | int ignore_help_classes, int *nfound) | 
|  | { | 
|  | struct cmd_list_element *found, *c; | 
|  |  | 
|  | found = NULL; | 
|  | *nfound = 0; | 
|  | for (c = clist; c; c = c->next) | 
|  | if (!strncmp (command, c->name, len) | 
|  | && (!ignore_help_classes || !c->is_command_class_help ())) | 
|  | { | 
|  | found = c; | 
|  | (*nfound)++; | 
|  | if (c->name[len] == '\0') | 
|  | { | 
|  | *nfound = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | return found; | 
|  | } | 
|  |  | 
|  | /* Return the length of command name in TEXT.  */ | 
|  |  | 
|  | int | 
|  | find_command_name_length (const char *text) | 
|  | { | 
|  | const char *p = text; | 
|  |  | 
|  | /* Treating underscores as part of command words is important | 
|  | so that "set args_foo()" doesn't get interpreted as | 
|  | "set args _foo()".  */ | 
|  | /* Some characters are only used for TUI specific commands. | 
|  | However, they are always allowed for the sake of consistency. | 
|  |  | 
|  | Note that this is larger than the character set allowed when | 
|  | creating user-defined commands.  */ | 
|  |  | 
|  | /* Recognize the single character commands so that, e.g., "!ls" | 
|  | works as expected.  */ | 
|  | if (*p == '!' || *p == '|') | 
|  | return 1; | 
|  |  | 
|  | while (valid_cmd_char_p (*p) | 
|  | /* Characters used by TUI specific commands.  */ | 
|  | || *p == '+' || *p == '<' || *p == '>' || *p == '$') | 
|  | p++; | 
|  |  | 
|  | return p - text; | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | bool | 
|  | valid_cmd_char_p (int c) | 
|  | { | 
|  | /* Alas "42" is a legitimate user-defined command. | 
|  | In the interests of not breaking anything we preserve that.  */ | 
|  |  | 
|  | return isalnum (c) || c == '-' || c == '_' || c == '.'; | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | bool | 
|  | valid_user_defined_cmd_name_p (const char *name) | 
|  | { | 
|  | const char *p; | 
|  |  | 
|  | if (*name == '\0') | 
|  | return false; | 
|  |  | 
|  | for (p = name; *p != '\0'; ++p) | 
|  | { | 
|  | if (valid_cmd_char_p (*p)) | 
|  | ; /* Ok.  */ | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | lookup_cmd_1 (const char **text, struct cmd_list_element *clist, | 
|  | struct cmd_list_element **result_list, std::string *default_args, | 
|  | int ignore_help_classes, bool lookup_for_completion_p) | 
|  | { | 
|  | char *command; | 
|  | int len, nfound; | 
|  | struct cmd_list_element *found, *c; | 
|  | bool found_alias = false; | 
|  | const char *line = *text; | 
|  |  | 
|  | while (**text == ' ' || **text == '\t') | 
|  | (*text)++; | 
|  |  | 
|  | /* Identify the name of the command.  */ | 
|  | len = find_command_name_length (*text); | 
|  |  | 
|  | /* If nothing but whitespace, return 0.  */ | 
|  | if (len == 0) | 
|  | return 0; | 
|  |  | 
|  | /* *text and p now bracket the first command word to lookup (and | 
|  | it's length is len).  We copy this into a local temporary.  */ | 
|  |  | 
|  |  | 
|  | command = (char *) alloca (len + 1); | 
|  | memcpy (command, *text, len); | 
|  | command[len] = '\0'; | 
|  |  | 
|  | /* Look it up.  */ | 
|  | found = 0; | 
|  | nfound = 0; | 
|  | found = find_cmd (command, len, clist, ignore_help_classes, &nfound); | 
|  |  | 
|  | /* If nothing matches, we have a simple failure.  */ | 
|  | if (nfound == 0) | 
|  | return 0; | 
|  |  | 
|  | if (nfound > 1) | 
|  | { | 
|  | if (result_list != nullptr) | 
|  | /* Will be modified in calling routine | 
|  | if we know what the prefix command is.  */ | 
|  | *result_list = 0; | 
|  | if (default_args != nullptr) | 
|  | *default_args = std::string (); | 
|  | return CMD_LIST_AMBIGUOUS;	/* Ambiguous.  */ | 
|  | } | 
|  |  | 
|  | /* We've matched something on this list.  Move text pointer forward.  */ | 
|  |  | 
|  | *text += len; | 
|  |  | 
|  | if (found->is_alias ()) | 
|  | { | 
|  | /* We drop the alias (abbreviation) in favor of the command it | 
|  | is pointing to.  If the alias is deprecated, though, we need to | 
|  | warn the user about it before we drop it.  Note that while we | 
|  | are warning about the alias, we may also warn about the command | 
|  | itself and we will adjust the appropriate DEPRECATED_WARN_USER | 
|  | flags.  */ | 
|  |  | 
|  | if (found->deprecated_warn_user && !lookup_for_completion_p) | 
|  | deprecated_cmd_warning (line, clist); | 
|  |  | 
|  |  | 
|  | /* Return the default_args of the alias, not the default_args | 
|  | of the command it is pointing to.  */ | 
|  | if (default_args != nullptr) | 
|  | *default_args = found->default_args; | 
|  | found = found->alias_target; | 
|  | found_alias = true; | 
|  | } | 
|  | /* If we found a prefix command, keep looking.  */ | 
|  |  | 
|  | if (found->is_prefix ()) | 
|  | { | 
|  | c = lookup_cmd_1 (text, *found->subcommands, result_list, default_args, | 
|  | ignore_help_classes, lookup_for_completion_p); | 
|  | if (!c) | 
|  | { | 
|  | /* Didn't find anything; this is as far as we got.  */ | 
|  | if (result_list != nullptr) | 
|  | *result_list = clist; | 
|  | if (!found_alias && default_args != nullptr) | 
|  | *default_args = found->default_args; | 
|  | return found; | 
|  | } | 
|  | else if (c == CMD_LIST_AMBIGUOUS) | 
|  | { | 
|  | /* We've gotten this far properly, but the next step is | 
|  | ambiguous.  We need to set the result list to the best | 
|  | we've found (if an inferior hasn't already set it).  */ | 
|  | if (result_list != nullptr) | 
|  | if (!*result_list) | 
|  | /* This used to say *result_list = *found->subcommands. | 
|  | If that was correct, need to modify the documentation | 
|  | at the top of this function to clarify what is | 
|  | supposed to be going on.  */ | 
|  | *result_list = found; | 
|  | /* For ambiguous commands, do not return any default_args args.  */ | 
|  | if (default_args != nullptr) | 
|  | *default_args = std::string (); | 
|  | return c; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* We matched!  */ | 
|  | return c; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (result_list != nullptr) | 
|  | *result_list = clist; | 
|  | if (!found_alias && default_args != nullptr) | 
|  | *default_args = found->default_args; | 
|  | return found; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* All this hair to move the space to the front of cmdtype */ | 
|  |  | 
|  | static void | 
|  | undef_cmd_error (const char *cmdtype, const char *q) | 
|  | { | 
|  | error (_("Undefined %scommand: \"%s\".  Try \"help%s%.*s\"."), | 
|  | cmdtype, | 
|  | q, | 
|  | *cmdtype ? " " : "", | 
|  | (int) strlen (cmdtype) - 1, | 
|  | cmdtype); | 
|  | } | 
|  |  | 
|  | /* Look up the contents of *LINE as a command in the command list LIST. | 
|  | LIST is a chain of struct cmd_list_element's. | 
|  | If it is found, return the struct cmd_list_element for that command, | 
|  | update *LINE to point after the command name, at the first argument | 
|  | and update *DEFAULT_ARGS (if DEFAULT_ARGS is not null) to the default | 
|  | args to prepend to the user provided args when running the command. | 
|  | Note that if the found cmd_list_element is found via an alias, | 
|  | the default args of the alias are returned. | 
|  |  | 
|  | If not found, call error if ALLOW_UNKNOWN is zero | 
|  | otherwise (or if error returns) return zero. | 
|  | Call error if specified command is ambiguous, | 
|  | unless ALLOW_UNKNOWN is negative. | 
|  | CMDTYPE precedes the word "command" in the error message. | 
|  |  | 
|  | If IGNORE_HELP_CLASSES is nonzero, ignore any command list | 
|  | elements which are actually help classes rather than commands (i.e. | 
|  | the function field of the struct cmd_list_element is 0).  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | lookup_cmd (const char **line, struct cmd_list_element *list, | 
|  | const char *cmdtype, | 
|  | std::string *default_args, | 
|  | int allow_unknown, int ignore_help_classes) | 
|  | { | 
|  | struct cmd_list_element *last_list = 0; | 
|  | struct cmd_list_element *c; | 
|  |  | 
|  | /* Note: Do not remove trailing whitespace here because this | 
|  | would be wrong for complete_command.  Jim Kingdon  */ | 
|  |  | 
|  | if (!*line) | 
|  | error (_("Lack of needed %scommand"), cmdtype); | 
|  |  | 
|  | c = lookup_cmd_1 (line, list, &last_list, default_args, ignore_help_classes); | 
|  |  | 
|  | if (!c) | 
|  | { | 
|  | if (!allow_unknown) | 
|  | { | 
|  | char *q; | 
|  | int len = find_command_name_length (*line); | 
|  |  | 
|  | q = (char *) alloca (len + 1); | 
|  | strncpy (q, *line, len); | 
|  | q[len] = '\0'; | 
|  | undef_cmd_error (cmdtype, q); | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  | else if (c == CMD_LIST_AMBIGUOUS) | 
|  | { | 
|  | /* Ambigous.  Local values should be off subcommands or called | 
|  | values.  */ | 
|  | int local_allow_unknown = (last_list ? last_list->allow_unknown : | 
|  | allow_unknown); | 
|  | std::string local_cmdtype | 
|  | = last_list ? last_list->prefixname () : cmdtype; | 
|  | struct cmd_list_element *local_list = | 
|  | (last_list ? *(last_list->subcommands) : list); | 
|  |  | 
|  | if (local_allow_unknown < 0) | 
|  | { | 
|  | if (last_list) | 
|  | return last_list;	/* Found something.  */ | 
|  | else | 
|  | return 0;		/* Found nothing.  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Report as error.  */ | 
|  | int amb_len; | 
|  | char ambbuf[100]; | 
|  |  | 
|  | for (amb_len = 0; | 
|  | ((*line)[amb_len] && (*line)[amb_len] != ' ' | 
|  | && (*line)[amb_len] != '\t'); | 
|  | amb_len++) | 
|  | ; | 
|  |  | 
|  | ambbuf[0] = 0; | 
|  | for (c = local_list; c; c = c->next) | 
|  | if (!strncmp (*line, c->name, amb_len)) | 
|  | { | 
|  | if (strlen (ambbuf) + strlen (c->name) + 6 | 
|  | < (int) sizeof ambbuf) | 
|  | { | 
|  | if (strlen (ambbuf)) | 
|  | strcat (ambbuf, ", "); | 
|  | strcat (ambbuf, c->name); | 
|  | } | 
|  | else | 
|  | { | 
|  | strcat (ambbuf, ".."); | 
|  | break; | 
|  | } | 
|  | } | 
|  | error (_("Ambiguous %scommand \"%s\": %s."), | 
|  | local_cmdtype.c_str (), *line, ambbuf); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (c->type == set_cmd && **line != '\0' && !isspace (**line)) | 
|  | error (_("Argument must be preceded by space.")); | 
|  |  | 
|  | /* We've got something.  It may still not be what the caller | 
|  | wants (if this command *needs* a subcommand).  */ | 
|  | while (**line == ' ' || **line == '\t') | 
|  | (*line)++; | 
|  |  | 
|  | if (c->is_prefix () && **line && !c->allow_unknown) | 
|  | undef_cmd_error (c->prefixname ().c_str (), *line); | 
|  |  | 
|  | /* Seems to be what he wants.  Return it.  */ | 
|  | return c; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* See command.h.  */ | 
|  |  | 
|  | struct cmd_list_element * | 
|  | lookup_cmd_exact (const char *name, | 
|  | struct cmd_list_element *list, | 
|  | bool ignore_help_classes) | 
|  | { | 
|  | const char *tem = name; | 
|  | struct cmd_list_element *cmd = lookup_cmd (&tem, list, "", NULL, -1, | 
|  | ignore_help_classes); | 
|  | if (cmd != nullptr && strcmp (name, cmd->name) != 0) | 
|  | cmd = nullptr; | 
|  | return cmd; | 
|  | } | 
|  |  | 
|  | /* We are here presumably because an alias or command in TEXT is | 
|  | deprecated and a warning message should be generated.  This | 
|  | function decodes TEXT and potentially generates a warning message | 
|  | as outlined below. | 
|  |  | 
|  | Example for 'set endian big' which has a fictitious alias 'seb'. | 
|  |  | 
|  | If alias wasn't used in TEXT, and the command is deprecated: | 
|  | "warning: 'set endian big' is deprecated." | 
|  |  | 
|  | If alias was used, and only the alias is deprecated: | 
|  | "warning: 'seb' an alias for the command 'set endian big' is deprecated." | 
|  |  | 
|  | If alias was used and command is deprecated (regardless of whether | 
|  | the alias itself is deprecated: | 
|  |  | 
|  | "warning: 'set endian big' (seb) is deprecated." | 
|  |  | 
|  | After the message has been sent, clear the appropriate flags in the | 
|  | command and/or the alias so the user is no longer bothered. | 
|  |  | 
|  | */ | 
|  | void | 
|  | deprecated_cmd_warning (const char *text, struct cmd_list_element *list) | 
|  | { | 
|  | struct cmd_list_element *alias = nullptr; | 
|  | struct cmd_list_element *cmd = nullptr; | 
|  |  | 
|  | /* Return if text doesn't evaluate to a command.  We place this lookup | 
|  | within its own scope so that the PREFIX_CMD local is not visible | 
|  | later in this function.  The value returned in PREFIX_CMD is based on | 
|  | the prefix found in TEXT, and is our case this prefix can be missing | 
|  | in some situations (when LIST is not the global CMDLIST). | 
|  |  | 
|  | It is better for our purposes to use the prefix commands directly from | 
|  | the ALIAS and CMD results.  */ | 
|  | { | 
|  | struct cmd_list_element *prefix_cmd = nullptr; | 
|  | if (!lookup_cmd_composition_1 (text, &alias, &prefix_cmd, &cmd, list)) | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Return if nothing is deprecated.  */ | 
|  | if (!((alias != nullptr ? alias->deprecated_warn_user : 0) | 
|  | || cmd->deprecated_warn_user)) | 
|  | return; | 
|  |  | 
|  | /* Join command prefix (if any) and the command name.  */ | 
|  | std::string tmp_cmd_str; | 
|  | if (cmd->prefix != nullptr) | 
|  | tmp_cmd_str += cmd->prefix->prefixname (); | 
|  | tmp_cmd_str += std::string (cmd->name); | 
|  |  | 
|  | /* Display the appropriate first line, this warns that the thing the user | 
|  | entered is deprecated.  */ | 
|  | if (alias != nullptr) | 
|  | { | 
|  | /* Join the alias prefix (if any) and the alias name.  */ | 
|  | std::string tmp_alias_str; | 
|  | if (alias->prefix != nullptr) | 
|  | tmp_alias_str += alias->prefix->prefixname (); | 
|  | tmp_alias_str += std::string (alias->name); | 
|  |  | 
|  | if (cmd->cmd_deprecated) | 
|  | gdb_printf (_("Warning: command '%ps' (%ps) is deprecated.\n"), | 
|  | styled_string (command_style.style (), | 
|  | tmp_cmd_str.c_str ()), | 
|  | styled_string (command_style.style (), | 
|  | tmp_alias_str.c_str ())); | 
|  | else | 
|  | gdb_printf (_("Warning: '%ps', an alias for the command '%ps', " | 
|  | "is deprecated.\n"), | 
|  | styled_string (command_style.style (), | 
|  | tmp_alias_str.c_str ()), | 
|  | styled_string (command_style.style (), | 
|  | tmp_cmd_str.c_str ())); | 
|  | } | 
|  | else | 
|  | gdb_printf (_("Warning: command '%ps' is deprecated.\n"), | 
|  | styled_string (command_style.style (), | 
|  | tmp_cmd_str.c_str ())); | 
|  |  | 
|  | /* Now display a second line indicating what the user should use instead. | 
|  | If it is only the alias that is deprecated, we want to indicate the | 
|  | new alias, otherwise we'll indicate the new command.  */ | 
|  | const char *replacement; | 
|  | if (alias != nullptr && !cmd->cmd_deprecated) | 
|  | replacement = alias->replacement; | 
|  | else | 
|  | replacement = cmd->replacement; | 
|  | if (replacement != nullptr) | 
|  | gdb_printf (_("Use '%ps'.\n\n"), | 
|  | styled_string (command_style.style (), | 
|  | replacement)); | 
|  | else | 
|  | gdb_printf (_("No alternative known.\n\n")); | 
|  |  | 
|  | /* We've warned you, now we'll keep quiet.  */ | 
|  | if (alias != nullptr) | 
|  | alias->deprecated_warn_user = 0; | 
|  | cmd->deprecated_warn_user = 0; | 
|  | } | 
|  |  | 
|  | /* Look up the contents of TEXT as a command in the command list CUR_LIST. | 
|  | Return 1 on success, 0 on failure. | 
|  |  | 
|  | If TEXT refers to an alias, *ALIAS will point to that alias. | 
|  |  | 
|  | If TEXT is a subcommand (i.e. one that is preceded by a prefix | 
|  | command) set *PREFIX_CMD. | 
|  |  | 
|  | Set *CMD to point to the command TEXT indicates, or to | 
|  | CMD_LIST_AMBIGUOUS if there are multiple possible matches. | 
|  |  | 
|  | If any of *ALIAS, *PREFIX_CMD, or *CMD cannot be determined or do not | 
|  | exist, they are NULL when we return. | 
|  |  | 
|  | */ | 
|  |  | 
|  | static int | 
|  | lookup_cmd_composition_1 (const char *text, | 
|  | struct cmd_list_element **alias, | 
|  | struct cmd_list_element **prefix_cmd, | 
|  | struct cmd_list_element **cmd, | 
|  | struct cmd_list_element *cur_list) | 
|  | { | 
|  | *alias = nullptr; | 
|  | *prefix_cmd = cur_list->prefix; | 
|  | *cmd = nullptr; | 
|  |  | 
|  | text = skip_spaces (text); | 
|  |  | 
|  | /* Go through as many command lists as we need to, to find the command | 
|  | TEXT refers to.  */ | 
|  | while (1) | 
|  | { | 
|  | /* Identify the name of the command.  */ | 
|  | int len = find_command_name_length (text); | 
|  |  | 
|  | /* If nothing but whitespace, return.  */ | 
|  | if (len == 0) | 
|  | return 0; | 
|  |  | 
|  | /* TEXT is the start of the first command word to lookup (and | 
|  | it's length is LEN).  We copy this into a local temporary.  */ | 
|  | std::string command (text, len); | 
|  |  | 
|  | /* Look it up.  */ | 
|  | int nfound = 0; | 
|  | *cmd = find_cmd (command.c_str (), len, cur_list, 1, &nfound); | 
|  |  | 
|  | /* We only handle the case where a single command was found.  */ | 
|  | if (nfound > 1) | 
|  | { | 
|  | *cmd = CMD_LIST_AMBIGUOUS; | 
|  | return 0; | 
|  | } | 
|  | else if (*cmd == nullptr) | 
|  | return 0; | 
|  | else | 
|  | { | 
|  | if ((*cmd)->is_alias ()) | 
|  | { | 
|  | /* If the command was actually an alias, we note that an | 
|  | alias was used (by assigning *ALIAS) and we set *CMD.  */ | 
|  | *alias = *cmd; | 
|  | *cmd = (*cmd)->alias_target; | 
|  | } | 
|  | } | 
|  |  | 
|  | text += len; | 
|  | text = skip_spaces (text); | 
|  |  | 
|  | if ((*cmd)->is_prefix () && *text != '\0') | 
|  | { | 
|  | cur_list = *(*cmd)->subcommands; | 
|  | *prefix_cmd = *cmd; | 
|  | } | 
|  | else | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Look up the contents of TEXT as a command in the command list 'cmdlist'. | 
|  | Return 1 on success, 0 on failure. | 
|  |  | 
|  | If TEXT refers to an alias, *ALIAS will point to that alias. | 
|  |  | 
|  | If TEXT is a subcommand (i.e. one that is preceded by a prefix | 
|  | command) set *PREFIX_CMD. | 
|  |  | 
|  | Set *CMD to point to the command TEXT indicates, or to | 
|  | CMD_LIST_AMBIGUOUS if there are multiple possible matches. | 
|  |  | 
|  | If any of *ALIAS, *PREFIX_CMD, or *CMD cannot be determined or do not | 
|  | exist, they are NULL when we return. | 
|  |  | 
|  | */ | 
|  |  | 
|  | int | 
|  | lookup_cmd_composition (const char *text, | 
|  | struct cmd_list_element **alias, | 
|  | struct cmd_list_element **prefix_cmd, | 
|  | struct cmd_list_element **cmd) | 
|  | { | 
|  | return lookup_cmd_composition_1 (text, alias, prefix_cmd, cmd, cmdlist); | 
|  | } | 
|  |  | 
|  | /* Helper function for SYMBOL_COMPLETION_FUNCTION.  */ | 
|  |  | 
|  | /* Return a vector of char pointers which point to the different | 
|  | possible completions in LIST of TEXT. | 
|  |  | 
|  | WORD points in the same buffer as TEXT, and completions should be | 
|  | returned relative to this position.  For example, suppose TEXT is | 
|  | "foo" and we want to complete to "foobar".  If WORD is "oo", return | 
|  | "oobar"; if WORD is "baz/foo", return "baz/foobar".  */ | 
|  |  | 
|  | void | 
|  | complete_on_cmdlist (struct cmd_list_element *list, | 
|  | completion_tracker &tracker, | 
|  | const char *text, const char *word, | 
|  | int ignore_help_classes) | 
|  | { | 
|  | struct cmd_list_element *ptr; | 
|  | int textlen = strlen (text); | 
|  | int pass; | 
|  | int saw_deprecated_match = 0; | 
|  |  | 
|  | /* We do one or two passes.  In the first pass, we skip deprecated | 
|  | commands.  If we see no matching commands in the first pass, and | 
|  | if we did happen to see a matching deprecated command, we do | 
|  | another loop to collect those.  */ | 
|  | for (pass = 0; pass < 2; ++pass) | 
|  | { | 
|  | bool got_matches = false; | 
|  |  | 
|  | for (ptr = list; ptr; ptr = ptr->next) | 
|  | if (!strncmp (ptr->name, text, textlen) | 
|  | && !ptr->abbrev_flag | 
|  | && (!ignore_help_classes || !ptr->is_command_class_help () | 
|  | || ptr->is_prefix ())) | 
|  | { | 
|  | if (pass == 0) | 
|  | { | 
|  | if (ptr->cmd_deprecated) | 
|  | { | 
|  | saw_deprecated_match = 1; | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | tracker.add_completion | 
|  | (make_completion_match_str (ptr->name, text, word)); | 
|  | got_matches = true; | 
|  | } | 
|  |  | 
|  | if (got_matches) | 
|  | break; | 
|  |  | 
|  | /* If we saw no matching deprecated commands in the first pass, | 
|  | just bail out.  */ | 
|  | if (!saw_deprecated_match) | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Helper function for SYMBOL_COMPLETION_FUNCTION.  */ | 
|  |  | 
|  | /* Add the different possible completions in ENUMLIST of TEXT. | 
|  |  | 
|  | WORD points in the same buffer as TEXT, and completions should be | 
|  | returned relative to this position.  For example, suppose TEXT is "foo" | 
|  | and we want to complete to "foobar".  If WORD is "oo", return | 
|  | "oobar"; if WORD is "baz/foo", return "baz/foobar".  */ | 
|  |  | 
|  | void | 
|  | complete_on_enum (completion_tracker &tracker, | 
|  | const char *const *enumlist, | 
|  | const char *text, const char *word) | 
|  | { | 
|  | int textlen = strlen (text); | 
|  | int i; | 
|  | const char *name; | 
|  |  | 
|  | for (i = 0; (name = enumlist[i]) != NULL; i++) | 
|  | if (strncmp (name, text, textlen) == 0) | 
|  | tracker.add_completion (make_completion_match_str (name, text, word)); | 
|  | } | 
|  |  | 
|  | /* Call the command function.  */ | 
|  | void | 
|  | cmd_func (struct cmd_list_element *cmd, const char *args, int from_tty) | 
|  | { | 
|  | if (!cmd->is_command_class_help ()) | 
|  | { | 
|  | std::optional<scoped_restore_tmpl<bool>> restore_suppress; | 
|  |  | 
|  | if (cmd->suppress_notification != NULL) | 
|  | restore_suppress.emplace (cmd->suppress_notification, true); | 
|  |  | 
|  | cmd->func (args, from_tty, cmd); | 
|  | } | 
|  | else | 
|  | error (_("Invalid command")); | 
|  | } | 
|  |  | 
|  | int | 
|  | cli_user_command_p (struct cmd_list_element *cmd) | 
|  | { | 
|  | return cmd->theclass == class_user && cmd->func == do_simple_func; | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | ui_file_style::color | 
|  | parse_cli_var_color (const char **args) | 
|  | { | 
|  | /* Do a "set" command.  ARG is nullptr if no argument, or the | 
|  | text of the argument.  */ | 
|  |  | 
|  | if (args == nullptr || *args == nullptr || **args == '\0') | 
|  | { | 
|  | std::string msg; | 
|  |  | 
|  | for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i) | 
|  | { | 
|  | msg.append ("\""); | 
|  | msg.append (ui_file_style::basic_color_enums[i]); | 
|  | msg.append ("\", "); | 
|  | } | 
|  |  | 
|  | error (_("Requires an argument. Valid arguments are %sinteger from -1 " | 
|  | "to 255 or an RGB hex triplet in a format #RRGGBB"), | 
|  | msg.c_str ()); | 
|  | } | 
|  |  | 
|  | const char *p = skip_to_space (*args); | 
|  | size_t len = p - *args; | 
|  |  | 
|  | int nmatches = 0; | 
|  | ui_file_style::basic_color match = ui_file_style::NONE; | 
|  | for (int i = 0; ui_file_style::basic_color_enums[i]; ++i) | 
|  | if (strncmp (*args, ui_file_style::basic_color_enums[i], len) == 0) | 
|  | { | 
|  | match = static_cast<ui_file_style::basic_color> (i - 1); | 
|  | if (ui_file_style::basic_color_enums[i][len] == '\0') | 
|  | { | 
|  | nmatches = 1; | 
|  | break; /* Exact match.  */ | 
|  | } | 
|  | else | 
|  | nmatches++; | 
|  | } | 
|  |  | 
|  | if (nmatches == 1) | 
|  | { | 
|  | *args += len; | 
|  | return ui_file_style::color (match); | 
|  | } | 
|  |  | 
|  | if (nmatches > 1) | 
|  | error (_("Ambiguous item \"%.*s\"."), (int) len, *args); | 
|  |  | 
|  | if (**args != '#') | 
|  | { | 
|  | ULONGEST num = get_ulongest (args); | 
|  | if (num > 255) | 
|  | error (_("integer %s out of range"), pulongest (num)); | 
|  | return ui_file_style::color (color_space::XTERM_256COLOR, | 
|  | static_cast<int> (num)); | 
|  | } | 
|  |  | 
|  | /* Try to parse #RRGGBB string.  */ | 
|  | if (len != 7) | 
|  | error_no_arg (_("invalid RGB hex triplet format")); | 
|  |  | 
|  | uint32_t rgb; | 
|  | uint8_t r, g, b; | 
|  | int scanned_chars = 0; | 
|  | int parsed_args = sscanf (*args, "#%6" SCNx32 "%n", | 
|  | &rgb, &scanned_chars); | 
|  |  | 
|  | if (parsed_args != 1 || scanned_chars != 7) | 
|  | error_no_arg (_("invalid RGB hex triplet format")); | 
|  |  | 
|  | gdb_assert ((rgb >> 24) == 0); | 
|  | r = (rgb >> 16) & 0xff; | 
|  | g = (rgb >> 8) & 0xff; | 
|  | b = rgb & 0xff; | 
|  |  | 
|  | *args += len; | 
|  | return ui_file_style::color (r, g, b); | 
|  | } | 
|  |  | 
|  | /* See cli-decode.h.  */ | 
|  |  | 
|  | ui_file_style::color | 
|  | parse_var_color (const char *arg) | 
|  | { | 
|  | const char *end_arg = arg; | 
|  | ui_file_style::color color = parse_cli_var_color (&end_arg); | 
|  |  | 
|  | int len = end_arg - arg; | 
|  | const char *after = skip_spaces (end_arg); | 
|  | if (*after != '\0') | 
|  | error (_("Junk after item \"%.*s\": %s"), len, arg, after); | 
|  |  | 
|  | return color; | 
|  | } |