From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 56572 invoked by alias); 9 Nov 2016 00:19:39 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 56533 invoked by uid 89); 9 Nov 2016 00:19:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.8 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=8606, dots, exercises, dfp X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 09 Nov 2016 00:19:36 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BD52283F38 for ; Wed, 9 Nov 2016 00:19:35 +0000 (UTC) Received: from cascais.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uA90JVUk022260 for ; Tue, 8 Nov 2016 19:19:35 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v2 3/5] Fix PR 20559 - "eval" command and $arg0...$arg9/$argc substitution Date: Wed, 09 Nov 2016 00:19:00 -0000 Message-Id: <1478650771-24430-4-git-send-email-palves@redhat.com> In-Reply-To: <1478650771-24430-1-git-send-email-palves@redhat.com> References: <1478650771-24430-1-git-send-email-palves@redhat.com> X-SW-Source: 2016-11/txt/msg00195.txt.bz2 It'd be handy to be able to iterate over command arguments in user-defined commands, in order to support optional arguments ($arg0..$argN). I thought I could make it work with "eval", but alas, it doesn't work currently. E.g., with: define test set $i = 0 while $i < $argc eval "print $arg%d", $i set $i = $i + 1 end end we get: (gdb) test 1 $1 = void (gdb) test 1 2 3 $2 = void $3 = void $4 = void (gdb) The problem is that "eval" doesn't do user-defined command arguments substitution after expanding its own argument. This patch fixes that, which makes the example above work: (gdb) test 1 $1 = 1 (gdb) test 1 2 3 $2 = 1 $3 = 2 $4 = 3 (gdb) New test included, similar the above, but also exercises expanding $argc. I think this is likely to simplify many scripts out there, so I'm adding an example to the manual and mentioning it in NEWS as well. gdb/ChangeLog: yyyy-mm-dd Pedro Alves PR cli/20559 * NEWS: Mention "eval" expands user-defined command arguments. * cli/cli-script.c (execute_control_command): Adjust to rename. (insert_args): Rename to ... (insert_user_defined_cmd_args): ... this, and make extern. * cli/cli-script.h (insert_user_defined_cmd_args): New declaration. * printcmd.c: Include "cli/cli-script.h". (eval_command): Call insert_user_defined_cmd_args. gdb/doc/ChangeLog: yyyy-mm-dd Pedro Alves PR cli/20559 * gdb.texinfo (Define): Add example of using "eval" to process a variable number of arguments. (Output) : Add anchor. gdb/testsuite/ChangeLog: yyyy-mm-dd Pedro Alves PR cli/20559 * gdb.base/commands.exp (user_defined_command_args_eval): New procedure. (top level): Call it. --- gdb/doc/gdb.texinfo | 16 ++++++++++++++++ gdb/NEWS | 12 ++++++++++++ gdb/cli/cli-script.c | 19 ++++++++----------- gdb/cli/cli-script.h | 6 ++++++ gdb/printcmd.c | 3 +++ gdb/testsuite/gdb.base/commands.exp | 31 +++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index df548dc..5311912 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -24096,6 +24096,21 @@ define adder end @end smallexample +Combining with the @code{eval} command (@pxref{eval}) makes it easier +to process a variable number of arguments: + +@smallexample +define adder + set $i = 0 + set $sum = 0 + while $i < $argc + eval "set $sum = $sum + $arg%d", $i + set $i = $i + 1 + end + print $sum +end +@end smallexample + @table @code @kindex define @@ -24526,6 +24541,7 @@ Here's an example of printing DFP types using the above conversion letters: printf "D32: %Hf - D64: %Df - D128: %DDf\n",1.2345df,1.2E10dd,1.2E1dl @end smallexample +@anchor{eval} @kindex eval @item eval @var{template}, @var{expressions}@dots{} Convert the values of one or more @var{expressions} under the control of diff --git a/gdb/NEWS b/gdb/NEWS index a6b1282..790629b 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -27,6 +27,18 @@ * Support for Java programs compiled with gcj has been removed. +* The "eval" command now expands user-defined command arguments. + + This makes it easier to process a variable number of arguments: + + define mycommand + set $i = 0 + while $i < $argc + eval "print $arg%d", $i + set $i = $i + 1 + end + end + * New targets Synopsys ARC arc*-*-elf32 diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index ce4d8cb..15947a9 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -41,8 +41,6 @@ recurse_read_control_structure (char * (*read_next_line_func) (void), void (*validator)(char *, void *), void *closure); -static std::string insert_args (const char *line); - static struct cleanup * setup_user_args (char *p); static char *read_next_line (void); @@ -455,7 +453,7 @@ execute_control_command (struct command_line *cmd) case simple_control: { /* A simple command, execute it and return. */ - std::string new_line = insert_args (cmd->line); + std::string new_line = insert_user_defined_cmd_args (cmd->line); execute_command (&new_line[0], 0); ret = cmd->control_type; break; @@ -486,7 +484,7 @@ execute_control_command (struct command_line *cmd) print_command_trace (buffer); /* Parse the loop control expression for the while statement. */ - std::string new_line = insert_args (cmd->line); + std::string new_line = insert_user_defined_cmd_args (cmd->line); expression_up expr = parse_expression (new_line.c_str ()); ret = simple_control; @@ -551,7 +549,7 @@ execute_control_command (struct command_line *cmd) print_command_trace (buffer); /* Parse the conditional for the if statement. */ - std::string new_line = insert_args (cmd->line); + std::string new_line = insert_user_defined_cmd_args (cmd->line); expression_up expr = parse_expression (new_line.c_str ()); current = NULL; @@ -591,7 +589,7 @@ execute_control_command (struct command_line *cmd) { /* Breakpoint commands list, record the commands in the breakpoint's command list and return. */ - std::string new_line = insert_args (cmd->line); + std::string new_line = insert_user_defined_cmd_args (cmd->line); ret = commands_from_control_command (new_line.c_str (), cmd); break; } @@ -782,13 +780,12 @@ locate_arg (const char *p) return NULL; } -/* Insert the user defined arguments stored in user_arg into the $arg - arguments found in line. */ +/* See cli-script.h. */ -static std::string -insert_args (const char *line) +std::string +insert_user_defined_cmd_args (const char *line) { - /* If we are not in a user-defined function, treat $argc, $arg0, et + /* If we are not in a user-defined command, treat $argc, $arg0, et cetera as normal convenience variables. */ if (user_args == NULL) return line; diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h index 7db6e82..8920d44 100644 --- a/gdb/cli/cli-script.h +++ b/gdb/cli/cli-script.h @@ -53,6 +53,12 @@ extern struct cleanup * extern void execute_user_command (struct cmd_list_element *c, char *args); +/* If we're in a user-defined command, replace any $argc/$argN + reference found in LINE with the arguments that were passed to the + command. Otherwise, treat $argc/$argN as normal convenience + variables. */ +extern std::string insert_user_defined_cmd_args (const char *line); + /* Exported to top.c */ extern void print_command_trace (const char *cmd); diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 23de57c..4004ee7 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -45,6 +45,7 @@ #include "charset.h" #include "arch-utils.h" #include "cli/cli-utils.h" +#include "cli/cli-script.h" #include "format.h" #include "source.h" @@ -2724,6 +2725,8 @@ eval_command (char *arg, int from_tty) std::string expanded = ui_file_as_string (ui_out); + expanded = insert_user_defined_cmd_args (expanded.c_str ()); + execute_command (&expanded[0], from_tty); do_cleanups (cleanups); diff --git a/gdb/testsuite/gdb.base/commands.exp b/gdb/testsuite/gdb.base/commands.exp index b6c8f9e..0ac2267 100644 --- a/gdb/testsuite/gdb.base/commands.exp +++ b/gdb/testsuite/gdb.base/commands.exp @@ -340,6 +340,36 @@ proc_with_prefix user_defined_command_test {} { "display user-defined empty command" } +# Test that "eval" in a user-defined command expands $argc/$argN. + +proc_with_prefix user_defined_command_args_eval {} { + global gdb_prompt + + gdb_test_multiple "define command_args_eval" \ + "define command_args_eval" { + -re "End with" { + pass "define" + } + } + + # Make a command that constructs references to $argc and $argN via + # eval. + gdb_test \ + [multi_line \ + {eval "printf \"argc = %%d,\", $arg%c", 'c'} \ + {set $i = 0} \ + {while $i < $argc} \ + { eval "printf \" %%d\", $arg%d", $i} \ + { set $i = $i + 1} \ + {end} \ + {printf "\n"} \ + {end}] \ + "" \ + "enter commands" + + gdb_test "command_args_eval 1 2 3" "argc = 3, 1 2 3" "execute command" +} + proc_with_prefix watchpoint_command_test {} { global gdb_prompt @@ -860,6 +890,7 @@ if_while_breakpoint_command_test infrun_breakpoint_command_test breakpoint_command_test user_defined_command_test +user_defined_command_args_eval watchpoint_command_test test_command_prompt_position deprecated_command_test -- 2.5.5