* Allow up to 10 whitespace separated arguments to user defined

commands.
        * top.c (struct user_args): Structure for holding arguments to
        user defined commands.
        (print_command_line): Delete unused "tmp_chain" variable.  Clean
        up flow control by having cases exit in the same manner.
        Before executing a command or evaluating an expression, substitute
        the current $arg0..$arg9 values if the command/expression uses them.
        (arg_cleanup): New function.
        (setup_user_args, locate_arg, insert_args): Likewise.
        (execute_user_command): Allow arguments to user defined commands.

        * Allow if/while commands to be used within a breakpoint command
        list.
        * breakpoint.c (bpstat_do_actions): Call execute_control_command
        rather than execute_command (passes entire command structure rather
        than just the command line text).
        (breakpoint_1): Use "print_command_line" to print a breakpoint
        command line (including control structures).
        * gdbcmd.h (execute_control_command): Provide extern decl.
        (print_command_line): Likewise.
        * top.c (execute_control_command): No longer static.
        (print_command_line): New function to recursively print a command
        line, including control structures.
This commit is contained in:
Jeff Law 1994-12-30 19:53:39 +00:00
parent 15edf5253b
commit 0f8cdd9ba4
4 changed files with 314 additions and 22 deletions

View File

@ -1,3 +1,30 @@
Thu Dec 29 22:40:00 1994 Jeff Law (law@snake.cs.utah.edu)
* Allow up to 10 whitespace separated arguments to user defined
commands.
* top.c (struct user_args): Structure for holding arguments to
user defined commands.
(print_command_line): Delete unused "tmp_chain" variable. Clean
up flow control by having cases exit in the same manner.
Before executing a command or evaluating an expression, substitute
the current $arg0..$arg9 values if the command/expression uses them.
(arg_cleanup): New function.
(setup_user_args, locate_arg, insert_args): Likewise.
(execute_user_command): Allow arguments to user defined commands.
* Allow if/while commands to be used within a breakpoint command
list.
* breakpoint.c (bpstat_do_actions): Call execute_control_command
rather than execute_command (passes entire command structure rather
than just the command line text).
(breakpoint_1): Use "print_command_line" to print a breakpoint
command line (including control structures).
* gdbcmd.h (execute_control_command): Provide extern decl.
(print_command_line): Likewise.
* top.c (execute_control_command): No longer static.
(print_command_line): New function to recursively print a command
line, including control structures.
Thu Dec 29 18:18:31 1994 Rob Savoye <rob@darkstar.cygnus.com>
* hppa-tdep.c (pa_print_registers): Extract register values stored

View File

@ -1,6 +1,19 @@
What has changed since GDB-3.5?
(Organized release by release)
* User commands may accept up to 10 arguments separated by whitespace.
Arguments are accessed within the user command via $arg0..$arg0.
A trivial example:
define adder
print $arg0 + $arg1 + $arg2
To execute the command use:
adder 1 2 3
Defines the command "adder" which prints the sum of its three arguments.
Note the arguments are text substitutions, so they may reference variables,
use complex expressions, or even perform inferior function calls.
* New "if" and "while" commands. This makes it possible to write
somewhat more sophisticated user-defined commands.

View File

