* [RFA] error-catching mechanism for scripts [not found] <Pine.LNX.4.33.0111270827180.2426-100000@theotherone.redhat-remotie.org> @ 2001-12-18 15:48 ` Don Howard 2001-12-19 2:36 ` Andrew Cagney ` (2 more replies) 0 siblings, 3 replies; 4+ messages in thread From: Don Howard @ 2001-12-18 15:48 UTC (permalink / raw) To: gdb-patches 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 <dhoward@redhat.com> * 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 <dhoward@redhat.com> * 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 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFA] error-catching mechanism for scripts 2001-12-18 15:48 ` [RFA] error-catching mechanism for scripts Don Howard @ 2001-12-19 2:36 ` Andrew Cagney 2001-12-19 10:10 ` Eli Zaretskii 2002-01-21 12:28 ` Fernando Nasser 2 siblings, 0 replies; 4+ messages in thread From: Andrew Cagney @ 2001-12-19 2:36 UTC (permalink / raw) To: Don Howard; +Cc: gdb-patches > try > some commands that might error > except > some commands to recover from error > (errors in this block will not be caught) > end Just a question. Given: try try some commands that might error except some commands to recover from error (erros in this block will not be caught) end end I assume the outer try catches errors from the inner except. Looking at the code, I think this is what happens and, I think, is correct. What about CNTRL-C? Does that abort the commands or does except catch it? Hmm (thinking out loud). What about internal-error, er, that throws an ``error'' which the user can now catch. I guess for the moment this is a feature :-) BTW, catch_errors() is discouraged in favour of catch_exceptions(). PTR -> void *. I see the tests are comming. Ya! Can I suggest expanding the doco to include an example. Even if it is just the example you posted with ``some commands that might error'' etc. I can't think of something that is guarenteed to cause a error - ah, a `maint error'' command :-/ Andrew ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFA] error-catching mechanism for scripts 2001-12-18 15:48 ` [RFA] error-catching mechanism for scripts Don Howard 2001-12-19 2:36 ` Andrew Cagney @ 2001-12-19 10:10 ` Eli Zaretskii 2002-01-21 12:28 ` Fernando Nasser 2 siblings, 0 replies; 4+ messages in thread From: Eli Zaretskii @ 2001-12-19 10:10 UTC (permalink / raw) To: dhoward; +Cc: gdb-patches > Date: Tue, 18 Dec 2001 15:48:18 -0800 (PST) > From: Don Howard <dhoward@redhat.com> > > I've included a quick write-up for the gdb manual. Thanks. The manual changes are approved, with the following gotchas: > +@kindex try > +@kindex except > +@item try Please add "@itemx except" after "@item try", so that the reader would see the command listed. > +execution of the series, but not the entire script. There can be and The last words should be "an", not "and", I think. > +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. Please consider adding a simple example. I think some users will have a difficulty grasping this without an example. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFA] error-catching mechanism for scripts 2001-12-18 15:48 ` [RFA] error-catching mechanism for scripts Don Howard 2001-12-19 2:36 ` Andrew Cagney 2001-12-19 10:10 ` Eli Zaretskii @ 2002-01-21 12:28 ` Fernando Nasser 2 siblings, 0 replies; 4+ messages in thread From: Fernando Nasser @ 2002-01-21 12:28 UTC (permalink / raw) To: Don Howard; +Cc: gdb-patches 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 <dhoward@redhat.com> > > * 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 <dhoward@redhat.com> > > * 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 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2002-01-21 20:28 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <Pine.LNX.4.33.0111270827180.2426-100000@theotherone.redhat-remotie.org>
2001-12-18 15:48 ` [RFA] error-catching mechanism for scripts Don Howard
2001-12-19 2:36 ` Andrew Cagney
2001-12-19 10:10 ` Eli Zaretskii
2002-01-21 12:28 ` Fernando Nasser
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox