# HG changeset patch # User jwe # Date 812266706 0 # Node ID 3e705c864019b00e1c74f88a1e0b0a8b77849aaa # Parent 89c5874780671e738fc9f065521a5b384262583b [project @ 1995-09-28 05:38:26 by jwe] diff -r 89c587478067 -r 3e705c864019 src/dirfns.cc --- a/src/dirfns.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/dirfns.cc Thu Sep 28 05:38:26 1995 +0000 @@ -507,7 +507,11 @@ } else { - DIR *dir = opendir (dirname); + char *tmp = tilde_expand (dirname); + + DIR *dir = opendir (tmp); + + free (tmp); if (dir) { @@ -579,10 +583,19 @@ if (error_state) gripe_wrong_type_arg ("mkdir", args(0)); - else if (mkdir (dirname, 0777) < 0) + else { - status = -1; - error ("%s", strerror (errno)); + char *tmp = tilde_expand (dirname); + + int mkdir_retval = mkdir (tmp, 0777); + + free (tmp); + + if (mkdir_retval < 0) + { + status = -1; + error ("%s", strerror (errno)); + } } } else @@ -610,10 +623,19 @@ if (error_state) gripe_wrong_type_arg ("rmdir", args(0)); - else if (rmdir (dirname) < 0) + else { - status = -1; - error ("%s", strerror (errno)); + char *tmp = tilde_expand (dirname); + + int rmdir_retval = rmdir (tmp); + + free (tmp); + + if (rmdir_retval < 0) + { + status = -1; + error ("%s", strerror (errno)); + } } } else diff -r 89c587478067 -r 3e705c864019 src/error.cc --- a/src/error.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/error.cc Thu Sep 28 05:38:26 1995 +0000 @@ -40,8 +40,13 @@ // Current error state. int error_state = 0; -// XXX FIXME XXX -int suppress_octave_error_messages = 0; +// Tell the error handler whether to print messages, or just store +// them for later. Used for handling errors in eval() and +// the `unwind_protect' statement. +int buffer_error_messages; + +// The message buffer +ostrstream *error_message_buffer = 0; static void verror (const char *name, const char *fmt, va_list args) @@ -50,13 +55,6 @@ int to_beep_or_not_to_beep = user_pref.beep_on_error && ! error_state; - if (to_beep_or_not_to_beep) - cerr << "\a"; - if (name) - cerr << name << ": "; - cerr.vform (fmt, args); - cerr << endl; - ostrstream output_buf; if (to_beep_or_not_to_beep) @@ -68,7 +66,32 @@ char *msg = output_buf.str (); - maybe_write_to_diary_file (msg); + if (buffer_error_messages) + { + char *ptr = msg; + + if (! error_message_buffer) + { + error_message_buffer = new ostrstream; + + // XXX FIXME XXX -- this is ugly, but it prevents + // + // eval ("error (\"msg\")", "error (__error_text__)"); + // + // from printing `error: ' twice. Assumes that the NAME we + // have been given doesn't contain `:'. + + ptr = strchr (msg, ':') + 2; + ptr = ptr ? ptr : msg; + } + + *error_message_buffer << ptr; + } + else + { + maybe_write_to_diary_file (msg); + cerr << msg; + } delete [] msg; } @@ -82,32 +105,29 @@ { if (error_state != -2) { - if (! suppress_octave_error_messages) + if (fmt) { - if (fmt) + if (*fmt) { - if (*fmt) + int len = strlen (fmt); + if (fmt[len - 1] == '\n') { - int len = strlen (fmt); - if (fmt[len - 1] == '\n') + if (len > 1) { - if (len > 1) - { - char *tmp_fmt = strsave (fmt); - tmp_fmt[len - 1] = '\0'; - verror (name, tmp_fmt, args); - delete [] tmp_fmt; - } + char *tmp_fmt = strsave (fmt); + tmp_fmt[len - 1] = '\0'; + verror (name, tmp_fmt, args); + delete [] tmp_fmt; + } - error_state = -2; - } - else - verror (name, fmt, args); + error_state = -2; } + else + verror (name, fmt, args); } - else - panic ("error_1: invalid format"); } + else + panic ("error_1: invalid format"); if (! error_state) error_state = 1; @@ -172,94 +192,79 @@ abort (); } -DEFUN ("error", Ferror, Serror, 10, - "error (MESSAGE): print MESSAGE and set the error state.\n\ -This should eventually take us up to the top level, possibly\n\ -printing traceback messages as we go.\n\ -\n\ -If MESSAGE ends in a newline character, traceback messages are not\n\ -printed.") +typedef void (*error_fun)(const char *, ...); + +extern Octave_object Fsprintf (const Octave_object&, int); + +static Octave_object +handle_message (error_fun f, const char *msg, const Octave_object& args) { Octave_object retval; - const char *msg = "unspecified error"; - int nargin = args.length (); - if (nargin == 1 && args(0).is_defined ()) + tree_constant arg = ((nargin > 1) ? Fsprintf (args, 1) : args) (0); + + if (arg.is_defined ()) { - if (args(0).is_string ()) + if (arg.is_string ()) { - msg = args(0).string_value (); + msg = arg.string_value (); if (! msg) return retval; } - else if (args(0).is_empty ()) + else if (arg.is_empty ()) return retval; } - error (msg); +// Ugh. + + int len = strlen (msg); + if (msg[len - 1] == '\n') + { + if (len > 1) + { + char *tmp_msg = strsave (msg); + tmp_msg[len - 1] = '\0'; + f ("%s\n", tmp_msg); + delete [] tmp_msg; + } + } + else + f ("%s", msg); return retval; } -DEFUN ("warning", Fwarning, Swarning, 10, - "warning (MESSAGE): print a warning MESSAGE.\n\ +DEFUN ("error", Ferror, Serror, 10, + "error (FMT, ...): print message according to FMT and set error state.\n\ \n\ -See also: error") +This should eventually take us up to the top level, possibly\n\ +printing traceback messages as we go.\n\ +\n\ +If MESSAGE ends in a newline character, traceback messages are not\n\ +printed.\n\ +\n\ +See also: printf") { - Octave_object retval; - - const char *msg = "unspecified warning"; - - int nargin = args.length (); + return handle_message (error, "unspecified error", args); +} - if (nargin == 1 && args(0).is_defined ()) - { - if (args(0).is_string ()) - { - msg = args(0).string_value (); - - if (! msg || ! *msg) - return retval; - } - else if (args(0).is_empty ()) - return retval; - } - - warning (msg); - - return retval; +DEFUN ("warning", Fwarning, Swarning, 10, + "warning (FMT, ...): print a warning message according to FMT.\n\ +\n\ +See also: error, printf") +{ + return handle_message (warning, "unspecified warning", args); } DEFUN ("usage", Fusage, Susage, 10, - "usage (MESSAGE): print a usage MESSAGE.\n\ + "usage (FMT, ...): print a usage message according to FMT.\n\ \n\ -See also: error") +See also: error, printf") { - Octave_object retval; - - const char *msg = "unknown"; - - int nargin = args.length (); - - if (nargin == 1 && args(0).is_defined ()) - { - if (args(0).is_string ()) - { - msg = args(0).string_value (); - - if (! msg || ! *msg) - return retval; - } - else if (args(0).is_empty ()) - return retval; - } - - usage (msg); - - return retval; + return handle_message (usage, "unknown", args); } /* diff -r 89c587478067 -r 3e705c864019 src/error.h --- a/src/error.h Tue Sep 26 22:49:48 1995 +0000 +++ b/src/error.h Thu Sep 28 05:38:26 1995 +0000 @@ -24,6 +24,8 @@ #if !defined (octave_error_h) #define octave_error_h 1 +class ostrstream; + #define panic_impossible() \ panic ("impossible state reached in file `%s' at line %d", \ __FILE__, __LINE__) @@ -38,8 +40,13 @@ // Current error state. extern int error_state; -// XXX FIXME XXX -extern int suppress_octave_error_messages; +// Tell the error handler whether to print messages, or just store +// them for later. Used for handling errors in eval() and +// the `unwind_protect' statement. +extern int buffer_error_messages; + +// The message buffer +extern ostrstream *error_message_buffer; #endif diff -r 89c587478067 -r 3e705c864019 src/help.cc --- a/src/help.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/help.cc Thu Sep 28 05:38:26 1995 +0000 @@ -195,6 +195,9 @@ { "break", "Exit the innermost enclosing while or for loop.", }, + { "catch", + "begin the cleanup part of a try-catch block", }, + { "continue", "Jump to the end of the innermost enclosing while or for loop.", }, @@ -207,6 +210,9 @@ { "end", "Mark the end of any for, if, while, or function block.", }, + { "end_try_catch", + "Mark the end of an try-catch block.", }, + { "end_unwind_protect", "Mark the end of an unwind_protect block.", }, @@ -243,6 +249,9 @@ { "return", "Return from a function.", }, + { "try", + "Begin a try-catch block.", }, + { "unwind_protect", "Begin an unwind_protect block.", }, diff -r 89c587478067 -r 3e705c864019 src/lex.l --- a/src/lex.l Tue Sep 26 22:49:48 1995 +0000 +++ b/src/lex.l Thu Sep 28 05:38:26 1995 +0000 @@ -1092,6 +1092,25 @@ yylval.tok_val = new token (token::unwind_protect_end, l, c); token_stack.push (yylval.tok_val); } + else if (strcmp ("try", s) == 0) + { + promptflag--; + yylval.tok_val = new token (l, c); + token_stack.push (yylval.tok_val); + return TRY; + } + else if (strcmp ("catch", s) == 0) + { + yylval.tok_val = new token (l, c); + token_stack.push (yylval.tok_val); + return CATCH; + } + else if (strcmp ("end_try_catch", s) == 0) + { + end_found = 1; + yylval.tok_val = new token (token::try_catch_end, l, c); + token_stack.push (yylval.tok_val); + } else if (strcmp ("all_va_args", s) == 0) { yylval.tok_val = new token (l, c); diff -r 89c587478067 -r 3e705c864019 src/octave.cc --- a/src/octave.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/octave.cc Thu Sep 28 05:38:26 1995 +0000 @@ -979,8 +979,8 @@ if (nargin > 1) { - unwind_protect_int (suppress_octave_error_messages); - suppress_octave_error_messages = 1; + unwind_protect_int (buffer_error_messages); + buffer_error_messages = 1; } int parse_status = 0; @@ -990,7 +990,16 @@ if (nargin > 1 && (parse_status != 0 || error_state)) { error_state = 0; + + // Set up for letting the user print any messages from + // errors that occurred in the first part of this eval(). + + buffer_error_messages = 0; + bind_global_error_variable (); + add_unwind_protect (clear_global_error_variable, 0); + eval_string (args(1), parse_status, nargout); + retval = Octave_object (); } diff -r 89c587478067 -r 3e705c864019 src/parse.y --- a/src/parse.y Tue Sep 26 22:49:48 1995 +0000 +++ b/src/parse.y Thu Sep 28 05:38:26 1995 +0000 @@ -223,6 +223,7 @@ %token TEXT STYLE %token FOR WHILE IF ELSEIF ELSE BREAK CONTINUE FUNC_RET %token UNWIND CLEANUP +%token TRY CATCH %token GLOBAL %token TEXT_ID @@ -612,6 +613,14 @@ $$ = new tree_unwind_protect_command ($3, $6, $1->line (), $1->column ()); } + | TRY optsep opt_list CATCH optsep opt_list END + { + if (check_end ($7, token::try_catch_end)) + ABORT_PARSE; + + $$ = new tree_try_catch_command ($3, $6, $1->line (), + $1->column ()); + } | WHILE expression optsep opt_list END { maybe_warn_assign_as_truth_value ($2); @@ -1318,6 +1327,14 @@ end_error ("if", ettype, l, c); break; + case token::try_catch_end: + end_error ("try", ettype, l, c); + break; + + case token::unwind_protect_end: + end_error ("unwind_protect", ettype, l, c); + break; + case token::while_end: end_error ("while", ettype, l, c); break; diff -r 89c587478067 -r 3e705c864019 src/pt-cmd.cc --- a/src/pt-cmd.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/pt-cmd.cc Thu Sep 28 05:38:26 1995 +0000 @@ -638,6 +638,123 @@ // Simple exception handling. +tree_try_catch_command::~tree_try_catch_command (void) +{ + delete try_code; + delete catch_code; +} + +static void +do_catch_code (void *ptr) +{ + tree_statement_list *list = (tree_statement_list *) ptr; + + // Set up for letting the user print any messages from errors that + // occurred in the body of the try_catch statement. + + buffer_error_messages = 0; + bind_global_error_variable (); + add_unwind_protect (clear_global_error_variable, 0); + + // Similarly, if we have seen a return or break statement, allow all + // the catch code to run before returning or handling the break. + // We don't have to worry about continue statements because they can + // only occur in loops. + + unwind_protect_int (returning); + returning = 0; + + unwind_protect_int (breaking); + breaking = 0; + + if (list) + list->eval (1); + + // This is the one for breaking. (The unwind_protects are popped + // off the stack in the reverse of the order they are pushed on). + + // XXX FIXME XXX -- inside a try-catch, should break work like + // a return, or just jump to the end of the try_catch block? + // The following code makes it just jump to the end of the block. + + run_unwind_protect (); + if (breaking) + breaking--; + + // This is the one for returning. + + if (returning) + discard_unwind_protect (); + else + run_unwind_protect (); + + run_unwind_protect (); +} + +void +tree_try_catch_command::eval (void) +{ + begin_unwind_frame ("tree_try_catch::eval"); + + add_unwind_protect (do_catch_code, catch_code); + + if (catch_code) + { + unwind_protect_int (buffer_error_messages); + buffer_error_messages = 1; + } + + if (try_code) + try_code->eval (1); + + if (catch_code && error_state) + { + error_state = 0; + run_unwind_frame ("tree_try_catch::eval"); + } + else + { + error_state = 0; + discard_unwind_frame ("tree_try_catch::eval"); + } +} + +void +tree_try_catch_command::print_code (ostream& os) +{ + print_code_indent (os); + + os << "try_catch"; + + print_code_new_line (os); + + if (try_code) + { + increment_indent_level (); + try_code->print_code (os); + decrement_indent_level (); + } + + print_code_indent (os); + + os << "catch_code"; + + print_code_new_line (os); + + if (catch_code) + { + increment_indent_level (); + catch_code->print_code (os); + decrement_indent_level (); + } + + print_code_indent (os); + + os << "end_try_catch"; +} + +// Simple exception handling. + tree_unwind_protect_command::~tree_unwind_protect_command (void) { delete unwind_protect_code; @@ -702,23 +819,12 @@ void tree_unwind_protect_command::eval (void) { - begin_unwind_frame ("tree_unwind_protect::eval"); - add_unwind_protect (do_unwind_protect_cleanup_code, cleanup_code); - if (cleanup_code) - { - unwind_protect_int (suppress_octave_error_messages); - suppress_octave_error_messages = 1; - } - if (unwind_protect_code) unwind_protect_code->eval (1); - if (cleanup_code && error_state) - error_state = 0; - - run_unwind_frame ("tree_unwind_protect::eval"); + run_unwind_protect (); } void diff -r 89c587478067 -r 3e705c864019 src/pt-cmd.h --- a/src/pt-cmd.h Tue Sep 26 22:49:48 1995 +0000 +++ b/src/pt-cmd.h Thu Sep 28 05:38:26 1995 +0000 @@ -47,6 +47,7 @@ class tree_while_command; class tree_for_command; class tree_if_command; +class tree_try_catch_command; class tree_unwind_protect_command; class tree_break_command; class tree_continue_command; @@ -243,6 +244,38 @@ tree_statement_list *cleanup_code; }; +// Simple exception handling. + +class +tree_try_catch_command : public tree_command +{ +public: + tree_try_catch_command (int l = -1, int c = -1) : tree_command (l, c) + { + try_code = 0; + catch_code = 0; + } + + tree_try_catch_command (tree_statement_list *tc, + tree_statement_list *cc, + int l = -1, int c = -1) + : tree_command (l, c) + { + try_code = tc; + catch_code = cc; + } + + ~tree_try_catch_command (void); + + void eval (void); + + void print_code (ostream& os); + +private: + tree_statement_list *try_code; + tree_statement_list *catch_code; +}; + // Break. class diff -r 89c587478067 -r 3e705c864019 src/token.h --- a/src/token.h Tue Sep 26 22:49:48 1995 +0000 +++ b/src/token.h Thu Sep 28 05:38:26 1995 +0000 @@ -51,6 +51,7 @@ function_end, if_end, while_end, + try_catch_end, unwind_protect_end, }; diff -r 89c587478067 -r 3e705c864019 src/variables.cc --- a/src/variables.cc Tue Sep 26 22:49:48 1995 +0000 +++ b/src/variables.cc Thu Sep 28 05:38:26 1995 +0000 @@ -1479,6 +1479,31 @@ tmp_ass.eval (print); } +void +bind_global_error_variable (void) +{ + *error_message_buffer << ends; + + char *error_text = error_message_buffer->str (); + + bind_builtin_variable ("__error_text__", error_text, 1); + + delete [] error_text; + + delete error_message_buffer; + + error_message_buffer = 0; +} + +void +clear_global_error_variable (void *) +{ + delete error_message_buffer; + error_message_buffer = 0; + + bind_builtin_variable ("__error_text__", "", 1); +} + // Give a global variable a definition. This will insert the symbol // in the global table if necessary. @@ -1605,6 +1630,13 @@ "the string to append after successful command-line completion\n\ attempts"); + DEFCONST ("error_text", SBV_current_error_text, "", 0, 0, + "the text of error messages that would have been printed in the +body of the most recent unwind_protect statement or the TRY part of\n\ +the most recent eval() command. Outside of unwind_protect and\n\ +eval(), or if no error has ocurred within them, the value of\n\ +__error_text__ is guaranteed to be the empty string."); + DEFVAR ("default_return_value", SBV_default_return_value, Matrix (), 0, 0, "the default for value for unitialized variables returned from\n\ diff -r 89c587478067 -r 3e705c864019 src/variables.h --- a/src/variables.h Tue Sep 26 22:49:48 1995 +0000 +++ b/src/variables.h Thu Sep 28 05:38:26 1995 +0000 @@ -108,6 +108,10 @@ extern void bind_ans (const tree_constant& val, int print); +extern void bind_global_error_variable (void); + +extern void clear_global_error_variable (void *); + extern void bind_builtin_variable (const char *, tree_constant *, int protect = 0, int eternal = 0, sv_Function f = (sv_Function) 0,