/* GDB CLI command scripting.
- Copyright (C) 1986-2019 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
#include "cli/cli-script.h"
+#include "cli/cli-style.h"
#include "extension.h"
#include "interps.h"
#include "compile/compile.h"
-#include "common/gdb_string_view.h"
+#include "gdbsupport/gdb_string_view.h"
#include "python/python.h"
#include "guile/guile.h"
static void do_define_command (const char *comname, int from_tty,
const counted_command_line *commands);
-static char *read_next_line (void);
+static const char *read_next_line ();
/* Level of control structure when reading. */
static int control_level;
}
/* An if command. Recursively print both arms before
- continueing. */
+ continuing. */
if (list->control_type == if_control)
{
uiout->field_fmt (NULL, "if %s", list->line);
execute_user_command (struct cmd_list_element *c, const char *args)
{
counted_command_line cmdlines_copy;
- extern unsigned int max_user_call_depth;
/* Ensure that the user commands can't be deleted while they are
executing. */
enum command_control_type
execute_control_command (struct command_line *cmd, int from_tty)
{
+ if (!current_uiout->is_mi_like_p ())
+ return execute_control_command_1 (cmd, from_tty);
+
/* Make sure we use the console uiout. It's possible that we are executing
breakpoint commands while running the MI interpreter. */
interp *console = interp_lookup (current_ui, INTERP_CONSOLE);
recurse_read_control_structure whenever we need to read commands
from stdin. */
-static char *
-read_next_line (void)
+static const char *
+read_next_line ()
{
struct ui *ui = current_ui;
char *prompt_ptr, control_prompt[256];
p = *comname;
while (*p)
{
- if (!isalnum (*p) && *p != '-' && *p != '_')
+ if (!valid_cmd_char_p (*p))
error (_("Junk in argument list: \"%s\""), p);
p++;
}
int q;
if (c->theclass == class_user || c->theclass == class_alias)
- q = query (_("Redefine command \"%s\"? "), c->name);
+ {
+ /* if C is a prefix command that was previously defined,
+ tell the user its subcommands will be kept, and ask
+ if ok to redefine the command. */
+ if (c->prefixlist != nullptr)
+ q = (c->user_commands.get () == nullptr
+ || query (_("Keeping subcommands of prefix command \"%s\".\n"
+ "Redefine command \"%s\"? "), c->name, c->name));
+ else
+ q = query (_("Redefine command \"%s\"? "), c->name);
+ }
else
q = query (_("Really redefine built-in command \"%s\"? "), c->name);
if (!q)
hook_type = CMD_POST_HOOK;
hook_name_size = HOOK_POST_LEN;
}
-
+
if (hook_type != CMD_NO_HOOK)
{
/* Look up cmd it hooks, and verify that we got an exact match. */
else
cmds = *commands;
- newc = add_cmd (comname, class_user, user_defined_command,
- (c && c->theclass == class_user)
- ? c->doc : xstrdup ("User-defined."), list);
- newc->user_commands = std::move (cmds);
+ {
+ struct cmd_list_element **c_prefixlist
+ = c == nullptr ? nullptr : c->prefixlist;
+ const char *c_prefixname = c == nullptr ? nullptr : c->prefixname;
+
+ newc = add_cmd (comname, class_user, user_defined_command,
+ (c != nullptr && c->theclass == class_user)
+ ? c->doc : xstrdup ("User-defined."), list);
+ newc->user_commands = std::move (cmds);
+
+ /* If we define or re-define a command that was previously defined
+ as a prefix, keep the prefix information. */
+ if (c_prefixlist != nullptr)
+ {
+ newc->prefixlist = c_prefixlist;
+ newc->prefixname = c_prefixname;
+ /* allow_unknown: see explanation in equivalent logic in
+ define_prefix_command (). */
+ newc->allow_unknown = newc->user_commands.get () != nullptr;
+ }
+ }
/* If this new command is a hook, then mark both commands as being
tied. */
counted_command_line doclines = read_command_lines (prompt.c_str (),
from_tty, 0, 0);
- if (c->doc)
- xfree ((char *) c->doc);
+ xfree ((char *) c->doc);
{
struct command_line *cl1;
c->doc = doc;
}
}
+
+/* Implementation of the "define-prefix" command. */
+
+static void
+define_prefix_command (const char *comname, int from_tty)
+{
+ struct cmd_list_element *c, **list;
+ const char *tem;
+ const char *comfull;
+
+ comfull = comname;
+ list = validate_comname (&comname);
+
+ /* Look it up, and verify that we got an exact match. */
+ tem = comname;
+ c = lookup_cmd (&tem, *list, "", -1, 1);
+ if (c != nullptr && strcmp (comname, c->name) != 0)
+ c = nullptr;
+
+ if (c != nullptr && c->theclass != class_user)
+ error (_("Command \"%s\" is built-in."), comfull);
+
+ if (c != nullptr && c->prefixlist != nullptr)
+ {
+ /* c is already a user defined prefix command. */
+ return;
+ }
+
+ /* If the command does not exist at all, create it. */
+ if (c == nullptr)
+ {
+ comname = xstrdup (comname);
+ c = add_cmd (comname, class_user, user_defined_command,
+ xstrdup ("User-defined."), list);
+ }
+
+ /* Allocate the c->prefixlist, which marks the command as a prefix
+ command. */
+ c->prefixlist = new struct cmd_list_element*;
+ *(c->prefixlist) = nullptr;
+ c->prefixname = xstrprintf ("%s ", comfull);
+ /* If the prefix command C is not a command, then it must be followed
+ by known subcommands. Otherwise, if C is also a normal command,
+ it can be followed by C args that must not cause a 'subcommand'
+ not recognised error, and thus we must allow unknown. */
+ c->allow_unknown = c->user_commands.get () != nullptr;
+}
+
\f
/* Used to implement source_command. */
show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
struct ui_file *stream)
{
- struct command_line *cmdlines;
+ if (cli_user_command_p (c))
+ {
+ struct command_line *cmdlines = c->user_commands.get ();
+
+ fprintf_filtered (stream, "User %scommand \"",
+ c->prefixlist == NULL ? "" : "prefix ");
+ fprintf_styled (stream, title_style.style (), "%s%s",
+ prefix, name);
+ fprintf_filtered (stream, "\":\n");
+ if (cmdlines)
+ {
+ print_command_lines (current_uiout, cmdlines, 1);
+ fputs_filtered ("\n", stream);
+ }
+ }
if (c->prefixlist != NULL)
{
for (c = *c->prefixlist; c != NULL; c = c->next)
if (c->theclass == class_user || c->prefixlist != NULL)
show_user_1 (c, prefixname, c->name, gdb_stdout);
- return;
}
- cmdlines = c->user_commands.get ();
- fprintf_filtered (stream, "User command \"%s%s\":\n", prefix, name);
-
- if (!cmdlines)
- return;
- print_command_lines (current_uiout, cmdlines, 1);
- fputs_filtered ("\n", stream);
}
+void _initialize_cli_script ();
void
-_initialize_cli_script (void)
+_initialize_cli_script ()
{
- add_com ("document", class_support, document_command, _("\
+ struct cmd_list_element *c;
+
+ /* "document", "define" and "define-prefix" use command_completer,
+ as this helps the user to either type the command name and/or
+ its prefixes. */
+ c = add_com ("document", class_support, document_command, _("\
Document a user-defined command.\n\
Give command name as argument. Give documentation on following lines.\n\
End with a line of just \"end\"."));
+ set_cmd_completer (c, command_completer);
define_cmd_element = add_com ("define", class_support, define_command, _("\
Define a new command name. Command name is argument.\n\
Definition appears on following lines, one command per line.\n\
Commands defined in this way may accept an unlimited number of arguments\n\
accessed via $arg0 .. $argN. $argc tells how many arguments have\n\
been passed."));
+ set_cmd_completer (define_cmd_element, command_completer);
+ c = add_com ("define-prefix", class_support, define_prefix_command,
+ _("\
+Define or mark a command as a user-defined prefix command.\n\
+User defined prefix commands can be used as prefix commands for\n\
+other user defined commands.\n\
+If the command already exists, it is changed to a prefix command."));
+ set_cmd_completer (c, command_completer);
while_cmd_element = add_com ("while", class_support, while_command, _("\
Execute nested commands WHILE the conditional expression is non zero.\n\