* [RFA v2 7/8] Allow breakpoint commands to be set from Python
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 16:13 ` Eli Zaretskii
2018-04-30 13:07 ` Phil Muldoon
2018-04-25 15:41 ` [RFA v2 8/8] Let gdb.execute handle multi-line commands Tom Tromey
` (7 subsequent siblings)
8 siblings, 2 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This changes the Python API so that breakpoint commands can be set by
writing to the "commands" attribute.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR python/22731:
* NEWS: Mention that breakpoint commands are writable.
* python/py-breakpoint.c (bppy_set_commands): New function.
(breakpoint_object_getset) <"commands">: Use it.
gdb/doc/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR python/22731:
* python.texi (Breakpoints In Python): Mention that "commands" is
writable.
gdb/testsuite/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR python/22731:
* gdb.python/py-breakpoint.exp: Test setting breakpoint commands.
---
gdb/ChangeLog | 7 +++++
gdb/NEWS | 5 ++++
gdb/doc/ChangeLog | 6 ++++
gdb/doc/python.texi | 2 +-
gdb/python/py-breakpoint.c | 45 +++++++++++++++++++++++++++++-
gdb/testsuite/ChangeLog | 5 ++++
gdb/testsuite/gdb.python/py-breakpoint.exp | 10 ++++++-
7 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 63fe30d175..14d5fbb7c0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -24,6 +24,11 @@ set|show record btrace cpu
Controls the processor to be used for enabling errata workarounds for
branch trace decode.
+* Python Scripting
+
+ ** The commands attached to a breakpoint can be set by assigning to
+ the breakpoint's "commands" field.
+
* New targets
RiscV ELF riscv*-*-elf
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index ebd48fffe7..a2b948a4ca 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -5116,7 +5116,7 @@ value is @code{None}. This attribute is writable.
This attribute holds the commands attached to the breakpoint. If
there are commands, this attribute's value is a string holding all the
commands, separated by newlines. If there are no commands, this
-attribute is @code{None}. This attribute is not writable.
+attribute is @code{None}. This attribute is writable.
@end defvar
@node Finish Breakpoints in Python
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index d654b92a8c..a66e553cf8 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -510,6 +510,49 @@ bppy_get_commands (PyObject *self, void *closure)
return host_string_to_python_string (stb.c_str ());
}
+/* Set the commands attached to a breakpoint. Returns 0 on success.
+ Returns -1 on error, with a python exception set. */
+static int
+bppy_set_commands (PyObject *self, PyObject *newvalue, void *closure)
+{
+ gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
+ struct breakpoint *bp = self_bp->bp;
+ struct gdb_exception except = exception_none;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ gdb::unique_xmalloc_ptr<char> commands
+ (python_string_to_host_string (newvalue));
+ if (commands == nullptr)
+ return -1;
+
+ TRY
+ {
+ bool first = true;
+ char *save_ptr = nullptr;
+ auto reader
+ = [&] ()
+ {
+ const char *result = strtok_r (first ? commands.get () : nullptr,
+ "\n", &save_ptr);
+ first = false;
+ return result;
+ };
+
+ counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
+ breakpoint_set_commands (self_bp->bp, std::move (lines));
+ }
+ CATCH (ex, RETURN_MASK_ALL)
+ {
+ except = ex;
+ }
+ END_CATCH
+
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
+
+ return 0;
+}
+
/* Python function to get the breakpoint type. */
static PyObject *
bppy_get_type (PyObject *self, void *closure)
@@ -1185,7 +1228,7 @@ when setting this property.", NULL },
{ "condition", bppy_get_condition, bppy_set_condition,
"Condition of the breakpoint, as specified by the user,\
or None if no condition set."},
- { "commands", bppy_get_commands, NULL,
+ { "commands", bppy_get_commands, bppy_set_commands,
"Commands of the breakpoint, as specified by the user."},
{ "type", bppy_get_type, NULL,
"Type of breakpoint."},
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
index 6e0ff88f87..3ce0ea11de 100644
--- a/gdb/testsuite/gdb.python/py-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
@@ -197,8 +197,16 @@ proc_with_prefix test_bkpt_cond_and_cmds { } {
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" \
"Get Breakpoint List" 0
- gdb_test "python print (blist\[len(blist)-1\].commands)" \
+ gdb_py_test_silent_cmd "python last_bp = blist\[len(blist)-1\]" \
+ "Find last breakpoint" 0
+ gdb_test "python print (last_bp.commands)" \
"print \"Command for breakpoint has been executed.\".*print result"
+
+ gdb_test_no_output "python last_bp.commands = 'echo hi\\necho there'" \
+ "set commands"
+ # Note the length is 3 because the string ends in a \n.
+ gdb_test "python print (len(last_bp.commands.split('\\n')))" "3" \
+ "check number of lines in commands"
}
proc_with_prefix test_bkpt_invisible { } {
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFA v2 7/8] Allow breakpoint commands to be set from Python
2018-04-25 15:41 ` [RFA v2 7/8] Allow breakpoint commands to be set from Python Tom Tromey
@ 2018-04-25 16:13 ` Eli Zaretskii
2018-04-30 13:07 ` Phil Muldoon
1 sibling, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2018-04-25 16:13 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Wed, 25 Apr 2018 09:41:32 -0600
>
> This changes the Python API so that breakpoint commands can be set by
> writing to the "commands" attribute.
>
> gdb/ChangeLog
> 2018-04-25 Tom Tromey <tom@tromey.com>
>
> PR python/22731:
> * NEWS: Mention that breakpoint commands are writable.
> * python/py-breakpoint.c (bppy_set_commands): New function.
> (breakpoint_object_getset) <"commands">: Use it.
>
> gdb/doc/ChangeLog
> 2018-04-25 Tom Tromey <tom@tromey.com>
>
> PR python/22731:
> * python.texi (Breakpoints In Python): Mention that "commands" is
> writable.
>
> gdb/testsuite/ChangeLog
> 2018-04-25 Tom Tromey <tom@tromey.com>
>
> PR python/22731:
> * gdb.python/py-breakpoint.exp: Test setting breakpoint commands.
OK for the documentation parts.
Thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFA v2 7/8] Allow breakpoint commands to be set from Python
2018-04-25 15:41 ` [RFA v2 7/8] Allow breakpoint commands to be set from Python Tom Tromey
2018-04-25 16:13 ` Eli Zaretskii
@ 2018-04-30 13:07 ` Phil Muldoon
2018-04-30 14:40 ` Tom Tromey
1 sibling, 1 reply; 14+ messages in thread
From: Phil Muldoon @ 2018-04-30 13:07 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
>
> @node Finish Breakpoints in Python
> diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
> index d654b92a8c..a66e553cf8 100644
> --- a/gdb/python/py-breakpoint.c
> +++ b/gdb/python/py-breakpoint.c
> @@ -510,6 +510,49 @@ bppy_get_commands (PyObject *self, void *closure)
> return host_string_to_python_string (stb.c_str ());
> }
>
> +/* Set the commands attached to a breakpoint. Returns 0 on success.
> + Returns -1 on error, with a python exception set. */
> +static int
> +bppy_set_commands (PyObject *self, PyObject *newvalue, void *closure)
> +{
> + gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
> + struct breakpoint *bp = self_bp->bp;
> + struct gdb_exception except = exception_none;
> +
> + BPPY_SET_REQUIRE_VALID (self_bp);
> +
> + gdb::unique_xmalloc_ptr<char> commands
> + (python_string_to_host_string (newvalue));
> + if (commands == nullptr)
> + return -1;
> +
> + TRY
> + {
> + bool first = true;
> + char *save_ptr = nullptr;
> + auto reader
> + = [&] ()
> + {
> + const char *result = strtok_r (first ? commands.get () : nullptr,
> + "\n", &save_ptr);
> + first = false;
> + return result;
> + };
> +
> + counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
> + breakpoint_set_commands (self_bp->bp, std::move (lines));
> + }
> + CATCH (ex, RETURN_MASK_ALL)
> + {
> + except = ex;
> + }
> + END_CATCH
> +
> + GDB_PY_SET_HANDLE_EXCEPTION (except);
> +
> + return 0;
> +}
The code bits LGTM but on a somewhat side note I'm wondering if there
are any side effects with the Python breakpoint stop callback? This
shouldn't interfere with the viability of this patch, though, because
a breakpoint previously could have had a command list attached to it
after being created in Python and via the commands command. I'm mildly
curious what would get called first.
Cheers
Phil
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFA v2 7/8] Allow breakpoint commands to be set from Python
2018-04-30 13:07 ` Phil Muldoon
@ 2018-04-30 14:40 ` Tom Tromey
0 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-30 14:40 UTC (permalink / raw)
To: Phil Muldoon; +Cc: Tom Tromey, gdb-patches
Phil> The code bits LGTM but on a somewhat side note I'm wondering if there
Phil> are any side effects with the Python breakpoint stop callback? This
Phil> shouldn't interfere with the viability of this patch, though, because
Phil> a breakpoint previously could have had a command list attached to it
Phil> after being created in Python and via the commands command. I'm mildly
Phil> curious what would get called first.
The stop method is called first and the commands are only run if stop
returns True. There's no conflict between the two.
Tom
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 8/8] Let gdb.execute handle multi-line commands
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
2018-04-25 15:41 ` [RFA v2 7/8] Allow breakpoint commands to be set from Python Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 16:16 ` Eli Zaretskii
2018-04-25 15:41 ` [RFA v2 3/8] Make print_command_trace varargs Tom Tromey
` (6 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This changes the Python API so that gdb.execute can now handle
multi-line commands, like "commands" or "define".
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR python/22730:
* NEWS: Mention gdb.execute change.
* gdbcmd.h (execute_control_command): Don't declare.
* python/python.c (execute_gdb_command): Use read_command_lines_1,
execute_control_commands, execute_control_commands_to_string.
* cli/cli-script.h (execute_control_commands)
(execute_control_commands_to_string): Declare.
(execute_control_command): Add from_tty parameter.
* cli/cli-script.c (execute_control_commands)
(execute_control_commands_to_string): New functions.
(execute_user_command): Use execute_control_commands.
(execute_control_command_1): Add "from_tty" parameter. Update.
(execute_control_command): Likewise.
gdb/testsuite/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR python/22730:
* gdb.python/python.exp: Test multi-line execute.
---
gdb/ChangeLog | 16 +++++++
gdb/NEWS | 2 +
gdb/cli/cli-script.c | 93 ++++++++++++++++++++++++++-----------
gdb/cli/cli-script.h | 15 +++++-
gdb/gdbcmd.h | 2 -
gdb/python/python.c | 19 +++++++-
gdb/testsuite/ChangeLog | 5 ++
gdb/testsuite/gdb.python/python.exp | 3 ++
8 files changed, 123 insertions(+), 32 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 14d5fbb7c0..a72ee21cf8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -29,6 +29,8 @@ set|show record btrace cpu
** The commands attached to a breakpoint can be set by assigning to
the breakpoint's "commands" field.
+ ** gdb.execute can now execute multi-line gdb commands.
+
* New targets
RiscV ELF riscv*-*-elf
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index e336c58ad0..a62e4fe1c1 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -374,12 +374,69 @@ execute_cmd_post_hook (struct cmd_list_element *c)
}
}
+/* See cli-script.h. */
+
+void
+execute_control_commands (struct command_line *cmdlines, int from_tty)
+{
+ /* Set the instream to 0, indicating execution of a
+ user-defined function. */
+ scoped_restore restore_instream
+ = make_scoped_restore (¤t_ui->instream, nullptr);
+ scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
+ scoped_restore save_nesting
+ = make_scoped_restore (&command_nest_depth, command_nest_depth + 1);
+
+ while (cmdlines)
+ {
+ enum command_control_type ret = execute_control_command (cmdlines,
+ from_tty);
+ if (ret != simple_control && ret != break_control)
+ {
+ warning (_("Error executing canned sequence of commands."));
+ break;
+ }
+ cmdlines = cmdlines->next;
+ }
+}
+
+/* See cli-script.h. */
+
+std::string
+execute_control_commands_to_string (struct command_line *commands,
+ int from_tty)
+{
+ /* GDB_STDOUT should be better already restored during these
+ restoration callbacks. */
+ set_batch_flag_and_restore_page_info save_page_info;
+
+ string_file str_file;
+
+ {
+ current_uiout->redirect (&str_file);
+ ui_out_redirect_pop redirect_popper (current_uiout);
+
+ scoped_restore save_stdout
+ = make_scoped_restore (&gdb_stdout, &str_file);
+ scoped_restore save_stderr
+ = make_scoped_restore (&gdb_stderr, &str_file);
+ scoped_restore save_stdlog
+ = make_scoped_restore (&gdb_stdlog, &str_file);
+ scoped_restore save_stdtarg
+ = make_scoped_restore (&gdb_stdtarg, &str_file);
+ scoped_restore save_stdtargerr
+ = make_scoped_restore (&gdb_stdtargerr, &str_file);
+
+ execute_control_commands (commands, from_tty);
+ }
+
+ return std::move (str_file.string ());
+}
+
void
execute_user_command (struct cmd_list_element *c, const char *args)
{
- struct ui *ui = current_ui;
counted_command_line cmdlines_copy;
- enum command_control_type ret;
extern unsigned int max_user_call_depth;
/* Ensure that the user commands can't be deleted while they are
@@ -395,25 +452,7 @@ execute_user_command (struct cmd_list_element *c, const char *args)
if (user_args_stack.size () > max_user_call_depth)
error (_("Max user call depth exceeded -- command aborted."));
- /* Set the instream to 0, indicating execution of a
- user-defined function. */
- scoped_restore restore_instream
- = make_scoped_restore (&ui->instream, nullptr);
-
- scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
-
- scoped_restore save_nesting
- = make_scoped_restore (&command_nest_depth, command_nest_depth + 1);
- while (cmdlines)
- {
- ret = execute_control_command (cmdlines);
- if (ret != simple_control && ret != break_control)
- {
- warning (_("Error executing canned sequence of commands."));
- break;
- }
- cmdlines = cmdlines->next;
- }
+ execute_control_commands (cmdlines, 0);
}
/* This function is called every time GDB prints a prompt. It ensures
@@ -465,7 +504,7 @@ print_command_trace (const char *fmt, ...)
/* Helper for execute_control_command. */
static enum command_control_type
-execute_control_command_1 (struct command_line *cmd)
+execute_control_command_1 (struct command_line *cmd, int from_tty)
{
struct command_line *current;
struct value *val;
@@ -483,7 +522,7 @@ execute_control_command_1 (struct command_line *cmd)
{
/* A simple command, execute it and return. */
std::string new_line = insert_user_defined_cmd_args (cmd->line);
- execute_command (new_line.c_str (), 0);
+ execute_command (new_line.c_str (), from_tty);
ret = cmd->control_type;
break;
}
@@ -538,7 +577,7 @@ execute_control_command_1 (struct command_line *cmd)
{
scoped_restore save_nesting
= make_scoped_restore (&command_nest_depth, command_nest_depth + 1);
- ret = execute_control_command_1 (current);
+ ret = execute_control_command_1 (current, from_tty);
/* If we got an error, or a "break" command, then stop
looping. */
@@ -593,7 +632,7 @@ execute_control_command_1 (struct command_line *cmd)
{
scoped_restore save_nesting
= make_scoped_restore (&command_nest_depth, command_nest_depth + 1);
- ret = execute_control_command_1 (current);
+ ret = execute_control_command_1 (current, from_tty);
/* If we got an error, get out. */
if (ret != simple_control)
@@ -644,7 +683,7 @@ execute_control_command_1 (struct command_line *cmd)
}
enum command_control_type
-execute_control_command (struct command_line *cmd)
+execute_control_command (struct command_line *cmd, int from_tty)
{
/* Make sure we use the console uiout. It's possible that we are executing
breakpoint commands while running the MI interpreter. */
@@ -652,7 +691,7 @@ execute_control_command (struct command_line *cmd)
scoped_restore save_uiout
= make_scoped_restore (¤t_uiout, interp_ui_out (console));
- return execute_control_command_1 (cmd);
+ return execute_control_command_1 (cmd, from_tty);
}
/* Like execute_control_command, but first set
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 3bebd0ed9d..736ebb3a7b 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -122,10 +122,23 @@ extern void show_user_1 (struct cmd_list_element *c,
const char *name,
struct ui_file *stream);
+/* Execute the commands in CMDLINES. */
+
+extern void execute_control_commands (struct command_line *cmdlines,
+ int from_tty);
+
+/* Run execute_control_commands for COMMANDS. Capture its output into
+ the returned string, do not display it to the screen. BATCH_FLAG
+ will be temporarily set to true. */
+
+extern std::string execute_control_commands_to_string
+ (struct command_line *commands, int from_tty);
+
/* Exported to gdb/breakpoint.c */
extern enum command_control_type
- execute_control_command (struct command_line *cmd);
+ execute_control_command (struct command_line *cmd,
+ int from_tty = 0);
extern enum command_control_type
execute_control_command_untraced (struct command_line *cmd);
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
index 342c8b2c0e..b675ae8618 100644
--- a/gdb/gdbcmd.h
+++ b/gdb/gdbcmd.h
@@ -135,8 +135,6 @@ extern struct cmd_list_element *save_cmdlist;
extern void execute_command (const char *, int);
extern std::string execute_command_to_string (const char *p, int from_tty);
-enum command_control_type execute_control_command (struct command_line *);
-
extern void print_command_line (struct command_line *, unsigned int,
struct ui_file *);
extern void print_command_lines (struct ui_out *,
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 45b6516fc2..befd3bb5aa 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -581,6 +581,20 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
{
struct interp *interp;
+ std::string arg_copy = arg;
+ bool first = true;
+ char *save_ptr = nullptr;
+ auto reader
+ = [&] ()
+ {
+ const char *result = strtok_r (first ? &arg_copy[0] : nullptr,
+ "\n", &save_ptr);
+ first = false;
+ return result;
+ };
+
+ counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
+
scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
scoped_restore save_uiout = make_scoped_restore (¤t_uiout);
@@ -592,9 +606,10 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
scoped_restore preventer = prevent_dont_repeat ();
if (to_string)
- to_string_res = execute_command_to_string (arg, from_tty);
+ to_string_res = execute_control_commands_to_string (lines.get (),
+ from_tty);
else
- execute_command (arg, from_tty);
+ execute_control_commands (lines.get (), from_tty);
}
CATCH (except, RETURN_MASK_ALL)
{
diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp
index cee195f315..f6bf93add0 100644
--- a/gdb/testsuite/gdb.python/python.exp
+++ b/gdb/testsuite/gdb.python/python.exp
@@ -119,6 +119,9 @@ gdb_test_no_output \
"python x = gdb.execute('printf \"%d\", 23', to_string = True)"
gdb_test "python print (x)" "23"
+gdb_test "python gdb.execute('echo 2\\necho 3\\\\n\\n')" "23" \
+ "multi-line execute"
+
# Test post_event.
gdb_py_test_multiple "post event insertion" \
"python" "" \
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFA v2 8/8] Let gdb.execute handle multi-line commands
2018-04-25 15:41 ` [RFA v2 8/8] Let gdb.execute handle multi-line commands Tom Tromey
@ 2018-04-25 16:16 ` Eli Zaretskii
0 siblings, 0 replies; 14+ messages in thread
From: Eli Zaretskii @ 2018-04-25 16:16 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Wed, 25 Apr 2018 09:41:33 -0600
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 14d5fbb7c0..a72ee21cf8 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -29,6 +29,8 @@ set|show record btrace cpu
> ** The commands attached to a breakpoint can be set by assigning to
> the breakpoint's "commands" field.
>
> + ** gdb.execute can now execute multi-line gdb commands.
> +
> * New targets
This part is OK, thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 3/8] Make print_command_trace varargs
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
2018-04-25 15:41 ` [RFA v2 7/8] Allow breakpoint commands to be set from Python Tom Tromey
2018-04-25 15:41 ` [RFA v2 8/8] Let gdb.execute handle multi-line commands Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 15:41 ` [RFA v2 6/8] Use function_view in cli-script.c Tom Tromey
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
I noticed some code in execute_control_command_1 that could be
simplified by making print_command_trace a printf-like function. This
patch makes this change.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
* top.c (execute_command): Update.
* cli/cli-script.h (print_command_lines): Now varargs.
* cli/cli-script.c (print_command_lines): Now varargs.
(execute_control_command_1) <case while_control, case if_control>:
Update.
---
gdb/ChangeLog | 8 ++++++++
gdb/cli/cli-script.c | 22 ++++++++++------------
gdb/cli/cli-script.h | 3 ++-
gdb/top.c | 2 +-
4 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index b066da7d60..c7d405c0d0 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -426,8 +426,9 @@ reset_command_nest_depth (void)
via while_command or if_command. Inner levels of 'if' and 'while'
are dealt with directly. Therefore we can use these functions
to determine whether the command has been printed already or not. */
+ATTRIBUTE_PRINTF (1, 2)
void
-print_command_trace (const char *cmd)
+print_command_trace (const char *fmt, ...)
{
int i;
@@ -443,7 +444,12 @@ print_command_trace (const char *cmd)
for (i=0; i < command_nest_depth; i++)
printf_filtered ("+");
- printf_filtered ("%s\n", cmd);
+ va_list args;
+
+ va_start (args, fmt);
+ vprintf_filtered (fmt, args);
+ va_end (args);
+ puts_filtered ("\n");
}
/* Helper for execute_control_command. */
@@ -490,11 +496,7 @@ execute_control_command_1 (struct command_line *cmd)
case while_control:
{
- int len = strlen (cmd->line) + 7;
- char *buffer = (char *) alloca (len);
-
- xsnprintf (buffer, len, "while %s", cmd->line);
- print_command_trace (buffer);
+ print_command_trace ("while %s", cmd->line);
/* Parse the loop control expression for the while statement. */
std::string new_line = insert_user_defined_cmd_args (cmd->line);
@@ -555,11 +557,7 @@ execute_control_command_1 (struct command_line *cmd)
case if_control:
{
- int len = strlen (cmd->line) + 4;
- char *buffer = (char *) alloca (len);
-
- xsnprintf (buffer, len, "if %s", cmd->line);
- print_command_trace (buffer);
+ print_command_trace ("if %s", cmd->line);
/* Parse the conditional for the if statement. */
std::string new_line = insert_user_defined_cmd_args (cmd->line);
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 58dede2342..10b6c17789 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -148,7 +148,8 @@ extern std::string insert_user_defined_cmd_args (const char *line);
/* Exported to top.c */
-extern void print_command_trace (const char *cmd);
+extern void print_command_trace (const char *cmd, ...)
+ ATTRIBUTE_PRINTF (1, 2);
/* Exported to event-top.c */
diff --git a/gdb/top.c b/gdb/top.c
index 8903a92983..6f5abd5a3d 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -571,7 +571,7 @@ execute_command (const char *p, int from_tty)
line = p;
/* If trace-commands is set then this will print this command. */
- print_command_trace (p);
+ print_command_trace ("%s", p);
c = lookup_cmd (&cmd, cmdlist, "", 0, 1);
p = cmd;
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 6/8] Use function_view in cli-script.c
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (2 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 3/8] Make print_command_trace varargs Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 15:41 ` [RFA v2 1/8] Allocate cmd_list_element with new Tom Tromey
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This changes some functions in cli-script.c to use function_view
rather than a function pointer and closure argument. This simplifies
the code a bit and is useful in a subsequent patch.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
* tracepoint.c (actions_command): Update.
* mi/mi-cmd-break.c (mi_command_line_array)
(mi_command_line_array_cnt, mi_command_line_array_ptr)
(mi_read_next_line): Remove.
(mi_cmd_break_commands): Update.
* cli/cli-script.h (read_command_lines, read_command_lines_1): Use
function_view.
* cli/cli-script.c (get_command_line): Update.
(process_next_line): Use function_view. Constify.
(recurse_read_control_structure, read_command_lines)
(read_command_lines_1): Change argument types to function_view.
(do_define_command, document_command): Update.
* breakpoint.h (check_tracepoint_command): Don't declare.
* breakpoint.c (check_tracepoint_command): Remove.
(commands_command_1, create_tracepoint_from_upload): Update.
---
gdb/ChangeLog | 18 ++++++++++++++++++
gdb/breakpoint.c | 23 ++++++++++-------------
gdb/breakpoint.h | 4 ----
gdb/cli/cli-script.c | 51 ++++++++++++++++++++++++++-------------------------
gdb/cli/cli-script.h | 11 +++++------
gdb/mi/mi-cmd-break.c | 40 ++++++++++++++++------------------------
gdb/tracepoint.c | 6 ++++--
7 files changed, 79 insertions(+), 74 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 7d284e9a96..1c553564e4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1216,14 +1216,6 @@ breakpoint_set_task (struct breakpoint *b, int task)
gdb::observers::breakpoint_modified.notify (b);
}
-void
-check_tracepoint_command (char *line, void *closure)
-{
- struct breakpoint *b = (struct breakpoint *) closure;
-
- validate_actionline (line, b);
-}
-
static void
commands_command_1 (const char *arg, int from_tty,
struct command_line *control)
@@ -1256,10 +1248,15 @@ commands_command_1 (const char *arg, int from_tty,
"%s, one per line."),
arg);
- cmd = read_command_lines (str.c_str (), from_tty, 1,
- (is_tracepoint (b)
- ? check_tracepoint_command : 0),
- b);
+ auto do_validate = [=] (const char *line)
+ {
+ validate_actionline (line, b);
+ };
+ gdb::function_view<void (const char *)> validator;
+ if (is_tracepoint (b))
+ validator = do_validate;
+
+ cmd = read_command_lines (str.c_str (), from_tty, 1, validator);
}
}
@@ -14794,7 +14791,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
this_utp = utp;
next_cmd = 0;
- cmd_list = read_command_lines_1 (read_uploaded_action, 1, NULL, NULL);
+ cmd_list = read_command_lines_1 (read_uploaded_action, 1, NULL);
breakpoint_set_commands (tp, std::move (cmd_list));
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index f3c2599286..2008683a0a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1600,10 +1600,6 @@ extern int is_tracepoint (const struct breakpoint *b);
it. */
extern VEC(breakpoint_p) *static_tracepoints_here (CORE_ADDR addr);
-/* Function that can be passed to read_command_line to validate
- that each command is suitable for tracepoint command list. */
-extern void check_tracepoint_command (char *line, void *closure);
-
/* Create an instance of this to start registering breakpoint numbers
for a later "commands" command. */
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index d679e04e55..e336c58ad0 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -39,10 +39,10 @@
/* Prototypes for local functions. */
static enum command_control_type
-recurse_read_control_structure (char * (*read_next_line_func) (void),
- struct command_line *current_cmd,
- void (*validator)(char *, void *),
- void *closure);
+recurse_read_control_structure
+ (gdb::function_view<const char * ()> read_next_line_func,
+ struct command_line *current_cmd,
+ gdb::function_view<void (const char *)> validator);
static void do_define_command (const char *comname, int from_tty,
const counted_command_line *commands);
@@ -163,7 +163,7 @@ get_command_line (enum command_control_type type, const char *arg)
command_lines_deleter ());
/* Read in the body of this command. */
- if (recurse_read_control_structure (read_next_line, cmd.get (), 0, 0)
+ if (recurse_read_control_structure (read_next_line, cmd.get (), 0)
== invalid_control)
{
warning (_("Error reading in canned sequence of commands."));
@@ -897,11 +897,13 @@ line_first_arg (const char *p)
Otherwise, only "end" is recognized. */
static enum misc_command_type
-process_next_line (char *p, struct command_line **command, int parse_commands,
- void (*validator)(char *, void *), void *closure)
+process_next_line (const char *p, struct command_line **command,
+ int parse_commands,
+ gdb::function_view<void (const char *)> validator)
+
{
- char *p_end;
- char *p_start;
+ const char *p_end;
+ const char *p_start;
int not_handled = 0;
/* Not sure what to do here. */
@@ -1013,10 +1015,9 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
if (validator)
{
-
TRY
{
- validator ((*command)->line, closure);
+ validator ((*command)->line);
}
CATCH (ex, RETURN_MASK_ALL)
{
@@ -1035,10 +1036,9 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
obtain lines of the command. */
static enum command_control_type
-recurse_read_control_structure (char * (*read_next_line_func) (void),
+recurse_read_control_structure (gdb::function_view<const char * ()> read_next_line_func,
struct command_line *current_cmd,
- void (*validator)(char *, void *),
- void *closure)
+ gdb::function_view<void (const char *)> validator)
{
enum misc_command_type val;
enum command_control_type ret;
@@ -1061,7 +1061,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
current_cmd->control_type != python_control
&& current_cmd->control_type != guile_control
&& current_cmd->control_type != compile_control,
- validator, closure);
+ validator);
/* Just skip blanks and comments. */
if (val == nop_command)
@@ -1114,7 +1114,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
{
control_level++;
ret = recurse_read_control_structure (read_next_line_func, next,
- validator, closure);
+ validator);
control_level--;
if (ret != simple_control)
@@ -1140,7 +1140,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
counted_command_line
read_command_lines (const char *prompt_arg, int from_tty, int parse_commands,
- void (*validator)(char *, void *), void *closure)
+ gdb::function_view<void (const char *)> validator)
{
if (from_tty && input_interactive_p (current_ui))
{
@@ -1163,13 +1163,13 @@ read_command_lines (const char *prompt_arg, int from_tty, int parse_commands,
counted_command_line head (nullptr, command_lines_deleter ());
if (current_interp_named_p (INTERP_CONSOLE))
head = read_command_lines_1 (read_next_line, parse_commands,
- validator, closure);
+ validator);
else
{
scoped_restore_interp interp_restorer (INTERP_CONSOLE);
head = read_command_lines_1 (read_next_line, parse_commands,
- validator, closure);
+ validator);
}
if (from_tty && input_interactive_p (current_ui)
@@ -1184,8 +1184,9 @@ read_command_lines (const char *prompt_arg, int from_tty, int parse_commands,
obtained using READ_NEXT_LINE_FUNC. */
counted_command_line
-read_command_lines_1 (char * (*read_next_line_func) (void), int parse_commands,
- void (*validator)(char *, void *), void *closure)
+read_command_lines_1 (gdb::function_view<const char * ()> read_next_line_func,
+ int parse_commands,
+ gdb::function_view<void (const char *)> validator)
{
struct command_line *tail, *next;
counted_command_line head (nullptr, command_lines_deleter ());
@@ -1199,7 +1200,7 @@ read_command_lines_1 (char * (*read_next_line_func) (void), int parse_commands,
{
dont_repeat ();
val = process_next_line (read_next_line_func (), &next, parse_commands,
- validator, closure);
+ validator);
/* Ignore blank lines or comments. */
if (val == nop_command)
@@ -1221,7 +1222,7 @@ read_command_lines_1 (char * (*read_next_line_func) (void), int parse_commands,
{
control_level++;
ret = recurse_read_control_structure (read_next_line_func, next,
- validator, closure);
+ validator);
control_level--;
if (ret == invalid_control)
@@ -1407,7 +1408,7 @@ do_define_command (const char *comname, int from_tty,
{
std::string prompt
= string_printf ("Type commands for definition of \"%s\".", comfull);
- cmds = read_command_lines (prompt.c_str (), from_tty, 1, 0, 0);
+ cmds = read_command_lines (prompt.c_str (), from_tty, 1, 0);
}
else
cmds = *commands;
@@ -1464,7 +1465,7 @@ document_command (const char *comname, int from_tty)
std::string prompt = string_printf ("Type documentation for \"%s\".",
comfull);
counted_command_line doclines = read_command_lines (prompt.c_str (),
- from_tty, 0, 0, 0);
+ from_tty, 0, 0);
if (c->doc)
xfree ((char *) c->doc);
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 0bd0d597ae..3bebd0ed9d 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -106,12 +106,11 @@ private:
}
};
-extern counted_command_line read_command_lines (const char *, int, int,
- void (*)(char *, void *),
- void *);
-extern counted_command_line read_command_lines_1 (char * (*) (void), int,
- void (*)(char *, void *),
- void *);
+extern counted_command_line read_command_lines
+ (const char *, int, int, gdb::function_view<void (const char *)>);
+extern counted_command_line read_command_lines_1
+ (gdb::function_view<const char * ()>, int,
+ gdb::function_view<void (const char *)>);
/* Exported to cli/cli-cmds.c */
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 1772fad43c..8897117bb8 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -32,6 +32,7 @@
#include "linespec.h"
#include "gdb_obstack.h"
#include <ctype.h>
+#include "tracepoint.h"
enum
{
@@ -468,24 +469,6 @@ mi_cmd_break_watch (const char *command, char **argv, int argc)
}
}
-/* The mi_read_next_line consults these variable to return successive
- command lines. While it would be clearer to use a closure pointer,
- it is not expected that any future code will use read_command_lines_1,
- therefore no point of overengineering. */
-
-static char **mi_command_line_array;
-static int mi_command_line_array_cnt;
-static int mi_command_line_array_ptr;
-
-static char *
-mi_read_next_line (void)
-{
- if (mi_command_line_array_ptr == mi_command_line_array_cnt)
- return NULL;
- else
- return mi_command_line_array[mi_command_line_array_ptr++];
-}
-
void
mi_cmd_break_commands (const char *command, char **argv, int argc)
{
@@ -509,15 +492,24 @@ mi_cmd_break_commands (const char *command, char **argv, int argc)
if (b == NULL)
error (_("breakpoint %d not found."), bnum);
- mi_command_line_array = argv;
- mi_command_line_array_ptr = 1;
- mi_command_line_array_cnt = argc;
+ int count = 1;
+ auto reader
+ = [&] ()
+ {
+ const char *result = nullptr;
+ if (count < argc)
+ result = argv[count++];
+ return result;
+ };
if (is_tracepoint (b))
- break_command = read_command_lines_1 (mi_read_next_line, 1,
- check_tracepoint_command, b);
+ break_command = read_command_lines_1 (reader, 1,
+ [=] (const char *line)
+ {
+ validate_actionline (line, b);
+ });
else
- break_command = read_command_lines_1 (mi_read_next_line, 1, 0, 0);
+ break_command = read_command_lines_1 (reader, 1, 0);
breakpoint_set_commands (b, std::move (break_command));
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index e6cd565985..d1e4f51685 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -580,8 +580,10 @@ actions_command (const char *args, int from_tty)
counted_command_line l = read_command_lines (tmpbuf.c_str (),
from_tty, 1,
- check_tracepoint_command,
- t);
+ [=] (const char *line)
+ {
+ validate_actionline (line, t);
+ });
breakpoint_set_commands (t, std::move (l));
}
/* else just return */
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 1/8] Allocate cmd_list_element with new
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (3 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 6/8] Use function_view in cli-script.c Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 15:41 ` [RFA v2 4/8] Constify prompt argument to read_command_lines Tom Tromey
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This adds a constructor and destructor to cmd_list_element and changes
it to be allocated with new. This will be useful in a subsequent
patch.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
* cli/cli-decode.h (cmd_list_element): New constructor.
(~cmd_list_element): New destructor.
(struct cmd_list_element): Add initializers.
* cli/cli-decode.c (do_add_cmd): Use "new".
(delete_cmd): Use "delete".
---
gdb/ChangeLog | 8 ++++++
gdb/cli/cli-decode.c | 35 +++----------------------
gdb/cli/cli-decode.h | 74 ++++++++++++++++++++++++++++++++++++----------------
3 files changed, 62 insertions(+), 55 deletions(-)
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 0afe36aa4e..c8dda700ca 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -193,7 +193,8 @@ 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 = XNEW (struct cmd_list_element);
+ struct cmd_list_element *c = new struct cmd_list_element (name, theclass,
+ doc);
struct cmd_list_element *p, *iter;
/* Turn each alias of the old command into an alias of the new
@@ -227,34 +228,6 @@ do_add_cmd (const char *name, enum command_class theclass,
p->next = c;
}
- c->name = name;
- c->theclass = theclass;
- set_cmd_context (c, NULL);
- c->doc = doc;
- c->cmd_deprecated = 0;
- c->deprecated_warn_user = 0;
- c->malloced_replacement = 0;
- c->doc_allocated = 0;
- c->replacement = NULL;
- c->pre_show_hook = NULL;
- c->hook_in = 0;
- c->prefixlist = NULL;
- c->prefixname = NULL;
- c->allow_unknown = 0;
- c->prefix = NULL;
- c->abbrev_flag = 0;
- set_cmd_completer (c, symbol_completer);
- c->completer_handle_brkchars = NULL;
- c->destroyer = NULL;
- c->type = not_set_cmd;
- c->var = NULL;
- c->var_type = var_boolean;
- c->enums = NULL;
- c->user_commands = NULL;
- c->cmd_pointer = NULL;
- c->alias_chain = NULL;
- c->suppress_notification = NULL;
-
return c;
}
@@ -841,8 +814,6 @@ delete_cmd (const char *name, struct cmd_list_element **list,
*prehookee = iter->hookee_pre;
if (iter->hookee_post)
iter->hookee_post->hook_post = 0;
- if (iter->doc && iter->doc_allocated)
- xfree ((char *) iter->doc);
*posthook = iter->hook_post;
*posthookee = iter->hookee_post;
@@ -866,7 +837,7 @@ delete_cmd (const char *name, struct cmd_list_element **list,
*prevp = iter->alias_chain;
}
- xfree (iter);
+ delete iter;
/* We won't see another command with the same name. */
break;
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index 30b4fa7ca2..a3208e1fc6 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -45,8 +45,35 @@ cmd_types;
struct cmd_list_element
{
+ cmd_list_element (const char *name_, enum command_class theclass_,
+ const char *doc_)
+ : name (name_),
+ theclass (theclass_),
+ cmd_deprecated (0),
+ deprecated_warn_user (0),
+ malloced_replacement (0),
+ doc_allocated (0),
+ hook_in (0),
+ allow_unknown (0),
+ abbrev_flag (0),
+ type (not_set_cmd),
+ var_type (var_boolean),
+ doc (doc_)
+ {
+ memset (&function, 0, sizeof (function));
+ }
+
+ ~cmd_list_element ()
+ {
+ if (doc && doc_allocated)
+ xfree ((char *) doc);
+ }
+
+ DISABLE_COPY_AND_ASSIGN (cmd_list_element);
+
+
/* Points to next command in this list. */
- struct cmd_list_element *next;
+ struct cmd_list_element *next = nullptr;
/* Name of this command. */
const char *name;
@@ -107,7 +134,8 @@ struct cmd_list_element
cagney/2002-02-02: This function signature is evolving. For
the moment suggest sticking with either set_cmd_cfunc() or
set_cmd_sfunc(). */
- void (*func) (struct cmd_list_element *c, const char *args, int from_tty);
+ void (*func) (struct cmd_list_element *c, const char *args, int from_tty)
+ = nullptr;
/* The command's real callback. At present func() bounces through
to one of the below. */
union
@@ -121,7 +149,7 @@ struct cmd_list_element
function;
/* Local state (context) for this command. This can be anything. */
- void *context;
+ void *context = nullptr;
/* Documentation of this command (or help topic).
First line is brief documentation; remaining lines form, with it,
@@ -131,37 +159,37 @@ struct cmd_list_element
/* For set/show commands. A method for printing the output to the
specified stream. */
- show_value_ftype *show_value_func;
+ show_value_ftype *show_value_func = nullptr;
/* If this command is deprecated, this is the replacement name. */
- const char *replacement;
+ const char *replacement = nullptr;
/* If this command represents a show command, then this function
is called before the variable's value is examined. */
- void (*pre_show_hook) (struct cmd_list_element *c);
+ void (*pre_show_hook) (struct cmd_list_element *c) = nullptr;
/* Hook for another command to be executed before this command. */
- struct cmd_list_element *hook_pre;
+ struct cmd_list_element *hook_pre = nullptr;
/* Hook for another command to be executed after this command. */
- struct cmd_list_element *hook_post;
+ struct cmd_list_element *hook_post = nullptr;
/* Nonzero identifies a prefix command. For them, the address
of the variable containing the list of subcommands. */
- struct cmd_list_element **prefixlist;
+ struct cmd_list_element **prefixlist = nullptr;
/* For prefix commands only:
String containing prefix commands to get here: this one
plus any others needed to get to it. Should end in a space.
It is used before the word "command" in describing the
commands reached through this prefix. */
- const char *prefixname;
+ const char *prefixname = nullptr;
/* The prefix command of this command. */
- struct cmd_list_element *prefix;
+ struct cmd_list_element *prefix = nullptr;
/* Completion routine for this command. */
- completer_ftype *completer;
+ completer_ftype *completer = symbol_completer;
/* Handle the word break characters for this completer. Usually
this function need not be defined, but for some types of
@@ -169,47 +197,47 @@ struct cmd_list_element
a class) the word break chars may need to be redefined
depending on the completer type (e.g., for filename
completers). */
- completer_handle_brkchars_ftype *completer_handle_brkchars;
+ completer_handle_brkchars_ftype *completer_handle_brkchars = nullptr;
/* Destruction routine for this command. If non-NULL, this is
called when this command instance is destroyed. This may be
used to finalize the CONTEXT field, if needed. */
- void (*destroyer) (struct cmd_list_element *self, void *context);
+ void (*destroyer) (struct cmd_list_element *self, void *context) = nullptr;
/* Pointer to variable affected by "set" and "show". Doesn't
matter if type is not_set. */
- void *var;
+ void *var = nullptr;
/* Pointer to NULL terminated list of enumerated values (like
argv). */
- const char *const *enums;
+ const char *const *enums = nullptr;
/* Pointer to command strings of user-defined commands */
- struct command_line *user_commands;
+ struct command_line *user_commands = nullptr;
/* Pointer to command that is hooked by this one, (by hook_pre)
so the hook can be removed when this one is deleted. */
- struct cmd_list_element *hookee_pre;
+ struct cmd_list_element *hookee_pre = nullptr;
/* Pointer to command that is hooked by this one, (by hook_post)
so the hook can be removed when this one is deleted. */
- struct cmd_list_element *hookee_post;
+ struct cmd_list_element *hookee_post = nullptr;
/* Pointer to command that is aliased by this one, so the
aliased command can be located in case it has been hooked. */
- struct cmd_list_element *cmd_pointer;
+ struct cmd_list_element *cmd_pointer = nullptr;
/* Start of a linked list of all aliases of this command. */
- struct cmd_list_element *aliases;
+ struct cmd_list_element *aliases = nullptr;
/* Link pointer for aliases on an alias list. */
- struct cmd_list_element *alias_chain;
+ struct cmd_list_element *alias_chain = nullptr;
/* If non-null, the pointer to a field in 'struct
cli_suppress_notification', which will be set to true in cmd_func
when this command is being executed. It will be set back to false
when the command has been executed. */
- int *suppress_notification;
+ int *suppress_notification = nullptr;
};
extern void help_cmd_list (struct cmd_list_element *, enum command_class,
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 4/8] Constify prompt argument to read_command_lines
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (4 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 1/8] Allocate cmd_list_element with new Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 15:41 ` [RFA v2 2/8] Use counted_command_line everywhere Tom Tromey
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
The prompt argument to read_command_lines can be const. This patch
makes this change, and also removes some fixed-sized buffers in favor
of using string_printf.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
* tracepoint.c (actions_command): Update.
* cli/cli-script.h (read_command_lines): Update.
* cli/cli-script.c (read_command_lines): Constify prompt_arg.
(MAX_TMPBUF): Remove define.
(define_command): Use string_printf.
(document_command): Likewise.
* breakpoint.c (commands_command_1): Update.
---
gdb/ChangeLog | 10 ++++++++++
gdb/breakpoint.c | 3 +--
gdb/cli/cli-script.c | 20 +++++++++-----------
gdb/cli/cli-script.h | 2 +-
gdb/tracepoint.c | 3 ++-
5 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2cb9c4b657..7d284e9a96 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1256,8 +1256,7 @@ commands_command_1 (const char *arg, int from_tty,
"%s, one per line."),
arg);
- cmd = read_command_lines (&str[0],
- from_tty, 1,
+ cmd = read_command_lines (str.c_str (), from_tty, 1,
(is_tracepoint (b)
? check_tracepoint_command : 0),
b);
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index c7d405c0d0..36740b97ad 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -1121,7 +1121,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
#define END_MESSAGE "End with a line saying just \"end\"."
counted_command_line
-read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
+read_command_lines (const char *prompt_arg, int from_tty, int parse_commands,
void (*validator)(char *, void *), void *closure)
{
if (from_tty && input_interactive_p (current_ui))
@@ -1306,7 +1306,6 @@ user_defined_command (const char *ignore, int from_tty)
static void
define_command (const char *comname, int from_tty)
{
-#define MAX_TMPBUF 128
enum cmd_hook_type
{
CMD_NO_HOOK = 0,
@@ -1315,7 +1314,6 @@ define_command (const char *comname, int from_tty)
};
struct cmd_list_element *c, *newc, *hookc = 0, **list;
const char *tem, *comfull;
- char tmpbuf[MAX_TMPBUF];
int hook_type = CMD_NO_HOOK;
int hook_name_size = 0;
@@ -1379,9 +1377,10 @@ define_command (const char *comname, int from_tty)
comname = xstrdup (comname);
- xsnprintf (tmpbuf, sizeof (tmpbuf),
- "Type commands for definition of \"%s\".", comfull);
- counted_command_line cmds = read_command_lines (tmpbuf, from_tty, 1, 0, 0);
+ std::string prompt
+ = string_printf ("Type commands for definition of \"%s\".", comfull);
+ counted_command_line cmds = read_command_lines (prompt.c_str (), from_tty,
+ 1, 0, 0);
newc = add_cmd (comname, class_user, user_defined_command,
(c && c->theclass == class_user)
@@ -1416,7 +1415,6 @@ document_command (const char *comname, int from_tty)
struct cmd_list_element *c, **list;
const char *tem;
const char *comfull;
- char tmpbuf[128];
comfull = comname;
list = validate_comname (&comname);
@@ -1427,10 +1425,10 @@ document_command (const char *comname, int from_tty)
if (c->theclass != class_user)
error (_("Command \"%s\" is built-in."), comfull);
- xsnprintf (tmpbuf, sizeof (tmpbuf), "Type documentation for \"%s\".",
- comfull);
- counted_command_line doclines = read_command_lines (tmpbuf, from_tty,
- 0, 0, 0);
+ std::string prompt = string_printf ("Type documentation for \"%s\".",
+ comfull);
+ counted_command_line doclines = read_command_lines (prompt.c_str (),
+ from_tty, 0, 0, 0);
if (c->doc)
xfree ((char *) c->doc);
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 10b6c17789..7e5f94c0ad 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -105,7 +105,7 @@ private:
}
};
-extern counted_command_line read_command_lines (char *, int, int,
+extern counted_command_line read_command_lines (const char *, int, int,
void (*)(char *, void *),
void *);
extern counted_command_line read_command_lines_1 (char * (*) (void), int,
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7fb05f8fca..e6cd565985 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -578,7 +578,8 @@ actions_command (const char *args, int from_tty)
string_printf ("Enter actions for tracepoint %d, one per line.",
t->number);
- counted_command_line l = read_command_lines (&tmpbuf[0], from_tty, 1,
+ counted_command_line l = read_command_lines (tmpbuf.c_str (),
+ from_tty, 1,
check_tracepoint_command,
t);
breakpoint_set_commands (t, std::move (l));
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 2/8] Use counted_command_line everywhere
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (5 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 4/8] Constify prompt argument to read_command_lines Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-04-25 15:41 ` [RFA v2 5/8] Allow defining a user command inside a user command Tom Tromey
2018-05-04 19:09 ` [RFA v2 0/8] Various command-related improvements Pedro Alves
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Currently command lines are reference counted using shared_ptr only
when attached to breakpoints. This patch changes gdb to use
shared_ptr in commands as well. This allows for the removal of
copy_command_lines.
Note that the change to execute_user_command explicitly makes a new
reference to the command line. This will be used in a later patch.
This simplifies struct command_line based on the observation that a
given command can have at most two child bodies: an "if" can have both
"then" and "else" parts. Perhaps the names I've chosen for the
replacements here are not very good -- your input requested.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
* tracepoint.c (all_tracepoint_actions): Rename from
all_tracepoint_actions_and_cleanup. Change return type.
(actions_command, encode_actions_1, encode_actions)
(trace_dump_actions, tdump_command): Update.
* remote.c (remote_download_command_source): Update.
* python/python.c (gdbpy_eval_from_control_command)
(python_command, python_interactive_command): Update.
* mi/mi-cmd-break.c (mi_cmd_break_commands): Update.
* guile/guile.c (guile_command)
(gdbscm_eval_from_control_command, guile_command): Update.
* compile/compile.c (compile_code_command)
(compile_print_command, compile_to_object): Update.
* cli/cli-script.h (struct command_lines_deleter): New.
(counted_command_line): New typedef.
(struct command_line): Add constructor, destructor.
<body_list>: Remove.
<body_list_0, body_list_1>: New members.
(command_line_up): Remove typedef.
(read_command_lines, read_command_lines_1, get_command_line):
Update.
(copy_command_lines): Don't declare.
* cli/cli-script.c (build_command_line): Use "new".
(get_command_line): Return counted_command_line.
(print_command_lines, execute_user_command)
(execute_control_command_1, while_command, if_command): Update.
(realloc_body_list): Remove.
(process_next_line, recurse_read_control_structure): Update.
(read_command_lines, read_command_lines_1): Return counted_command_line.
(free_command_lines): Use "delete".
(copy_command_lines): Remove.
(define_command, document_command, show_user_1): Update.
* cli/cli-decode.h (struct cmd_list_element) <user_commands>: Now
a counted_command_line.
* breakpoint.h (counted_command_line): Remove typedef.
(breakpoint_set_commands): Update.
* breakpoint.c (check_no_tracepoint_commands)
(validate_commands_for_breakpoint): Update.
(breakpoint_set_commands): Change commands to be a
counted_command_line.
(commands_command_1, update_dprintf_command_list)
(create_tracepoint_from_upload): Update.
---
gdb/ChangeLog | 44 ++++++++++++
gdb/breakpoint.c | 30 ++++----
gdb/breakpoint.h | 6 +-
gdb/cli/cli-decode.h | 3 +-
gdb/cli/cli-script.c | 190 ++++++++++++--------------------------------------
gdb/cli/cli-script.h | 66 +++++++++++-------
gdb/compile/compile.c | 6 +-
gdb/guile/guile.c | 8 +--
gdb/mi/mi-cmd-break.c | 2 +-
gdb/python/python.c | 8 +--
gdb/remote.c | 2 +-
gdb/tracepoint.c | 61 +++++++---------
12 files changed, 183 insertions(+), 243 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 11b89bcf88..2cb9c4b657 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1015,8 +1015,8 @@ check_no_tracepoint_commands (struct command_line *commands)
error (_("The 'while-stepping' command can "
"only be used for tracepoints"));
- for (i = 0; i < c->body_count; ++i)
- check_no_tracepoint_commands ((c->body_list)[i]);
+ check_no_tracepoint_commands (c->body_list_0.get ());
+ check_no_tracepoint_commands (c->body_list_1.get ());
/* Not that command parsing removes leading whitespace and comment
lines and also empty lines. So, we only need to check for
@@ -1127,8 +1127,8 @@ validate_commands_for_breakpoint (struct breakpoint *b,
{
struct command_line *c2;
- gdb_assert (while_stepping->body_count == 1);
- c2 = while_stepping->body_list[0];
+ gdb_assert (while_stepping->body_list_1 == nullptr);
+ c2 = while_stepping->body_list_0.get ();
for (; c2; c2 = c2->next)
{
if (c2->control_type == while_stepping_control)
@@ -1168,7 +1168,7 @@ static_tracepoints_here (CORE_ADDR addr)
void
breakpoint_set_commands (struct breakpoint *b,
- command_line_up &&commands)
+ counted_command_line &&commands)
{
validate_commands_for_breakpoint (b, commands.get ());
@@ -1248,7 +1248,7 @@ commands_command_1 (const char *arg, int from_tty,
if (cmd == NULL)
{
if (control != NULL)
- cmd = copy_command_lines (control->body_list[0]);
+ cmd = control->body_list_0;
else
{
std::string str
@@ -8781,18 +8781,12 @@ update_dprintf_command_list (struct breakpoint *b)
_("Invalid dprintf style."));
gdb_assert (printf_line != NULL);
- /* Manufacture a printf sequence. */
- {
- struct command_line *printf_cmd_line = XNEW (struct command_line);
-
- printf_cmd_line->control_type = simple_control;
- printf_cmd_line->body_count = 0;
- printf_cmd_line->body_list = NULL;
- printf_cmd_line->next = NULL;
- printf_cmd_line->line = printf_line;
- breakpoint_set_commands (b, command_line_up (printf_cmd_line));
- }
+ /* Manufacture a printf sequence. */
+ struct command_line *printf_cmd_line
+ = new struct command_line (simple_control, printf_line);
+ breakpoint_set_commands (b, counted_command_line (printf_cmd_line,
+ command_lines_deleter ()));
}
/* Update all dprintf commands, making their command lists reflect
@@ -14796,7 +14790,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
function. */
if (!utp->cmd_strings.empty ())
{
- command_line_up cmd_list;
+ counted_command_line cmd_list;
this_utp = utp;
next_cmd = 0;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 062e390469..f3c2599286 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -661,10 +661,6 @@ enum watchpoint_triggered
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
-/* A reference-counted struct command_line. This is an implementation
- detail to the breakpoints module. */
-typedef std::shared_ptr<command_line> counted_command_line;
-
/* Some targets (e.g., embedded PowerPC) need two debug registers to set
a watchpoint over a memory region. If this flag is true, GDB will use
only one register per watchpoint, thus assuming that all acesses that
@@ -1479,7 +1475,7 @@ extern void disable_breakpoint (struct breakpoint *);
extern void enable_breakpoint (struct breakpoint *);
extern void breakpoint_set_commands (struct breakpoint *b,
- command_line_up &&commands);
+ counted_command_line &&commands);
extern void breakpoint_set_silent (struct breakpoint *b, int silent);
diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h
index a3208e1fc6..e18b709767 100644
--- a/gdb/cli/cli-decode.h
+++ b/gdb/cli/cli-decode.h
@@ -24,6 +24,7 @@
/* Include the public interfaces. */
#include "command.h"
#include "gdb_regex.h"
+#include "cli-script.h"
#if 0
/* FIXME: cagney/2002-03-17: Once cmd_type() has been removed, ``enum
@@ -213,7 +214,7 @@ struct cmd_list_element
const char *const *enums = nullptr;
/* Pointer to command strings of user-defined commands */
- struct command_line *user_commands = nullptr;
+ counted_command_line user_commands;
/* Pointer to command that is hooked by this one, (by hook_pre)
so the hook can be removed when this one is deleted. */
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index cdfda113a7..b066da7d60 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -134,32 +134,23 @@ multi_line_command_p (enum command_control_type type)
static struct command_line *
build_command_line (enum command_control_type type, const char *args)
{
- struct command_line *cmd;
-
if ((args == NULL || *args == '\0')
&& (type == if_control || type == while_control))
error (_("if/while commands require arguments."));
gdb_assert (args != NULL);
- cmd = XNEW (struct command_line);
- cmd->next = NULL;
- cmd->control_type = type;
-
- cmd->body_count = 1;
- cmd->body_list = XCNEWVEC (struct command_line *, cmd->body_count);
- cmd->line = xstrdup (args);
-
- return cmd;
+ return new struct command_line (type, xstrdup (args));
}
/* Build and return a new command structure for the control commands
such as "if" and "while". */
-command_line_up
+counted_command_line
get_command_line (enum command_control_type type, const char *arg)
{
/* Allocate and build a new command line structure. */
- command_line_up cmd (build_command_line (type, arg));
+ counted_command_line cmd (build_command_line (type, arg),
+ command_lines_deleter ());
/* Read in the body of this command. */
if (recurse_read_control_structure (read_next_line, cmd.get (), 0, 0)
@@ -228,7 +219,7 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
else
uiout->field_string (NULL, list->line);
uiout->text ("\n");
- print_command_lines (uiout, *list->body_list, depth + 1);
+ print_command_lines (uiout, list->body_list_0.get (), depth + 1);
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "end");
@@ -244,16 +235,16 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
uiout->field_fmt (NULL, "if %s", list->line);
uiout->text ("\n");
/* The true arm. */
- print_command_lines (uiout, list->body_list[0], depth + 1);
+ print_command_lines (uiout, list->body_list_0.get (), depth + 1);
/* Show the false arm if it exists. */
- if (list->body_count == 2)
+ if (list->body_list_1 != nullptr)
{
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "else");
uiout->text ("\n");
- print_command_lines (uiout, list->body_list[1], depth + 1);
+ print_command_lines (uiout, list->body_list_1.get (), depth + 1);
}
if (depth)
@@ -273,7 +264,7 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
else
uiout->field_string (NULL, "commands");
uiout->text ("\n");
- print_command_lines (uiout, *list->body_list, depth + 1);
+ print_command_lines (uiout, list->body_list_0.get (), depth + 1);
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "end");
@@ -287,7 +278,7 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
uiout->field_string (NULL, "python");
uiout->text ("\n");
/* Don't indent python code at all. */
- print_command_lines (uiout, *list->body_list, 0);
+ print_command_lines (uiout, list->body_list_0.get (), 0);
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "end");
@@ -300,7 +291,7 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
{
uiout->field_string (NULL, "compile expression");
uiout->text ("\n");
- print_command_lines (uiout, *list->body_list, 0);
+ print_command_lines (uiout, list->body_list_0.get (), 0);
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "end");
@@ -313,7 +304,7 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
{
uiout->field_string (NULL, "guile");
uiout->text ("\n");
- print_command_lines (uiout, *list->body_list, depth + 1);
+ print_command_lines (uiout, list->body_list_0.get (), depth + 1);
if (depth)
uiout->spaces (2 * depth);
uiout->field_string (NULL, "end");
@@ -377,14 +368,17 @@ void
execute_user_command (struct cmd_list_element *c, const char *args)
{
struct ui *ui = current_ui;
- struct command_line *cmdlines;
+ counted_command_line cmdlines_copy;
enum command_control_type ret;
extern unsigned int max_user_call_depth;
- cmdlines = c->user_commands;
- if (cmdlines == 0)
+ /* Ensure that the user commands can't be deleted while they are
+ executing. */
+ cmdlines_copy = c->user_commands;
+ if (cmdlines_copy == 0)
/* Null command */
return;
+ struct command_line *cmdlines = cmdlines_copy.get ();
scoped_user_args_level push_user_args (args);
@@ -527,7 +521,7 @@ execute_control_command_1 (struct command_line *cmd)
break;
/* Execute the body of the while statement. */
- current = *cmd->body_list;
+ current = cmd->body_list_0.get ();
while (current)
{
scoped_restore save_nesting
@@ -581,9 +575,9 @@ execute_control_command_1 (struct command_line *cmd)
/* Choose which arm to take commands from based on the value
of the conditional expression. */
if (value_true (val))
- current = *cmd->body_list;
- else if (cmd->body_count == 2)
- current = *(cmd->body_list + 1);
+ current = cmd->body_list_0.get ();
+ else if (cmd->body_list_1 != nullptr)
+ current = cmd->body_list_1.get ();
value_free_to_mark (val_mark);
/* Execute commands in the given arm. */
@@ -665,7 +659,7 @@ static void
while_command (const char *arg, int from_tty)
{
control_level = 1;
- command_line_up command = get_command_line (while_control, arg);
+ counted_command_line command = get_command_line (while_control, arg);
if (command == NULL)
return;
@@ -682,7 +676,7 @@ static void
if_command (const char *arg, int from_tty)
{
control_level = 1;
- command_line_up command = get_command_line (if_control, arg);
+ counted_command_line command = get_command_line (if_control, arg);
if (command == NULL)
return;
@@ -828,31 +822,6 @@ user_args::insert_args (const char *line) const
}
\f
-/* Expand the body_list of COMMAND so that it can hold NEW_LENGTH
- code bodies. This is typically used when we encounter an "else"
- clause for an "if" command. */
-
-static void
-realloc_body_list (struct command_line *command, int new_length)
-{
- int n;
- struct command_line **body_list;
-
- n = command->body_count;
-
- /* Nothing to do? */
- if (new_length <= n)
- return;
-
- body_list = XCNEWVEC (struct command_line *, new_length);
-
- memcpy (body_list, command->body_list, sizeof (struct command_line *) * n);
-
- xfree (command->body_list);
- command->body_list = body_list;
- command->body_count = new_length;
-}
-
/* Read next line from stdin. Passed to read_command_line_1 and
recurse_read_control_structure whenever we need to read commands
from stdin. */
@@ -1012,23 +981,9 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
*command = build_command_line (guile_control, "");
}
else if (p_end - p == 10 && startswith (p, "loop_break"))
- {
- *command = XNEW (struct command_line);
- (*command)->next = NULL;
- (*command)->line = NULL;
- (*command)->control_type = break_control;
- (*command)->body_count = 0;
- (*command)->body_list = NULL;
- }
+ *command = new struct command_line (break_control);
else if (p_end - p == 13 && startswith (p, "loop_continue"))
- {
- *command = XNEW (struct command_line);
- (*command)->next = NULL;
- (*command)->line = NULL;
- (*command)->control_type = continue_control;
- (*command)->body_count = 0;
- (*command)->body_list = NULL;
- }
+ *command = new struct command_line (continue_control);
else
not_handled = 1;
}
@@ -1036,12 +991,8 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
if (!parse_commands || not_handled)
{
/* A normal command. */
- *command = XNEW (struct command_line);
- (*command)->next = NULL;
- (*command)->line = savestring (p, p_end - p);
- (*command)->control_type = simple_control;
- (*command)->body_count = 0;
- (*command)->body_list = NULL;
+ *command = new struct command_line (simple_control,
+ savestring (p, p_end - p));
}
if (validator)
@@ -1053,7 +1004,7 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
}
CATCH (ex, RETURN_MASK_ALL)
{
- xfree (*command);
+ free_command_lines (command);
throw_exception (ex);
}
END_CATCH
@@ -1073,21 +1024,17 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
void (*validator)(char *, void *),
void *closure)
{
- int current_body, i;
enum misc_command_type val;
enum command_control_type ret;
struct command_line **body_ptr, *child_tail, *next;
+ counted_command_line *current_body = ¤t_cmd->body_list_0;
child_tail = NULL;
- current_body = 1;
/* Sanity checks. */
if (current_cmd->control_type == simple_control)
error (_("Recursed on a simple control type."));
- if (current_body > current_cmd->body_count)
- error (_("Allocated body is smaller than this command type needs."));
-
/* Read lines from the input stream and build control structures. */
while (1)
{
@@ -1123,10 +1070,9 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
if (val == else_command)
{
if (current_cmd->control_type == if_control
- && current_body == 1)
+ && current_body == ¤t_cmd->body_list_0)
{
- realloc_body_list (current_cmd, 2);
- current_body = 2;
+ current_body = ¤t_cmd->body_list_1;
child_tail = NULL;
continue;
}
@@ -1142,14 +1088,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
child_tail->next = next;
}
else
- {
- body_ptr = current_cmd->body_list;
- for (i = 1; i < current_body; i++)
- body_ptr++;
-
- *body_ptr = next;
-
- }
+ *current_body = counted_command_line (next, command_lines_deleter ());
child_tail = next;
@@ -1183,7 +1122,7 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
#define END_MESSAGE "End with a line saying just \"end\"."
-command_line_up
+counted_command_line
read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
void (*validator)(char *, void *), void *closure)
{
@@ -1205,7 +1144,7 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
/* Reading commands assumes the CLI behavior, so temporarily
override the current interpreter with CLI. */
- command_line_up head;
+ counted_command_line head (nullptr, command_lines_deleter ());
if (current_interp_named_p (INTERP_CONSOLE))
head = read_command_lines_1 (read_next_line, parse_commands,
validator, closure);
@@ -1228,12 +1167,12 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
/* Act the same way as read_command_lines, except that each new line is
obtained using READ_NEXT_LINE_FUNC. */
-command_line_up
+counted_command_line
read_command_lines_1 (char * (*read_next_line_func) (void), int parse_commands,
void (*validator)(char *, void *), void *closure)
{
struct command_line *tail, *next;
- command_line_up head;
+ counted_command_line head (nullptr, command_lines_deleter ());
enum command_control_type ret;
enum misc_command_type val;
@@ -1279,7 +1218,7 @@ read_command_lines_1 (char * (*read_next_line_func) (void), int parse_commands,
}
else
{
- head.reset (next);
+ head = counted_command_line (next, command_lines_deleter ());
}
tail = next;
}
@@ -1299,54 +1238,15 @@ free_command_lines (struct command_line **lptr)
{
struct command_line *l = *lptr;
struct command_line *next;
- struct command_line **blist;
- int i;
while (l)
{
- if (l->body_count > 0)
- {
- blist = l->body_list;
- for (i = 0; i < l->body_count; i++, blist++)
- free_command_lines (blist);
- }
next = l->next;
- xfree (l->line);
- xfree (l);
+ delete l;
l = next;
}
*lptr = NULL;
}
-
-command_line_up
-copy_command_lines (struct command_line *cmds)
-{
- struct command_line *result = NULL;
-
- if (cmds)
- {
- result = XNEW (struct command_line);
-
- result->next = copy_command_lines (cmds->next).release ();
- result->line = xstrdup (cmds->line);
- result->control_type = cmds->control_type;
- result->body_count = cmds->body_count;
- if (cmds->body_count > 0)
- {
- int i;
-
- result->body_list = XNEWVEC (struct command_line *, cmds->body_count);
-
- for (i = 0; i < cmds->body_count; i++)
- result->body_list[i]
- = copy_command_lines (cmds->body_list[i]).release ();
- }
- else
- result->body_list = NULL;
- }
-
- return command_line_up (result);
-}
\f
/* Validate that *COMNAME is a valid name for a command. Return the
containing command list, in case it starts with a prefix command.
@@ -1483,15 +1383,12 @@ define_command (const char *comname, int from_tty)
xsnprintf (tmpbuf, sizeof (tmpbuf),
"Type commands for definition of \"%s\".", comfull);
- command_line_up cmds = read_command_lines (tmpbuf, from_tty, 1, 0, 0);
-
- if (c && c->theclass == class_user)
- free_command_lines (&c->user_commands);
+ counted_command_line cmds = read_command_lines (tmpbuf, from_tty, 1, 0, 0);
newc = add_cmd (comname, class_user, user_defined_command,
(c && c->theclass == class_user)
? c->doc : xstrdup ("User-defined."), list);
- newc->user_commands = cmds.release ();
+ newc->user_commands = std::move (cmds);
/* If this new command is a hook, then mark both commands as being
tied. */
@@ -1534,7 +1431,8 @@ document_command (const char *comname, int from_tty)
xsnprintf (tmpbuf, sizeof (tmpbuf), "Type documentation for \"%s\".",
comfull);
- command_line_up doclines = read_command_lines (tmpbuf, from_tty, 0, 0, 0);
+ counted_command_line doclines = read_command_lines (tmpbuf, from_tty,
+ 0, 0, 0);
if (c->doc)
xfree ((char *) c->doc);
@@ -1611,7 +1509,7 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
return;
}
- cmdlines = c->user_commands;
+ cmdlines = c->user_commands.get ();
fprintf_filtered (stream, "User command \"%s%s\":\n", prefix, name);
if (!cmdlines)
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 518c8a80b8..58dede2342 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -45,12 +45,38 @@ enum command_control_type
invalid_control
};
+struct command_line;
+
+extern void free_command_lines (struct command_line **);
+
+/* A deleter for command_line that calls free_command_lines. */
+
+struct command_lines_deleter
+{
+ void operator() (command_line *cmd_lines) const
+ {
+ free_command_lines (&cmd_lines);
+ }
+};
+
+/* A reference-counted struct command_line. */
+typedef std::shared_ptr<command_line> counted_command_line;
+
/* * Structure for saved commands lines (for breakpoints, defined
commands, etc). */
struct command_line
{
- struct command_line *next;
+ explicit command_line (command_control_type type_, char *line_ = nullptr)
+ : line (line_),
+ control_type (type_)
+ {
+ memset (&control_u, 0, sizeof (control_u));
+ }
+
+ DISABLE_COPY_AND_ASSIGN (command_line);
+
+ struct command_line *next = nullptr;
char *line;
enum command_control_type control_type;
union
@@ -63,36 +89,28 @@ struct command_line
compile;
}
control_u;
- /* * The number of elements in body_list. */
- int body_count;
/* * For composite commands, the nested lists of commands. For
example, for "if" command this will contain the then branch and
the else branch, if that is available. */
- struct command_line **body_list;
-};
+ counted_command_line body_list_0;
+ counted_command_line body_list_1;
-extern void free_command_lines (struct command_line **);
+private:
-/* A deleter for command_line that calls free_command_lines. */
+ friend void free_command_lines (struct command_line **);
-struct command_lines_deleter
-{
- void operator() (command_line *cmd_lines) const
+ ~command_line ()
{
- free_command_lines (&cmd_lines);
+ xfree (line);
}
};
-/* A unique pointer to a command_line. */
-
-typedef std::unique_ptr<command_line, command_lines_deleter> command_line_up;
-
-extern command_line_up read_command_lines (char *, int, int,
- void (*)(char *, void *),
- void *);
-extern command_line_up read_command_lines_1 (char * (*) (void), int,
- void (*)(char *, void *),
- void *);
+extern counted_command_line read_command_lines (char *, int, int,
+ void (*)(char *, void *),
+ void *);
+extern counted_command_line read_command_lines_1 (char * (*) (void), int,
+ void (*)(char *, void *),
+ void *);
/* Exported to cli/cli-cmds.c */
@@ -112,14 +130,12 @@ extern enum command_control_type
extern enum command_control_type
execute_control_command_untraced (struct command_line *cmd);
-extern command_line_up get_command_line (enum command_control_type,
- const char *);
+extern counted_command_line get_command_line (enum command_control_type,
+ const char *);
extern void print_command_lines (struct ui_out *,
struct command_line *, unsigned int);
-extern command_line_up copy_command_lines (struct command_line *cmds);
-
/* Exported to gdb/infrun.c */
extern void execute_user_command (struct cmd_list_element *c, const char *args);
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 7f35272872..01c0bc4b39 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -149,7 +149,7 @@ compile_code_command (const char *arg, int from_tty)
eval_compile_command (NULL, arg, scope, NULL);
else
{
- command_line_up l = get_command_line (compile_control, "");
+ counted_command_line l = get_command_line (compile_control, "");
l->control_u.compile.scope = scope;
execute_control_command_untraced (l.get ());
@@ -187,7 +187,7 @@ compile_print_command (const char *arg, int from_tty)
eval_compile_command (NULL, arg, scope, &fmt);
else
{
- command_line_up l = get_command_line (compile_control, "");
+ counted_command_line l = get_command_line (compile_control, "");
l->control_u.compile.scope = scope;
l->control_u.compile.scope_data = &fmt;
@@ -512,7 +512,7 @@ compile_to_object (struct command_line *cmd, const char *cmd_string,
{
struct command_line *iter;
- for (iter = cmd->body_list[0]; iter; iter = iter->next)
+ for (iter = cmd->body_list_0.get (); iter; iter = iter->next)
{
input_buf.puts (iter->line);
input_buf.puts ("\n");
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index 8fc12dd876..0bbbf6eac1 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -209,7 +209,7 @@ guile_command (const char *arg, int from_tty)
}
else
{
- command_line_up l = get_command_line (guile_control, "");
+ counted_command_line l = get_command_line (guile_control, "");
execute_control_command_untraced (l.get ());
}
@@ -256,12 +256,12 @@ gdbscm_eval_from_control_command
char *script, *msg;
struct cleanup *cleanup;
- if (cmd->body_count != 1)
+ if (cmd->body_list_1 != nullptr)
error (_("Invalid \"guile\" block structure."));
cleanup = make_cleanup (null_cleanup, NULL);
- script = compute_scheme_string (cmd->body_list[0]);
+ script = compute_scheme_string (cmd->body_list_0.get ());
msg = gdbscm_safe_eval_string (script, 0);
xfree (script);
if (msg != NULL)
@@ -408,7 +408,7 @@ guile_command (const char *arg, int from_tty)
{
/* Even if Guile isn't enabled, we still have to slurp the
command list to the corresponding "end". */
- command_line_up l = get_command_line (guile_control, "");
+ counted_command_line l = get_command_line (guile_control, "");
execute_control_command_untraced (l.get ());
}
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index c1f5e2d924..1772fad43c 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -489,7 +489,7 @@ mi_read_next_line (void)
void
mi_cmd_break_commands (const char *command, char **argv, int argc)
{
- command_line_up break_command;
+ counted_command_line break_command;
char *endptr;
int bnum;
struct breakpoint *b;
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 9eae8a1aef..45b6516fc2 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -385,12 +385,12 @@ gdbpy_eval_from_control_command (const struct extension_language_defn *extlang,
{
int ret;
- if (cmd->body_count != 1)
+ if (cmd->body_list_1 != nullptr)
error (_("Invalid \"python\" block structure."));
gdbpy_enter enter_py (get_current_arch (), current_language);
- std::string script = compute_python_string (cmd->body_list[0]);
+ std::string script = compute_python_string (cmd->body_list_0.get ());
ret = PyRun_SimpleString (script.c_str ());
if (ret)
error (_("Error while executing Python code."));
@@ -413,7 +413,7 @@ python_command (const char *arg, int from_tty)
}
else
{
- command_line_up l = get_command_line (python_control, "");
+ counted_command_line l = get_command_line (python_control, "");
execute_control_command_untraced (l.get ());
}
@@ -1582,7 +1582,7 @@ python_interactive_command (const char *arg, int from_tty)
error (_("Python scripting is not supported in this copy of GDB."));
else
{
- command_line_up l = get_command_line (python_control, "");
+ counted_command_line l = get_command_line (python_control, "");
execute_control_command_untraced (l.get ());
}
diff --git a/gdb/remote.c b/gdb/remote.c
index 61d1dcb573..94cb34440e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -12248,7 +12248,7 @@ remote_download_command_source (int num, ULONGEST addr,
if (cmd->control_type == while_control
|| cmd->control_type == while_stepping_control)
{
- remote_download_command_source (num, addr, *cmd->body_list);
+ remote_download_command_source (num, addr, cmd->body_list_0.get ());
QUIT; /* Allow user to bail out with ^C. */
strcpy (rs->buf, "QTDPsrc:");
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7e173ce75d..7fb05f8fca 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -167,8 +167,7 @@ char *trace_stop_notes = NULL;
struct collection_list;
static char *mem2hex (gdb_byte *, char *, int);
-static struct command_line *
- all_tracepoint_actions_and_cleanup (struct breakpoint *t);
+static counted_command_line all_tracepoint_actions (struct breakpoint *);
static struct trace_status trace_status;
@@ -579,8 +578,9 @@ actions_command (const char *args, int from_tty)
string_printf ("Enter actions for tracepoint %d, one per line.",
t->number);
- command_line_up l = read_command_lines (&tmpbuf[0], from_tty, 1,
- check_tracepoint_command, t);
+ counted_command_line l = read_command_lines (&tmpbuf[0], from_tty, 1,
+ check_tracepoint_command,
+ t);
breakpoint_set_commands (t, std::move (l));
}
/* else just return */
@@ -1437,7 +1437,7 @@ encode_actions_1 (struct command_line *action,
here. */
gdb_assert (stepping_list);
- encode_actions_1 (action->body_list[0], tloc, frame_reg,
+ encode_actions_1 (action->body_list_0.get (), tloc, frame_reg,
frame_offset, stepping_list, NULL);
}
else
@@ -1453,17 +1453,17 @@ encode_actions (struct bp_location *tloc,
struct collection_list *tracepoint_list,
struct collection_list *stepping_list)
{
- struct command_line *actions;
int frame_reg;
LONGEST frame_offset;
gdbarch_virtual_frame_pointer (tloc->gdbarch,
tloc->address, &frame_reg, &frame_offset);
- actions = all_tracepoint_actions_and_cleanup (tloc->owner);
-
- encode_actions_1 (actions, tloc, frame_reg, frame_offset,
+ counted_command_line actions = all_tracepoint_actions (tloc->owner);
+ encode_actions_1 (actions.get (), tloc, frame_reg, frame_offset,
tracepoint_list, stepping_list);
+ encode_actions_1 (breakpoint_commands (tloc->owner), tloc,
+ frame_reg, frame_offset, tracepoint_list, stepping_list);
tracepoint_list->finish ();
stepping_list->finish ();
@@ -2663,11 +2663,9 @@ trace_dump_actions (struct command_line *action,
if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
{
- int i;
-
- for (i = 0; i < action->body_count; ++i)
- trace_dump_actions (action->body_list[i],
- 1, stepping_frame, from_tty);
+ gdb_assert (action->body_list_1 == nullptr);
+ trace_dump_actions (action->body_list_0.get (),
+ 1, stepping_frame, from_tty);
}
else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
{
@@ -2778,16 +2776,12 @@ get_traceframe_location (int *stepping_frame_p)
return t->loc;
}
-/* Return all the actions, including default collect, of a tracepoint
- T. It constructs cleanups into the chain, and leaves the caller to
- handle them (call do_cleanups). */
+/* Return the default collect actions of a tracepoint T. */
-static struct command_line *
-all_tracepoint_actions_and_cleanup (struct breakpoint *t)
+static counted_command_line
+all_tracepoint_actions (struct breakpoint *t)
{
- struct command_line *actions;
-
- actions = breakpoint_commands (t);
+ counted_command_line actions (nullptr, command_lines_deleter ());
/* If there are default expressions to collect, make up a collect
action and prepend to the action list to encode. Note that since
@@ -2797,17 +2791,13 @@ all_tracepoint_actions_and_cleanup (struct breakpoint *t)
if (*default_collect)
{
struct command_line *default_collect_action;
- char *default_collect_line;
-
- default_collect_line = xstrprintf ("collect %s", default_collect);
- make_cleanup (xfree, default_collect_line);
+ gdb::unique_xmalloc_ptr<char> default_collect_line
+ (xstrprintf ("collect %s", default_collect));
- validate_actionline (default_collect_line, t);
- default_collect_action = XNEW (struct command_line);
- make_cleanup (xfree, default_collect_action);
- default_collect_action->next = actions;
- default_collect_action->line = default_collect_line;
- actions = default_collect_action;
+ validate_actionline (default_collect_line.get (), t);
+ actions.reset (new struct command_line (simple_control,
+ default_collect_line.release ()),
+ command_lines_deleter ());
}
return actions;
@@ -2820,7 +2810,6 @@ tdump_command (const char *args, int from_tty)
{
int stepping_frame = 0;
struct bp_location *loc;
- struct command_line *actions;
/* This throws an error is not inspecting a trace frame. */
loc = get_traceframe_location (&stepping_frame);
@@ -2834,9 +2823,11 @@ tdump_command (const char *args, int from_tty)
select_frame (get_current_frame ());
- actions = all_tracepoint_actions_and_cleanup (loc->owner);
+ counted_command_line actions = all_tracepoint_actions (loc->owner);
- trace_dump_actions (actions, 0, stepping_frame, from_tty);
+ trace_dump_actions (actions.get (), 0, stepping_frame, from_tty);
+ trace_dump_actions (breakpoint_commands (loc->owner), 0, stepping_frame,
+ from_tty);
}
/* Encode a piece of a tracepoint's source-level definition in a form
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFA v2 5/8] Allow defining a user command inside a user command
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (6 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 2/8] Use counted_command_line everywhere Tom Tromey
@ 2018-04-25 15:41 ` Tom Tromey
2018-05-04 19:09 ` [RFA v2 0/8] Various command-related improvements Pedro Alves
8 siblings, 0 replies; 14+ messages in thread
From: Tom Tromey @ 2018-04-25 15:41 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
PR gdb/11750 concerns defining a command inside a user commnad, like:
define outer
define inner
echo hi\n
end
end
This patch adds this capability to gdb.
gdb/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR gdb/11750:
* cli/cli-script.h (enum command_control_type) <define_control>:
New constant.
* cli/cli-script.c (multi_line_command_p): Handle define_control.
(build_command_line, execute_control_command_1)
(process_next_line): Likewise.
(do_define_command): New function, extracted from define_command.
(define_command): Use it.
gdb/testsuite/ChangeLog
2018-04-25 Tom Tromey <tom@tromey.com>
PR gdb/11750:
* gdb.base/define.exp: Test defining a user command inside a user
command.
* gdb.base/commands.exp (define_if_without_arg_test): Test "define".
---
gdb/ChangeLog | 11 ++++++++
gdb/cli/cli-script.c | 56 ++++++++++++++++++++++++++++++-------
gdb/cli/cli-script.h | 1 +
gdb/testsuite/ChangeLog | 7 +++++
gdb/testsuite/gdb.base/commands.exp | 4 +--
gdb/testsuite/gdb.base/define.exp | 8 ++++++
6 files changed, 75 insertions(+), 12 deletions(-)
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 36740b97ad..d679e04e55 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -44,6 +44,9 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
void (*validator)(char *, void *),
void *closure);
+static void do_define_command (const char *comname, int from_tty,
+ const counted_command_line *commands);
+
static char *read_next_line (void);
/* Level of control structure when reading. */
@@ -122,6 +125,7 @@ multi_line_command_p (enum command_control_type type)
case compile_control:
case python_control:
case guile_control:
+ case define_control:
return 1;
default:
return 0;
@@ -134,9 +138,15 @@ multi_line_command_p (enum command_control_type type)
static struct command_line *
build_command_line (enum command_control_type type, const char *args)
{
- if ((args == NULL || *args == '\0')
- && (type == if_control || type == while_control))
- error (_("if/while commands require arguments."));
+ if (args == NULL || *args == '\0')
+ {
+ if (type == if_control)
+ error (_("if command requires an argument."));
+ else if (type == while_control)
+ error (_("while command requires an argument."));
+ else if (type == define_control)
+ error (_("define command requires an argument."));
+ }
gdb_assert (args != NULL);
return new struct command_line (type, xstrdup (args));
@@ -611,6 +621,12 @@ execute_control_command_1 (struct command_line *cmd)
ret = simple_control;
break;
+ case define_control:
+ print_command_trace ("define %s", cmd->line);
+ do_define_command (cmd->line, 0, &cmd->body_list_0);
+ ret = simple_control;
+ break;
+
case python_control:
case guile_control:
{
@@ -960,6 +976,8 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
{
*command = build_command_line (commands_control, line_first_arg (p));
}
+ else if (command_name_equals (cmd, "define"))
+ *command = build_command_line (define_control, line_first_arg (p));
else if (command_name_equals (cmd, "python") && !inline_cmd)
{
/* Note that we ignore the inline "python command" form
@@ -1303,8 +1321,15 @@ user_defined_command (const char *ignore, int from_tty)
{
}
+/* Define a user-defined command. If COMMANDS is NULL, then this is a
+ top-level call and the commands will be read using
+ read_command_lines. Otherwise, it is a "define" command in an
+ existing command and the commands are provided. In the
+ non-top-level case, various prompts and warnings are disabled. */
+
static void
-define_command (const char *comname, int from_tty)
+do_define_command (const char *comname, int from_tty,
+ const counted_command_line *commands)
{
enum cmd_hook_type
{
@@ -1331,7 +1356,7 @@ define_command (const char *comname, int from_tty)
if (c && strcmp (comname, c->name) != 0)
c = 0;
- if (c)
+ if (c && commands == nullptr)
{
int q;
@@ -1365,7 +1390,7 @@ define_command (const char *comname, int from_tty)
hookc = lookup_cmd (&tem, *list, "", -1, 0);
if (hookc && strcmp (comname + hook_name_size, hookc->name) != 0)
hookc = 0;
- if (!hookc)
+ if (!hookc && commands == nullptr)
{
warning (_("Your new `%s' command does not "
"hook any existing command."),
@@ -1377,10 +1402,15 @@ define_command (const char *comname, int from_tty)
comname = xstrdup (comname);
- std::string prompt
- = string_printf ("Type commands for definition of \"%s\".", comfull);
- counted_command_line cmds = read_command_lines (prompt.c_str (), from_tty,
- 1, 0, 0);
+ counted_command_line cmds;
+ if (commands == nullptr)
+ {
+ std::string prompt
+ = string_printf ("Type commands for definition of \"%s\".", comfull);
+ cmds = read_command_lines (prompt.c_str (), from_tty, 1, 0, 0);
+ }
+ else
+ cmds = *commands;
newc = add_cmd (comname, class_user, user_defined_command,
(c && c->theclass == class_user)
@@ -1410,6 +1440,12 @@ define_command (const char *comname, int from_tty)
}
static void
+define_command (const char *comname, int from_tty)
+{
+ do_define_command (comname, from_tty, nullptr);
+}
+
+static void
document_command (const char *comname, int from_tty)
{
struct cmd_list_element *c, **list;
diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h
index 7e5f94c0ad..0bd0d597ae 100644
--- a/gdb/cli/cli-script.h
+++ b/gdb/cli/cli-script.h
@@ -42,6 +42,7 @@ enum command_control_type
compile_control,
guile_control,
while_stepping_control,
+ define_control,
invalid_control
};
diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp
index b33e5124ec..259b89b803 100644
--- a/gdb/testsuite/gdb.base/commands.exp
+++ b/gdb/testsuite/gdb.base/commands.exp
@@ -1014,7 +1014,7 @@ proc_with_prefix redefine_backtrace_test {} {
# Test using "if" and "while" without args when building a command list.
proc define_if_without_arg_test {} {
- foreach cmd {if while} {
+ foreach cmd {if while define} {
set test "define some_command_$cmd"
gdb_test_multiple $test $test {
-re "End with" {
@@ -1022,7 +1022,7 @@ proc define_if_without_arg_test {} {
}
}
- gdb_test "$cmd" "if/while commands require arguments." "type $cmd without args"
+ gdb_test "$cmd" "$cmd command requires an argument." "type $cmd without args"
}
}
diff --git a/gdb/testsuite/gdb.base/define.exp b/gdb/testsuite/gdb.base/define.exp
index f82a9efdff..e4064b7afc 100644
--- a/gdb/testsuite/gdb.base/define.exp
+++ b/gdb/testsuite/gdb.base/define.exp
@@ -298,5 +298,13 @@ gdb_test_multiple "set prompt \\(gdb\\) " "reset gdb_prompt" {
}
}
+gdb_test_multiple "define do-define" "" {
+ -re "Type commands for definition of \"do-define\".\r\nEnd with a line saying just \"end\".\r\n>$" {
+ gdb_test "define do-printit\necho here\\n\nend\nend" "" "define do-define"
+ }
+}
+gdb_test_no_output "do-define" "invoke do-define"
+gdb_test "do-printit" "here" "invoke do-printit"
+
gdb_exit
return 0
--
2.13.6
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFA v2 0/8] Various command-related improvements
2018-04-25 15:41 [RFA v2 0/8] Various command-related improvements Tom Tromey
` (7 preceding siblings ...)
2018-04-25 15:41 ` [RFA v2 5/8] Allow defining a user command inside a user command Tom Tromey
@ 2018-05-04 19:09 ` Pedro Alves
8 siblings, 0 replies; 14+ messages in thread
From: Pedro Alves @ 2018-05-04 19:09 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 04/25/2018 04:41 PM, Tom Tromey wrote:
> Here's v2 of the series that improves commands in a few ways.
>
> I believe this version addresses all the review comments.
Indeed it does. Looks good, thanks.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 14+ messages in thread