aboutsummaryrefslogtreecommitdiff
path: root/gdb/cli/cli-decode.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/cli/cli-decode.c')
-rw-r--r--gdb/cli/cli-decode.c348
1 files changed, 266 insertions, 82 deletions
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 163012a..48a3466 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -1,6 +1,6 @@
/* Handle lists of commands, their decoding and documentation, for GDB.
- Copyright (C) 1986-2024 Free Software Foundation, Inc.
+ Copyright (C) 1986-2025 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
@@ -23,6 +23,7 @@
#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. */
@@ -127,8 +128,10 @@ set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd,
cmd->completer_handle_brkchars = func;
}
+/* See cli-decode.h. */
+
std::string
-cmd_list_element::prefixname () const
+cmd_list_element::prefixname_no_space () const
{
if (!this->is_prefix ())
/* Not a prefix command. */
@@ -136,14 +139,27 @@ cmd_list_element::prefixname () const
std::string prefixname;
if (this->prefix != nullptr)
- prefixname = this->prefix->prefixname ();
+ {
+ prefixname = this->prefix->prefixname_no_space ();
+ prefixname += " ";
+ }
prefixname += this->name;
- prefixname += " ";
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>
@@ -380,7 +396,7 @@ do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c)
while (c->is_alias ())
c = c->alias_target;
- help_list (*c->subcommands, c->prefixname ().c_str (),
+ help_list (*c->subcommands, c->prefixname_no_space ().c_str (),
all_commands, gdb_stdout);
}
@@ -740,6 +756,87 @@ add_setshow_enum_cmd (const char *name, command_class theclass,
}
/* 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
@@ -1530,7 +1627,7 @@ add_com_suppress_notification (const char *name, enum command_class theclass,
&cmdlist, suppress_notification);
}
-/* Print the prefix of C followed by name of C in title style. */
+/* 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)
@@ -1538,7 +1635,7 @@ 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, title_style.style (), "%s%s",
+ fprintf_styled (stream, command_style.style (), "%s%s",
prefixname.c_str (), c.name);
}
@@ -1803,7 +1900,7 @@ help_cmd (const char *command, struct ui_file *stream)
/* If this is a prefix command, print it's subcommands. */
if (c->is_prefix ())
- help_list (*c->subcommands, c->prefixname ().c_str (),
+ 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. */
@@ -1824,71 +1921,72 @@ help_cmd (const char *command, struct ui_file *stream)
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.
- * 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.
- */
+/* 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;
- char *cmdtype1, *cmdtype2;
-
- /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub".
- */
- len = strlen (cmdtype);
- cmdtype1 = (char *) alloca (len + 1);
- cmdtype1[0] = 0;
- cmdtype2 = (char *) alloca (len + 4);
- cmdtype2[0] = 0;
- if (len)
+ int len = strlen (cmdtype);
+ const char *space = "";
+ const char *prefix = "";
+ if (len > 0)
{
- cmdtype1[0] = ' ';
- memcpy (cmdtype1 + 1, cmdtype, len - 1);
- cmdtype1[len] = 0;
- memcpy (cmdtype2, cmdtype, len - 1);
- strcpy (cmdtype2 + len - 1, " sub");
+ prefix = "sub";
+ space = " ";
}
if (theclass == all_classes)
- gdb_printf (stream, "List of classes of %scommands:\n\n", cmdtype2);
+ 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 %scommands:\n\n", cmdtype2);
+ 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 \"help%s\" followed by a class name for a list of commands in ",
- cmdtype1);
+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 \"help all\" for the list of all commands.");
+Type \"%ps\" for the list of all commands.",
+ styled_string (command_style.style (), "help all"));
}
- gdb_printf (stream, "\nType \"help%s\" followed by %scommand name ",
- cmdtype1, cmdtype2);
+ 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_puts ("Type \"apropos word\" to search "
- "for commands related to \"word\".\n", stream);
- gdb_puts ("Type \"apropos -v word\" for full documentation", 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",
@@ -1943,40 +2041,28 @@ 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;
+ const char *p = strchr (str, '\n');
- if (!line_buffer)
- {
- line_size = 80;
- line_buffer = (char *) xmalloc (line_size);
- }
+ /* Only copy the input string if we really need to. */
+ std::optional<std::string> line_buffer;
+ if (p != nullptr)
+ line_buffer = std::string (str, p);
+ else if (for_value_prefix)
+ line_buffer = str;
- /* 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';
+ char &c = (*line_buffer)[0];
+ if (islower (c))
+ c = toupper (c);
+ if (line_buffer->back () == '.')
+ line_buffer->pop_back ();
}
- else
- line_buffer[p - str] = '\0';
- gdb_puts (line_buffer, stream);
+
+ gdb_puts (line_buffer.has_value ()
+ ? line_buffer->c_str ()
+ : str,
+ stream);
}
/* Print one-line help for command C.
@@ -2354,7 +2440,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
}
else if (c == CMD_LIST_AMBIGUOUS)
{
- /* Ambigous. Local values should be off subcommands or called
+ /* Ambiguous. Local values should be off subcommands or called
values. */
int local_allow_unknown = (last_list ? last_list->allow_unknown :
allow_unknown);
@@ -2502,21 +2588,21 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list)
if (cmd->cmd_deprecated)
gdb_printf (_("Warning: command '%ps' (%ps) is deprecated.\n"),
- styled_string (title_style.style (),
+ styled_string (command_style.style (),
tmp_cmd_str.c_str ()),
- styled_string (title_style.style (),
+ 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 (title_style.style (),
+ styled_string (command_style.style (),
tmp_alias_str.c_str ()),
- styled_string (title_style.style (),
+ styled_string (command_style.style (),
tmp_cmd_str.c_str ()));
}
else
gdb_printf (_("Warning: command '%ps' is deprecated.\n"),
- styled_string (title_style.style (),
+ styled_string (command_style.style (),
tmp_cmd_str.c_str ()));
/* Now display a second line indicating what the user should use instead.
@@ -2529,7 +2615,7 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list)
replacement = cmd->replacement;
if (replacement != nullptr)
gdb_printf (_("Use '%ps'.\n\n"),
- styled_string (title_style.style (),
+ styled_string (command_style.style (),
replacement));
else
gdb_printf (_("No alternative known.\n\n"));
@@ -2749,3 +2835,101 @@ 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;
+}