From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9305 invoked by alias); 18 Dec 2001 23:48:45 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 8915 invoked from network); 18 Dec 2001 23:48:38 -0000 Received: from unknown (HELO cygnus.com) (205.180.230.5) by sources.redhat.com with SMTP; 18 Dec 2001 23:48:38 -0000 Received: from theotherone.redhat-remotie.org (taarna.cygnus.com [205.180.230.102]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id PAA17696 for ; Tue, 18 Dec 2001 15:48:35 -0800 (PST) Received: from localhost (localhost.fidalgo.net [127.0.0.1]) by theotherone.redhat-remotie.org (Postfix) with ESMTP id 3DE7CBB2E2 for ; Tue, 18 Dec 2001 15:48:18 -0800 (PST) Date: Tue, 18 Dec 2001 15:48:00 -0000 From: Don Howard X-X-Sender: To: Subject: [RFA] error-catching mechanism for scripts In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-SW-Source: 2001-12/txt/msg00449.txt.bz2 Here is an implementation of the error-catcher that I mentioned a few weeks ago. I chose "try" and "except" as the keywords: try some commands that might error end -- or -- try some commands that might error except some commands to recover from error (errors in this block will not be caught) end I've included a quick write-up for the gdb manual. I'll submit new tests for the testsuite shortly. 2001-12-18 Don Howard * cli/cli-script.h: New function. * cli/cli-script.c (build_command_line): Add support for try command. (print_command_lines): Ditto. (print_command_line): Ditto. (execute_control_command): Ditto. (read_next_line): Ditto. (recurse_read_control_structure): Ditto. (captured_execute_control_command): New function. (try_command): Ditto. * cli/cli-cmds.c (init_cli_cmds): Add try command. * defs.h (enum misc_command_type): Added enum except_command. (enum command_control_type): Exclude zero from the range of command_control_type. Added enum try_control. 2001-12-18 Don Howard * gdb.texinfo (User-defined commands): New section, documenting try/except feature. Index: defs.h =================================================================== RCS file: /cvs/src/src/gdb/defs.h,v retrieving revision 1.68 diff -p -u -w -r1.68 defs.h --- defs.h 2001/12/15 16:53:22 1.68 +++ defs.h 2001/12/18 23:45:33 @@ -811,16 +811,18 @@ enum misc_command_type ok_command, end_command, else_command, + except_command, nop_command }; enum command_control_type { - simple_control, + simple_control = 1, break_control, continue_control, while_control, if_control, + try_control, invalid_control }; Index: cli/cli-cmds.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v retrieving revision 1.10 diff -p -u -w -r1.10 cli-cmds.c --- cli-cmds.c 2001/09/01 21:38:05 1.10 +++ cli-cmds.c 2001/12/18 23:45:34 @@ -721,6 +721,12 @@ The conditional expression must follow t followed by a new line. The nested commands must be entered one per line,\n\ and should be terminated by the word `end'."); + add_com ("try", class_support, try_command, +"Execute nested commands. On error, terminate execution of the 'try' block\n\ +and execute the optional 'except' block. Commands must be entered one per line,\n\ +terminating with the word 'end'."); + + add_com ("if", class_support, if_command, "Execute nested commands once IF the conditional expression is non zero.\n\ The conditional expression must follow the word `if' and must in turn be\n\ Index: cli/cli-script.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.c,v retrieving revision 1.8 diff -p -u -w -r1.8 cli-script.c --- cli-script.c 2001/12/13 22:42:23 1.8 +++ cli-script.c 2001/12/18 23:45:34 @@ -83,7 +83,7 @@ build_command_line (enum command_control { struct command_line *cmd; - if (args == NULL) + if (args == NULL && type != try_control) error ("if/while commands require arguments.\n"); cmd = (struct command_line *) xmalloc (sizeof (struct command_line)); @@ -95,7 +95,12 @@ build_command_line (enum command_control = (struct command_line **) xmalloc (sizeof (struct command_line *) * cmd->body_count); memset (cmd->body_list, 0, sizeof (struct command_line *) * cmd->body_count); + + if (type != try_control) cmd->line = savestring (args, strlen (args)); + else + cmd->line = savestring ("", strlen ("")); + return cmd; } @@ -208,6 +213,33 @@ print_command_lines (struct ui_out *uiou continue; } + /* A try command. Recursively print the try and catch blocks + before continuing. */ + if (list->control_type == try_control) + { + ui_out_field_string (uiout, NULL, "try"); + ui_out_text (uiout, "\n"); + /* The true arm. */ + print_command_lines (uiout, list->body_list[0], depth + 1); + + /* Show the except arm if it exists. */ + if (list->body_count == 2) + { + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_field_string (uiout, NULL, "except"); + ui_out_text (uiout, "\n"); + print_command_lines (uiout, list->body_list[1], depth + 1); + } + + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_field_string (uiout, NULL, "end"); + ui_out_text (uiout, "\n"); + list = list->next; + continue; + } + /* ignore illegal command type and try next */ list = list->next; } /* while (list) */ @@ -290,7 +322,33 @@ print_command_line (struct command_line } fputs_filtered ("end\n", stream); } + + /* A try command. Recursively print both try and catch blocks. */ + if (cmd->control_type == try_control) + { + fputs_filtered ("try\n", stream); + /* The true arm. */ + print_command_line (cmd->body_list[0], depth + 1, stream); + + /* Show the catch block if it exists. */ + if (cmd->body_count == 2) + { + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); + } + fputs_filtered ("except\n", stream); + print_command_line (cmd->body_list[1], depth + 1, stream); + } + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); } + fputs_filtered ("end\n", stream); + } +} #endif /* Execute the command in CMD. */ @@ -326,6 +384,13 @@ execute_user_command (struct cmd_list_el do_cleanups (old_chain); } +static int +captured_execute_control_command (PTR arg) +{ + struct command_line * cmd = (struct command_line *) arg; + return execute_control_command (cmd); +} + enum command_control_type execute_control_command (struct command_line *cmd) { @@ -459,6 +524,30 @@ execute_control_command (struct command_ break; } + case try_control: + { + current = cmd->body_list[0]; + + while (current) + { + ret = catch_errors (captured_execute_control_command, current, + "", RETURN_MASK_ALL); + + if (ret == 0 || ret == invalid_control) + { + if (cmd->body_count == 2) + current = cmd->body_list[1]; + else + current = NULL; + } + else + { + current = current->next; + } + } + break; + } + default: warning ("Invalid control type in command structure."); return invalid_control; @@ -506,6 +595,21 @@ if_command (char *arg, int from_tty) free_command_lines (&command); } +void +try_command (char *block, int from_tty) +{ + struct command_line *command = NULL; + + control_level = 1; + command = get_command_line (try_control, block); + + if (command == NULL) + return; + + execute_control_command (command); + free_command_lines (&command); +} + /* Cleanup */ static void arg_cleanup (void *ignore) @@ -758,12 +862,18 @@ read_next_line (struct command_line **co if (p1 - p == 4 && !strncmp (p, "else", 4)) return else_command; + /* Is the except clause of an if try structure? */ + if (p1 - p == 6 && !strncmp (p, "except", 6)) + return except_command; + /* Check for while, if, break, continue, etc and build a new command line structure for them. */ if (p1 - p > 5 && !strncmp (p, "while", 5)) *command = build_command_line (while_control, p + 6); else if (p1 - p > 2 && !strncmp (p, "if", 2)) *command = build_command_line (if_control, p + 3); + else if (p1 - p == 3 && !strncmp (p, "try", 3)) + *command = build_command_line (try_control, p + 4); else if (p1 - p == 10 && !strncmp (p, "loop_break", 10)) { *command = (struct command_line *) @@ -845,7 +955,8 @@ recurse_read_control_structure (struct c if (val == end_command) { if (current_cmd->control_type == while_control - || current_cmd->control_type == if_control) + || current_cmd->control_type == if_control + || current_cmd->control_type == try_control) { /* Success reading an entire control structure. */ ret = simple_control; @@ -876,6 +987,23 @@ recurse_read_control_structure (struct c } } + if (val == except_command) + { + if (current_cmd->control_type == try_control + && current_body == 1) + { + realloc_body_list (current_cmd, 2); + current_body = 2; + child_tail = NULL; + continue; + } + else + { + ret = invalid_control; + break; + } + } + if (child_tail) { child_tail->next = next; @@ -895,7 +1023,8 @@ recurse_read_control_structure (struct c /* If the latest line is another control structure, then recurse on it. */ if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); @@ -962,7 +1091,8 @@ read_command_lines (char *prompt_arg, in } if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); Index: cli/cli-script.h =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.h,v retrieving revision 1.2 diff -p -u -w -r1.2 cli-script.h --- cli-script.h 2001/03/06 08:21:20 1.2 +++ cli-script.h 2001/12/18 23:45:34 @@ -31,6 +31,8 @@ extern void while_command (char *arg, in extern void if_command (char *arg, int from_tty); +extern void try_command (char *block, int from_tty); + extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream); /* Exported to gdb/breakpoint.c */ Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.59 diff -p -u -w -r1.59 gdb.texinfo --- gdb.texinfo 2001/11/30 23:03:09 1.59 +++ gdb.texinfo 2001/12/18 23:45:47 @@ -13323,6 +13323,17 @@ execute, one per line, terminated by an The commands are executed repeatedly as long as the expression evaluates to true. +@kindex try +@kindex except +@item try +Takes no arguments and must be followed by a series of commands to be +executed, one per line. Errors in the series of commands will terminate +execution of the series, but not the entire script. There can be and +optional @code{except} line, which must also be followed by a series of +commands, one per line. Commands in the @code{except} block are +executed if an error is encountered in the corresponding @code{try} +block. + @kindex document @item document @var{commandname} Document the user-defined command @var{commandname}, so that it can be -- dhoward@redhat.com gdb engineering