aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog27
-rw-r--r--gdb/NEWS15
-rw-r--r--gdb/cli/cli-cmds.c134
-rw-r--r--gdb/cli/cli-cmds.h15
-rw-r--r--gdb/cli/cli-setshow.c74
-rw-r--r--gdb/cli/cli-setshow.h5
-rw-r--r--gdb/command.h19
-rw-r--r--gdb/doc/ChangeLog8
-rw-r--r--gdb/doc/gdb.texinfo100
-rw-r--r--gdb/maint.c28
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.base/with.c41
-rw-r--r--gdb/testsuite/gdb.base/with.exp289
-rw-r--r--gdb/top.c7
14 files changed, 717 insertions, 50 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4f74038..adc56b4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
2019-07-03 Pedro Alves <palves@redhat.com>
+ * NEWS (New commands): Mention "with" and "maint with".
+ * cli/cli-cmds.c (with_command_1, with_command_completer_1)
+ (with_command, with_command_completer): New.
+ (pipe_command): Adjust to new repeat_previous
+ interface.
+ (_initialize_cli_cmds): Install the "with" command and its "w"
+ alias.
+ * cli/cli-cmds.h (with_command_1, with_command_completer_1): New
+ declarations.
+ * cli/cli-setshow.c (parse_cli_var_uinteger)
+ (parse_cli_var_zuinteger_unlimited, do_set_command): Handle empty
+ argument strings for all var_types.
+ (get_setshow_command_value_string): New, factored out from ...
+ (do_show_command): ... this.
+ * cli/cli-setshow.h: Include <string>.
+ (get_setshow_command_value_string): Declare.
+ * command.h (repeat_previous): Now returns const char *. Adjust
+ comment.
+ * maint.c: Include "cli/cli-cmds.h".
+ (maintenance_with_cmd, maintenance_with_cmd_completer): New.
+ (_initialize_maint_cmds): Register the "maintenance with" command.
+ * top.c (repeat_previous): Move bits from pipe_command here:
+ Return the saved command line, if any; error out if there's no
+ command to relaunch.
+
+2019-07-03 Pedro Alves <palves@redhat.com>
+
* NEWS (New commands): Mention "maint set/show test-settings"
instead of "maint test-settings".
* maint-test-settings.c (maintenance_test_settings_list): Delete.
diff --git a/gdb/NEWS b/gdb/NEWS
index 4a7a117..34c544c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,21 @@ pipe -d DELIM COMMAND DELIM SHELL_COMMAND
With no COMMAND, repeat the last executed command
and send its output to SHELL_COMMAND.
+with SETTING [VALUE] [-- COMMAND]
+w SETTING [VALUE] [-- COMMAND]
+ Temporarily set SETTING, run COMMAND, and restore SETTING.
+ Usage: with SETTING -- COMMAND
+ With no COMMAND, repeats the last executed command.
+ SETTING is any GDB setting you can change with the "set"
+ subcommands. For example, 'with language c -- print someobj'
+ temporarily switches to the C language in order to print someobj.
+ Settings can be combined: 'w lang c -- w print elements unlimited --
+ usercmd' switches to the C language and runs usercmd with no limit
+ of array elements to print.
+
+maint with SETTING [VALUE] [-- COMMAND]
+ Like "with", but works with "maintenance set" settings.
+
set may-call-functions [on|off]
show may-call-functions
This controls whether GDB will attempt to call functions in
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 5124ab3..d1ecd62 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -211,6 +211,116 @@ show_command (const char *arg, int from_tty)
cmd_show_list (showlist, from_tty, "");
}
+/* See cli/cli-cmds.h. */
+
+void
+with_command_1 (const char *set_cmd_prefix,
+ cmd_list_element *setlist, const char *args, int from_tty)
+{
+ const char *delim = strstr (args, "--");
+ const char *nested_cmd = nullptr;
+
+ if (delim == args)
+ error (_("Missing setting before '--' delimiter"));
+
+ if (delim == nullptr || *skip_spaces (&delim[2]) == '\0')
+ nested_cmd = repeat_previous ();
+
+ cmd_list_element *set_cmd = lookup_cmd (&args, setlist, set_cmd_prefix,
+ /*allow_unknown=*/ 0,
+ /*ignore_help_classes=*/ 1);
+ gdb_assert (set_cmd != nullptr);
+
+ if (set_cmd->var == nullptr)
+ error (_("Cannot use this setting with the \"with\" command"));
+
+ std::string temp_value
+ = (delim == nullptr ? args : std::string (args, delim - args));
+
+ if (nested_cmd == nullptr)
+ nested_cmd = skip_spaces (delim + 2);
+
+ std::string org_value = get_setshow_command_value_string (set_cmd);
+
+ /* Tweak the setting to the new temporary value. */
+ do_set_command (temp_value.c_str (), from_tty, set_cmd);
+
+ try
+ {
+ scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
+
+ /* Execute the nested command. */
+ execute_command (nested_cmd, from_tty);
+ }
+ catch (const gdb_exception &ex)
+ {
+ /* Restore the setting and rethrow. If restoring the setting
+ throws, swallow the new exception and warn. There's nothing
+ else we can reasonably do. */
+ try
+ {
+ do_set_command (org_value.c_str (), from_tty, set_cmd);
+ }
+ catch (const gdb_exception &ex2)
+ {
+ warning (_("Couldn't restore setting: %s"), ex2.what ());
+ }
+
+ throw;
+ }
+
+ /* Restore the setting. */
+ do_set_command (org_value.c_str (), from_tty, set_cmd);
+}
+
+/* See cli/cli-cmds.h. */
+
+void
+with_command_completer_1 (const char *set_cmd_prefix,
+ completion_tracker &tracker,
+ const char *text)
+{
+ tracker.set_use_custom_word_point (true);
+
+ const char *delim = strstr (text, "--");
+
+ /* If we're still not past the "--" delimiter, complete the "with"
+ command as if it was a "set" command. */
+ if (delim == text
+ || delim == nullptr
+ || !isspace (delim[-1])
+ || !(isspace (delim[2]) || delim[2] == '\0'))
+ {
+ std::string new_text = std::string (set_cmd_prefix) + text;
+ tracker.advance_custom_word_point_by (-(int) strlen (set_cmd_prefix));
+ complete_nested_command_line (tracker, new_text.c_str ());
+ return;
+ }
+
+ /* We're past the "--" delimiter. Complete on the sub command. */
+ const char *nested_cmd = skip_spaces (delim + 2);
+ tracker.advance_custom_word_point_by (nested_cmd - text);
+ complete_nested_command_line (tracker, nested_cmd);
+}
+
+/* The "with" command. */
+
+static void
+with_command (const char *args, int from_tty)
+{
+ with_command_1 ("set ", setlist, args, from_tty);
+}
+
+/* "with" command completer. */
+
+static void
+with_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char * /*word*/)
+{
+ with_command_completer_1 ("set ", tracker, text);
+}
+
/* Provide documentation on command or list given by COMMAND. FROM_TTY
is ignored. */
@@ -878,12 +988,7 @@ pipe_command (const char *arg, int from_tty)
arg += delim.length (); /* Skip the delimiter. */
if (gdb_cmd.empty ())
- {
- repeat_previous ();
- gdb_cmd = skip_spaces (get_saved_command_line ());
- if (gdb_cmd.empty ())
- error (_("No previous command to relaunch"));
- }
+ gdb_cmd = repeat_previous ();
const char *shell_command = skip_spaces (arg);
if (*shell_command == '\0')
@@ -1850,6 +1955,23 @@ Generic command for showing things about the debugger."),
/* Another way to get at the same thing. */
add_info ("set", show_command, _("Show all GDB settings."));
+ c = add_com ("with", class_vars, with_command, _("\
+Temporarily set SETTING to VALUE, run COMMAND, and restore SETTING.\n\
+Usage: with SETTING [VALUE] [-- COMMAND]\n\
+Usage: w SETTING [VALUE] [-- COMMAND]\n\
+With no COMMAND, repeats the last executed command.\n\
+\n\
+SETTING is any setting you can change with the \"set\" subcommands.\n\
+E.g.:\n\
+ with language pascal -- print obj\n\
+ with print elements unlimited -- print obj\n\
+\n\
+You can change multiple settings using nested with, and use\n\
+abbreviations for commands and/or values. E.g.:\n\
+ w la p -- w p el u -- p obj"));
+ set_cmd_completer_handle_brkchars (c, with_command_completer);
+ add_com_alias ("w", "with", class_vars, 1);
+
add_cmd ("commands", no_set_class, show_commands, _("\
Show the history of commands you typed.\n\
You can supply a command number to start with, or a `+' to start after\n\
diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h
index 63b8c40..94e210a 100644
--- a/gdb/cli/cli-cmds.h
+++ b/gdb/cli/cli-cmds.h
@@ -142,4 +142,19 @@ extern gdb::optional<open_script>
extern int source_verbose;
extern int trace_commands;
+/* Common code for the "with" and "maintenance with" commands.
+ SET_CMD_PREFIX is the spelling of the corresponding "set" command
+ prefix: i.e., "set " or "maintenance set ". SETLIST is the command
+ element for the same "set" command prefix. */
+extern void with_command_1 (const char *set_cmd_prefix,
+ cmd_list_element *setlist,
+ const char *args, int from_tty);
+
+/* Common code for the completers of the "with" and "maintenance with"
+ commands. SET_CMD_PREFIX is the spelling of the corresponding
+ "set" command prefix: i.e., "set " or "maintenance set ". */
+extern void with_command_completer_1 (const char *set_cmd_prefix,
+ completion_tracker &tracker,
+ const char *text);
+
#endif /* CLI_CLI_CMDS_H */
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index d588d04..6fb3244 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -190,7 +190,7 @@ parse_cli_var_uinteger (var_types var_type, const char **arg,
{
LONGEST val;
- if (*arg == nullptr)
+ if (*arg == nullptr || **arg == '\0')
{
if (var_type == var_uinteger)
error_no_arg (_("integer to set it to, or \"unlimited\"."));
@@ -225,7 +225,7 @@ parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
{
LONGEST val;
- if (*arg == nullptr)
+ if (*arg == nullptr || **arg == '\0')
error_no_arg (_("integer to set it to, or \"unlimited\"."));
if (is_unlimited_literal (arg, expression))
@@ -308,6 +308,9 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
gdb_assert (c->type == set_cmd);
+ if (arg == NULL)
+ arg = "";
+
switch (c->var_type)
{
case var_string:
@@ -317,8 +320,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
char *q;
int ch;
- if (arg == NULL)
- arg = "";
newobj = (char *) xmalloc (strlen (arg) + 2);
p = arg;
q = newobj;
@@ -364,9 +365,6 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
}
break;
case var_string_noescape:
- if (arg == NULL)
- arg = "";
-
if (*(char **) c->var == NULL || strcmp (*(char **) c->var, arg) != 0)
{
xfree (*(char **) c->var);
@@ -376,14 +374,14 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
}
break;
case var_filename:
- if (arg == NULL)
+ if (*arg == '\0')
error_no_arg (_("filename to set it to."));
/* FALLTHROUGH */
case var_optional_filename:
{
char *val = NULL;
- if (arg != NULL)
+ if (*arg != '\0')
{
/* Clear trailing whitespace of filename. */
const char *ptr = arg + strlen (arg) - 1;
@@ -455,7 +453,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
{
LONGEST val;
- if (arg == NULL)
+ if (*arg == '\0')
{
if (c->var_type == var_integer)
error_no_arg (_("integer to set it to, or \"unlimited\"."));
@@ -625,24 +623,13 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
}
}
-/* Do a "show" command. ARG is NULL if no argument, or the
- text of the argument, and FROM_TTY is nonzero if this command is
- being entered directly by the user (i.e. these are just like any
- other command). C is the command list element for the command. */
+/* See cli/cli-setshow.h. */
-void
-do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
+std::string
+get_setshow_command_value_string (cmd_list_element *c)
{
- struct ui_out *uiout = current_uiout;
-
- gdb_assert (c->type == show_cmd);
-
string_file stb;
- /* Possibly call the pre hook. */
- if (c->pre_show_hook)
- (c->pre_show_hook) (c);
-
switch (c->var_type)
{
case var_string:
@@ -672,9 +659,7 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
stb.puts ("auto");
break;
default:
- internal_error (__FILE__, __LINE__,
- _("do_show_command: "
- "invalid var_auto_boolean"));
+ gdb_assert_not_reached ("invalid var_auto_boolean");
break;
}
break;
@@ -703,23 +688,42 @@ do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
}
break;
default:
- error (_("gdb internal error: bad var_type in do_show_command"));
+ gdb_assert_not_reached ("bad var_type");
}
+ return std::move (stb.string ());
+}
+
+
+/* Do a "show" command. ARG is NULL if no argument, or the
+ text of the argument, and FROM_TTY is nonzero if this command is
+ being entered directly by the user (i.e. these are just like any
+ other command). C is the command list element for the command. */
+
+void
+do_show_command (const char *arg, int from_tty, struct cmd_list_element *c)
+{
+ struct ui_out *uiout = current_uiout;
+
+ gdb_assert (c->type == show_cmd);
+
+ /* Possibly call the pre hook. */
+ if (c->pre_show_hook)
+ (c->pre_show_hook) (c);
+
+ std::string val = get_setshow_command_value_string (c);
- /* FIXME: cagney/2005-02-10: Need to split this in half: code to
- convert the value into a string (esentially the above); and
- code to print the value out. For the latter there should be
- MI and CLI specific versions. */
+ /* FIXME: cagney/2005-02-10: There should be MI and CLI specific
+ versions of code to print the value out. */
if (uiout->is_mi_like_p ())
- uiout->field_stream ("value", stb);
+ uiout->field_string ("value", val.c_str ());
else
{
if (c->show_value_func != NULL)
- c->show_value_func (gdb_stdout, from_tty, c, stb.c_str ());
+ c->show_value_func (gdb_stdout, from_tty, c, val.c_str ());
else
- deprecated_show_value_hack (gdb_stdout, from_tty, c, stb.c_str ());
+ deprecated_show_value_hack (gdb_stdout, from_tty, c, val.c_str ());
}
c->func (c, NULL, from_tty);
diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h
index c00a098..8bfe7e8 100644
--- a/gdb/cli/cli-setshow.h
+++ b/gdb/cli/cli-setshow.h
@@ -17,6 +17,8 @@
#ifndef CLI_CLI_SETSHOW_H
#define CLI_CLI_SETSHOW_H
+#include <string>
+
struct cmd_list_element;
/* Parse ARG, an option to a boolean variable.
@@ -55,6 +57,9 @@ extern void do_set_command (const char *arg, int from_tty,
extern void do_show_command (const char *arg, int from_tty,
struct cmd_list_element *c);
+/* Get a string version of C's current value. */
+extern std::string get_setshow_command_value_string (cmd_list_element *c);
+
extern void cmd_show_list (struct cmd_list_element *list, int from_tty,
const char *prefix);
diff --git a/gdb/command.h b/gdb/command.h
index 4d52f00..648950b 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -461,14 +461,17 @@ extern void error_no_arg (const char *) ATTRIBUTE_NORETURN;
extern void dont_repeat ();
-/* Commands call repeat_previous if they want to repeat the previous command.
- Such commands that repeat the previous command must indicate
- to not repeat themselves, to avoid recursive repeat.
- repeat_previous will mark the current command as not repeating,
- and will ensure get_saved_command_line returns the previous command,
- so that the currently executing command can repeat it. */
-
-extern void repeat_previous ();
+/* Commands call repeat_previous if they want to repeat the previous
+ command. Such commands that repeat the previous command must
+ indicate to not repeat themselves, to avoid recursive repeat.
+ repeat_previous marks the current command as not repeating, and
+ ensures get_saved_command_line returns the previous command, so
+ that the currently executing command can repeat it. If there's no
+ previous command, throws an error. Otherwise, returns the result
+ of get_saved_command_line, which now points at the command to
+ repeat. */
+
+extern const char *repeat_previous ();
/* Prevent dont_repeat from working, and return a cleanup that
restores the previous state. */
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 1ebaae3..1025916 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,4 +1,12 @@
2019-07-03 Pedro Alves <palves@redhat.com>
+ Philippe Waroquiers <philippe.waroquiers@skynet.be>
+
+ * gdb.texinfo (Command Settings): New node documenting the general
+ concept of settings, how to change them, and the new "with"
+ command.
+ (Maintenance Commands): Document "maint with".
+
+2019-07-03 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Maintenance Commands): Document "maint set/show
test-settings" instead of "maint test-settings set/show".
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ca43166..299c4a1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1561,6 +1561,7 @@ show you the alternatives available, if there is more than one possibility).
@menu
* Command Syntax:: How to give commands to @value{GDBN}
+* Command Settings:: How to change default behavior of commands
* Completion:: Command completion
* Command Options:: Command options
* Help:: How to ask @value{GDBN} for help
@@ -1617,6 +1618,98 @@ commands. This command accepts the current line, like @key{RET}, and
then fetches the next line relative to the current line from the history
for editing.
+
+@node Command Settings
+@section Command Settings
+@cindex default behavior of commands, changing
+@cindex default settings, changing
+
+Many commands change their behavior according to command-specific
+variables or settings. These settings can be changed with the
+@code{set} subcommands. For example, the @code{print} command
+(@pxref{Data, ,Examining Data}) prints arrays differently depending on
+settings changeable with the commands @code{set print elements
+NUMBER-OF-ELEMENTS} and @code{set print array-indexes}, among others.
+
+You can change these settings to your preference in the gdbinit files
+loaded at @value{GDBN} startup. @xref{Startup}.
+
+The settings can also be changed interactively during the debugging
+session. For example, to change the limit of array elements to print,
+you can do the following:
+@smallexample
+(@value{GDBN}) set print elements 10
+(@value{GDBN}) print some_array
+$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@}
+@end smallexample
+
+The above @code{set print elements 10} command changes the number of
+elements to print from the default of 200 to 10. If you only intend
+this limit of 10 to be used for printing @code{some_array}, then you
+must restore the limit back to 200, with @code{set print elements
+200}.
+
+Some commands allow overriding settings with command options. For
+example, the @code{print} command supports a number of options that
+allow overriding relevant global print settings as set by @code{set
+print} subcommands. @xref{print options}. The example above could be
+rewritten as:
+@smallexample
+(@value{GDBN}) print -elements 10 -- some_array
+$1 = @{0, 10, 20, 30, 40, 50, 60, 70, 80, 90...@}
+@end smallexample
+
+Alternatively, you can use the @code{with} command to change a setting
+temporarily, for the duration of a command invocation.
+
+@table @code
+@kindex with command
+@kindex w @r{(@code{with})}
+@cindex settings
+@cindex temporarily change settings
+@item with @var{setting} [@var{value}] [-- @var{command}]
+@itemx w @var{setting} [@var{value}] [-- @var{command}]
+Temporarily set @var{setting} to @var{value} for the duration of
+@var{command}.
+
+@var{setting} is any setting you can change with the @code{set}
+subcommands. @var{value} is the value to assign to @code{setting}
+while running @code{command}.
+
+If no @var{command} is provided, the last command executed is
+repeated.
+
+If a @var{command} is provided, it must be preceded by a double dash
+(@code{--}) separator. This is required because some settings accept
+free-form arguments, such as expressions or filenames.
+
+For example, the command
+@smallexample
+(@value{GDBN}) with print array on -- print some_array
+@end smallexample
+@noindent
+is equivalent to the following 3 commands:
+@smallexample
+(@value{GDBN}) set print array on
+(@value{GDBN}) print some_array
+(@value{GDBN}) set print array off
+@end smallexample
+
+The @code{with} command is particularly useful when you want to
+override a setting while running user-defined commands, or commands
+defined in Python or Guile. @xref{Extending GDB,, Extending GDB}.
+
+@smallexample
+(@value{GDBN}) with print pretty on -- my_complex_command
+@end smallexample
+
+To change several settings for the same command, you can nest
+@code{with} commands. For example, @code{with language ada -- with
+print elements 10} temporarily changes the language to Ada and sets a
+limit of 10 elements to print for arrays and strings.
+
+@end table
+
@node Completion
@section Command Completion
@@ -37634,6 +37727,13 @@ support in the command options framework.
These are representative commands for each @var{kind} of setting type
@value{GDBN} supports. They are used by the testsuite for exercising
the settings infrastructure.
+
+@kindex maint with
+@item maint with @var{setting} [@var{value}] [-- @var{command}]
+Like the @code{with} command, but works with @code{maintenance set}
+variables. This is used by the testsuite to exercise the @code{with}
+command's infrastructure.
+
@end table
The following command is useful for non-interactive invocations of
diff --git a/gdb/maint.c b/gdb/maint.c
index aaabb35..cecde84 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -43,6 +43,7 @@
#include "cli/cli-decode.h"
#include "cli/cli-utils.h"
#include "cli/cli-setshow.h"
+#include "cli/cli-cmds.h"
static void maintenance_do_deprecate (const char *, int);
@@ -634,6 +635,24 @@ maintenance_show_cmd (const char *args, int from_tty)
cmd_show_list (maintenance_show_cmdlist, from_tty, "");
}
+/* "maintenance with" command. */
+
+static void
+maintenance_with_cmd (const char *args, int from_tty)
+{
+ with_command_1 ("maintenance set ", maintenance_set_cmdlist, args, from_tty);
+}
+
+/* "maintenance with" command completer. */
+
+static void
+maintenance_with_cmd_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char * /*word*/)
+{
+ with_command_completer_1 ("maintenance set ", tracker, text);
+}
+
/* Profiling support. */
static int maintenance_profile_p;
@@ -1023,6 +1042,15 @@ Configure variables internal to GDB that aid in GDB's maintenance"),
0/*allow-unknown*/,
&maintenancelist);
+ cmd = add_cmd ("with", class_maintenance, maintenance_with_cmd, _("\
+Like \"with\", but works with \"maintenance set\" variables.\n\
+Usage: maintenance with SETTING [VALUE] [-- COMMAND]\n\
+With no COMMAND, repeats the last executed command.\n\
+SETTING is any setting you can change with the \"maintenance set\"\n\
+subcommands."),
+ &maintenancelist);
+ set_cmd_completer_handle_brkchars (cmd, maintenance_with_cmd_completer);
+
#ifndef _WIN32
add_cmd ("dump-me", class_maintenance, maintenance_dump_me, _("\
Get fatal error; make debugger dump its core.\n\
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index a954e6d..9b988dc 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2019-07-03 Pedro Alves <palves@redhat.com>
+ * gdb.base/with.c: New file.
+ * gdb.base/with.exp: New file.
+
+2019-07-03 Pedro Alves <palves@redhat.com>
+
* gdb.base/settings.exp: Replace all references to "maint
test-settings set" with references to "maint set test-settings",
and all references to "maint test-settings show" with references
diff --git a/gdb/testsuite/gdb.base/with.c b/gdb/testsuite/gdb.base/with.c
new file mode 100644
index 0000000..c642662
--- /dev/null
+++ b/gdb/testsuite/gdb.base/with.c
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 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/>. */
+
+int xxx1 = 123;
+
+struct S
+{
+ int a;
+ int b;
+ int c;
+};
+
+struct S g_s = {1, 2, 3};
+
+static void
+inc ()
+{
+ g_s.a++;;
+}
+
+int
+main ()
+{
+ inc ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp
new file mode 100644
index 0000000..9ea7685
--- /dev/null
+++ b/gdb/testsuite/gdb.base/with.exp
@@ -0,0 +1,289 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2019 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/>.
+
+# Test the "with" command.
+
+load_lib completion-support.exp
+
+standard_testfile .c
+
+if {[build_executable "failed to prepare" $testfile $srcfile debug]} {
+ return -1
+}
+
+clean_restart $binfile
+
+# Test "maint with". VALUES is a list of values. A nested "with" is
+# performed with each combination of pair of values from this list.
+# This exercises setting a value, and restoring it too. This is
+# particularly important for the "special" values like "unlimited",
+# which for example for var_uinteger maps to 0 at the user-visible
+# level, but maps to -1 internally.
+
+proc test_with {setting values} {
+ foreach val1 $values {
+ foreach val2 $values {
+ gdb_test \
+ "maint with test-settings $setting $val1 -- maint with test-settings $setting $val2 -- p 1" \
+ " = 1"
+ }
+ }
+}
+
+# Test "maint with" in the error case. SETTING is the "maint set
+# test-setting" setting to exercise. TMP_VAL is the value to set the
+# setting to. EXPECTED_RE is the expected GDB output, which should be
+# an error of some kind. Also checks that the setting's original
+# value is preserved across the error.
+
+proc test_with_error {setting tmp_val expected_re} {
+ global gdb_prompt
+
+ with_test_prefix "$setting, $tmp_val" {
+ set test "save org value"
+ set org_val ""
+ gdb_test_multiple "maint show test-settings $setting" $test {
+ -re "(.*)\r\n$gdb_prompt $" {
+ set org_val $expect_out(1,string)
+ pass $test
+ }
+ }
+
+ gdb_test \
+ "maint with test-settings $setting $tmp_val -- p 1" \
+ $expected_re
+
+ gdb_test "maint show test-settings $setting" "^$org_val" \
+ "value hasn't changed across error"
+ }
+}
+
+# Test "with" framework basics, using the internal "maint with
+# test-settings" subcommands.
+with_test_prefix "maint" {
+ test_with "auto-boolean" {"on" "off" "auto"}
+ test_with "boolean" {"" "on" "off" "0" "1" "enable" "disable"}
+ test_with "integer" {"0" "1" "-1" "unlimited"}
+ test_with "uinteger" {"0" "1" "unlimited"}
+ test_with "zinteger" {"0" "1" "-1"}
+ test_with "zuinteger" {"0" "1"}
+ test_with "zuinteger-unlimited" {"-1" "unlimited" "0" "1"}
+ test_with "string" {"" "foo" "\"hello world\""}
+ test_with "string-noescape" {"" "foo" "\"hello world\""}
+ test_with "filename" {"/foo" "bar/x/y"}
+ test_with "optional-filename" {"" "/foo" "bar/x/y"}
+ test_with "enum" {"xxx" "yyy"}
+
+ # Check the most important error conditions. E.g., empty,
+ # negative or "unlimited" values for settings that don't accept
+ # those. Exhaustive error coverage of the set/with value parsing
+ # is left to "set" testing, in gdb.base/settings.exp.
+ test_with_error "auto-boolean" "" \
+ "\"on\", \"off\" or \"auto\" expected\\."
+ test_with_error "auto-boolean" "xxx" \
+ "\"on\", \"off\" or \"auto\" expected\\."
+ test_with_error "boolean" "2" "\"on\" or \"off\" expected\\."
+ test_with_error "uinteger" "-1" "integer -1 out of range"
+ test_with_error "uinteger" "" \
+ "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+ test_with_error "zuinteger" "-1" "integer -1 out of range"
+ test_with_error "zuinteger" "" \
+ "Argument required \\(integer to set it to\\.\\)\\."
+ test_with_error "zuinteger-unlimited" "-2" \
+ "only -1 is allowed to set as unlimited"
+ test_with_error "zuinteger-unlimited" "" \
+ "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+ test_with_error "filename" "" \
+ "Argument required \\(filename to set it to\\.\\)\\."
+ test_with_error "enum" "" \
+ "Requires an argument\\. Valid arguments are xxx, yyy, zzz\\."
+}
+
+# Basic/core tests using user-visible commands.
+with_test_prefix "basics" {
+ gdb_test "print g_s" " = {a = 1, b = 2, c = 3}"
+ gdb_test "with print pretty -- print g_s" \
+ [multi_line \
+ " = {" \
+ " a = 1," \
+ " b = 2," \
+ " c = 3" \
+ "}"]
+
+ # A boolean setting.
+ gdb_test "with non-stop on -- show non-stop" \
+ "Controlling the inferior in non-stop mode is on\\."
+ gdb_test "show non-stop" \
+ "Controlling the inferior in non-stop mode is off\\."
+
+ # Language.
+ gdb_test "with language pascal -- show language" \
+ "The current source language is \"pascal\"\\."
+
+ gdb_test "show language" \
+ "The current source language is \"auto; currently c\"\\."
+
+ gdb_test "with language ada -- print g_s" \
+ " = \\(a => 1, b => 2, c => 3\\)"
+
+ # Nested "with"s.
+ gdb_test "with language ada -- with language c -- print g_s" \
+ " = {a = 1, b = 2, c = 3}"
+
+ # "w" alias.
+ gdb_test "w language pascal -- show language" \
+ "The current source language is \"pascal\"\\." \
+ "w alias works"
+
+ # An early prototype of the "with" command got this wrong.
+ gdb_test \
+ "w print repeats unlimited -- w print repeats 1 -- p \"1223334444\"" \
+ " = \"1\", '2' <repeats 2 times>, '3' <repeats 3 times>, '4' <repeats 4 times>"
+}
+
+# Check a user-defined command.
+with_test_prefix "user-defined" {
+ # A user defined command.
+ set test "define usercmd"
+ gdb_test_multiple "define usercmd" $test {
+ -re "End with" {
+ gdb_test \
+ [multi_line_input \
+ {print g_s} \
+ {end}] \
+ "" \
+ $test
+ }
+ }
+ gdb_test "with language ada -- usercmd" \
+ " = \\(a => 1, b => 2, c => 3\\)"
+}
+
+# Check repeating.
+with_test_prefix "repeat" {
+ clean_restart $binfile
+
+ # "with" with no command reinvokes the previous command.
+ gdb_test "with language ada" \
+ "No previous command to relaunch" \
+ "reinvoke with no previous command to relaunch"
+
+ gdb_test "print g_s" " = {a = 1, b = 2, c = 3}"
+
+ gdb_test "with language ada" \
+ " = \\(a => 1, b => 2, c => 3\\)" \
+ "reinvoke with language"
+
+ # Same, but with "--".
+ gdb_test "with language fortran --" \
+ " = \\( a = 1, b = 2, c = 3 \\)" \
+ "reinvoke with language and --"
+
+ # Repeating repeats the original "print g_s", not the last "with"
+ # command.
+ set test "repeat command line"
+ send_gdb "\n"
+ gdb_test_multiple "" $test {
+ -re " = {a = 1, b = 2, c = 3}\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+}
+
+# Basic run control.
+with_test_prefix "run control" {
+ clean_restart $binfile
+
+ if ![runto_main] {
+ fail "cannot run to main"
+ return
+ }
+
+ # Check "with" with a synchronous execution command.
+ gdb_test "with disassemble-next-line on -- next" \
+ "return 0;.*=>.*"
+}
+
+# Check errors.
+with_test_prefix "errors" {
+ # Try both an unknown root setting and an unknown prefixed
+ # setting. The errors come from different locations in the
+ # sources.
+ gdb_test "with xxxx yyyy" \
+ "Undefined set command: \"xxxx\". Try \"help set\"\\."
+ gdb_test "with print xxxx yyyy" \
+ "Undefined set print command: \"xxxx yyyy\". Try \"help set print\"\\."
+ # Try one error case for "maint with", to make sure the right
+ # "maintenance with" prefix is shown.
+ gdb_test "maint with xxxx yyyy" \
+ "Undefined maintenance set command: \"xxxx\". Try \"help maintenance set\"\\."
+
+ # Try ambiguous settings.
+ gdb_test "with w" \
+ "Ambiguous set command \"w\": watchdog, width, write\\."
+ gdb_test "with print m" \
+ "Ambiguous set print command \"m\": max-depth, max-symbolic-offset\\."
+
+ gdb_test "with variable xxx=1" \
+ "Cannot use this setting with the \"with\" command"
+
+ gdb_test "with print elements -- p 1" \
+ "Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+
+ gdb_test "with -- p 1" \
+ "Missing setting before '--' delimiter"
+
+ # Check that the setting is restored even if the command throws.
+ gdb_test "with print elements 1 -- unknowncommand" \
+ "Undefined command: \"unknowncommand\"\\. Try \"help\"\\."
+ gdb_test "show print elements" \
+ "Limit on string chars or array elements to print is 200\\."
+}
+
+# Check completion.
+with_test_prefix "completion" {
+ test_gdb_complete_unique \
+ "with pri" \
+ "with print"
+
+ test_gdb_complete_unique \
+ "with print ele" \
+ "with print elements"
+
+ test_gdb_complete_unique \
+ "with print elements u" \
+ "with print elements unlimited"
+
+ test_gdb_complete_none \
+ "with print elements unlimited "
+
+ test_gdb_completion_offers_commands "with print elements unlimited -- "
+
+ # Check that the completer nests into the nested command line's
+ # completer.
+ test_gdb_complete_unique \
+ "with print elements unlimited -- with print ele" \
+ "with print elements unlimited -- with print elements"
+
+ # Check completion of "maint with". "maint with" and "with"'s
+ # completers share 99% of the code. All we need to care about
+ # here is that the completion word point is computed correctly, so
+ # any simple completion is sufficient.
+ test_gdb_complete_unique \
+ "maint with test-set" \
+ "maint with test-settings"
+}
diff --git a/gdb/top.c b/gdb/top.c
index be736b0..c5fc94f 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -730,7 +730,7 @@ dont_repeat (void)
/* See command.h */
-void
+const char *
repeat_previous ()
{
/* Do not repeat this command, as this command is a repeating command. */
@@ -740,6 +740,11 @@ repeat_previous ()
so swap it with previous_saved_command_line. */
std::swap (previous_saved_command_line, saved_command_line);
std::swap (previous_repeat_arguments, repeat_arguments);
+
+ const char *prev = skip_spaces (get_saved_command_line ());
+ if (*prev == '\0')
+ error (_("No previous command to relaunch"));
+ return prev;
}
/* See command.h. */