From 0f8cdd9ba42a878a78380901afe4e2031935ca1f Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 30 Dec 1994 19:53:39 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 27 +++++ gdb/NEWS | 13 +++ gdb/breakpoint.c | 8 +- gdb/top.c | 288 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 314 insertions(+), 22 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f4f5c697be..1e4505bb28 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 * hppa-tdep.c (pa_print_registers): Extract register values stored diff --git a/gdb/NEWS b/gdb/NEWS index 0c447119cb..0af1c67cfc 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -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. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index aa9ebf678c..629a53bf73 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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; } } diff --git a/gdb/top.c b/gdb/top.c index 7ac7b1b1b6..ce199b8216 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -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)