From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1177 invoked by alias); 21 Jan 2002 20:28:03 -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 1126 invoked from network); 21 Jan 2002 20:27:58 -0000 Received: from unknown (HELO cygnus.com) (205.180.230.5) by sources.redhat.com with SMTP; 21 Jan 2002 20:27:58 -0000 Received: from redhat.com (totem.toronto.redhat.com [172.16.14.242]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id MAA28987; Mon, 21 Jan 2002 12:27:54 -0800 (PST) Message-ID: <3C4C79C8.204C2083@redhat.com> Date: Mon, 21 Jan 2002 12:28:00 -0000 From: Fernando Nasser Organization: Red Hat , Inc. - Toronto X-Mailer: Mozilla 4.78 [en] (X11; U; Linux 2.4.7-10smp i686) X-Accept-Language: en MIME-Version: 1.0 To: Don Howard CC: gdb-patches@sources.redhat.com Subject: Re: [RFA] error-catching mechanism for scripts References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-01/txt/msg00662.txt.bz2 Don, This is a cool command. Have you ever had the time to address Andrew's and Eli's suggestions (and a couple of tests)? Best regards, Fernando Don Howard wrote: > > 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 -- Fernando Nasser Red Hat - Toronto E-Mail: fnasser@redhat.com 2323 Yonge Street, Suite #300 Toronto, Ontario M4P 2C9