@ -947,9 +947,9 @@ top:
{
while (bs->commands)
{
char *line = bs->commands->line;
struct command_line *cmd = bs->commands;
bs->commands = bs->commands->next;
execute_command (line, 0);
execute_control_command (cmd);
/* If the inferior is proceeded by the command, bomb out now.
The bpstat chain has been blown away by wait_for_inferior.
But since execution has stopped again, there is a new bpstat
@ -1793,9 +1793,7 @@ breakpoint_1 (bnum, allflag)
while (l)
{
fputs_filtered ("\t", gdb_stdout);
fputs_filtered (l->line, gdb_stdout);
fputs_filtered ("\n", gdb_stdout);
print_command_line (l, 4);
l = l->next;
}
}

288
gdb/top.c
View File

@ -68,9 +68,6 @@ static void while_command PARAMS ((char *, int));
static void if_command PARAMS ((char *, int));
static enum command_control_type
execute_control_command PARAMS ((struct command_line *));
static struct command_line *
build_command_line PARAMS ((enum command_control_type, char *));
@ -84,6 +81,14 @@ static enum misc_command_type read_next_line PARAMS ((struct command_line **));
static enum command_control_type
recurse_read_control_structure PARAMS ((struct command_line *));
static struct cleanup * setup_user_args PARAMS ((char *));
static char * locate_arg PARAMS ((char *));
static char * insert_args PARAMS ((char *));
static void arg_cleanup PARAMS ((void));
static void init_main PARAMS ((void));
static void init_cmd_lists PARAMS ((void));
@ -318,6 +323,19 @@ int remote_debug = 0;
/* Level of control structure. */
static int control_level;
/* Structure for arguments to user defined functions. */
#define MAXUSERARGS 10
struct user_args
{
struct user_args *next;
struct
{
char *arg;
int len;
} a[MAXUSERARGS];
int count;
} *user_args;
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
#ifndef STOP_SIGNAL
@ -646,41 +664,130 @@ get_command_line (type, arg)
return cmd;
}
/* Recursively print a command (including full control structures). */
void
print_command_line (cmd, depth)
struct command_line *cmd;
unsigned int depth;
{
unsigned int i;
if (depth)
{
for (i = 0; i < depth; i++)
fputs_filtered (" ", gdb_stdout);
}
/* A simple command, print it and return. */
if (cmd->control_type == simple_control)
{
fputs_filtered (cmd->line, gdb_stdout);
fputs_filtered ("\n", gdb_stdout);
return;
}
/* loop_continue to jump to the start of a while loop, print it
and return. */
if (cmd->control_type == continue_control)
{
fputs_filtered ("loop_continue\n", gdb_stdout);
return;
}
/* loop_break to break out of a while loop, print it and return. */
if (cmd->control_type == break_control)
{
fputs_filtered ("loop_break\n", gdb_stdout);
return;
}
/* A while command. Recursively print its subcommands before returning. */
if (cmd->control_type == while_control)
{
struct command_line *list;
fputs_filtered ("while ", gdb_stdout);
fputs_filtered (cmd->line, gdb_stdout);
fputs_filtered ("\n", gdb_stdout);
list = *cmd->body_list;
while (list)
{
print_command_line (list, depth + 1);
list = list->next;
}
}
/* An if command. Recursively print both arms before returning. */
if (cmd->control_type == if_control)
{
fputs_filtered ("if ", gdb_stdout);
fputs_filtered (cmd->line, gdb_stdout);
fputs_filtered ("\n", gdb_stdout);
/* The true arm. */
print_command_line (cmd->body_list[0], depth + 1);
/* Show the false arm if it exists. */
if (cmd->body_count == 2)
{
if (depth)
{
for (i = 0; i < depth; i++)
fputs_filtered (" ", gdb_stdout);
}
fputs_filtered ("else\n", gdb_stdout);
print_command_line (cmd->body_list[1], depth + 1);
}
if (depth)
{
for (i = 0; i < depth; i++)
fputs_filtered (" ", gdb_stdout);
}
fputs_filtered ("end\n", gdb_stdout);
}
}
/* Execute the command in CMD. */
static enum command_control_type
enum command_control_type
execute_control_command (cmd)
struct command_line *cmd;
{
struct expression *expr;
struct command_line *current;
struct cleanup *old_chain = 0;
struct cleanup *tmp_chain;
value_ptr val;
int loop;
enum command_control_type ret;
char *new_line;
switch (cmd->control_type)
{
case simple_control:
/* A simple command, execute it and return. */
execute_command (cmd->line, 0);
return cmd->control_type;
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
execute_command (new_line, 0);
ret = cmd->control_type;
break;
case continue_control:
case break_control:
/* Return for "continue", and "break" so we can either
continue the loop at the top, or break out. */
return cmd->control_type;
ret = cmd->control_type;
break;
case while_control:
{
/* Parse the loop control expression for the while statement. */
expr = parse_expression (cmd->line);
tmp_chain = make_cleanup (free_current_contents, &expr);
if (!old_chain)
old_chain = tmp_chain;
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
expr = parse_expression (new_line);
make_cleanup (free_current_contents, &expr);
ret = simple_control;
loop = true;
@ -727,9 +834,13 @@ execute_control_command (cmd)
case if_control:
{
new_line = insert_args (cmd->line);
if (!new_line)
return invalid_control;
old_chain = make_cleanup (free_current_contents, &new_line);
/* Parse the conditional for the if statement. */
expr = parse_expression (cmd->line);
old_chain = make_cleanup (free_current_contents, &expr);
expr = parse_expression (new_line);
make_cleanup (free_current_contents, &expr);
current = NULL;
ret = simple_control;
@ -756,6 +867,7 @@ execute_control_command (cmd)
/* Get the next statement in the body. */
current = current->next;
}
break;
}
@ -810,6 +922,149 @@ if_command (arg, from_tty)
free_command_lines (&command);
}
/* Cleanup */
static void
arg_cleanup ()
{
struct user_args *oargs = user_args;
if (!user_args)
fatal ("Internal error, arg_cleanup called with no user args.\n");
user_args = user_args->next;
free (oargs);
}
/* Bind the incomming arguments for a user defined command to
$arg0, $arg1 ... $argMAXUSERARGS. */
static struct cleanup *
setup_user_args (p)
char *p;
{
struct user_args *args;
struct cleanup *old_chain;
unsigned int arg_count = 0;
args = (struct user_args *)xmalloc (sizeof (struct user_args));
memset (args, 0, sizeof (struct user_args));
args->next = user_args;
user_args = args;
old_chain = make_cleanup (arg_cleanup, 0);
if (p == NULL)
return old_chain;
while (*p)
{
char *start_arg;
if (arg_count >= MAXUSERARGS)
{
error ("user defined function may only have %d arguments.\n",
MAXUSERARGS);
return old_chain;
}
/* Strip whitespace. */
while (*p == ' ' || *p == '\t')
p++;
/* P now points to an argument. */
start_arg = p;
user_args->a[arg_count].arg = p;
/* Get to the end of this argument. */
while (*p && *p != ' ' && *p != '\t')
p++;
user_args->a[arg_count].len = p - start_arg;
arg_count++;
user_args->count++;
}
return old_chain;
}
/* Given character string P, return a point to the first argument ($arg),
or NULL if P contains no arguments. */
static char *
locate_arg (p)
char *p;
{
while (p = index (p, '$'))
{
if (strncmp (p, "$arg", 4) == 0 && isdigit (p[4]))
return p;
p++;
}
return NULL;
}
/* Insert the user defined arguments stored in user_arg into the $arg
arguments found in line, with the updated copy being placed into nline. */
static char *
insert_args (line)
char *line;
{
char *p, *save_line, *new_line;
unsigned len, i;
/* First we need to know how much memory to allocate for the new line. */
save_line = line;
len = 0;
while (p = locate_arg (line))
{
len += p - line;
i = p[4] - '0';
if (i >= user_args->count)
{
error ("Missing argument %d in user function.\n", i);
return NULL;
}
len += user_args->a[i].len;
line = p + 5;
}
/* Don't forget the tail. */
len += strlen (line);
/* Allocate space for the new line and fill it in. */
new_line = (char *)xmalloc (len + 1);
if (new_line == NULL)
return NULL;
/* Restore pointer to beginning of old line. */
line = save_line;
/* Save pointer to beginning of new line. */
save_line = new_line;
while (p = locate_arg (line))
{
int i, len;
memcpy (new_line, line, p - line);
new_line += p - line;
i = p[4] - '0';
if (len = user_args->a[i].len)
{
memcpy (new_line, user_args->a[i].arg, len);
new_line += len;
}
line = p + 5;
}
/* Don't forget the tail. */
strcpy (new_line, line);
/* Return a pointer to the beginning of the new line. */
return save_line;
}
void
execute_user_command (c, args)
struct cmd_list_element *c;
@ -819,8 +1074,7 @@ execute_user_command (c, args)
struct cleanup *old_chain;
enum command_control_type ret;
if (args)
error ("User-defined commands cannot take arguments.");
old_chain = setup_user_args (args);
cmdlines = c->user_commands;
if (cmdlines == 0)