Mercurial > hg > octave-nkf
changeset 1489:3e705c864019
[project @ 1995-09-28 05:38:26 by jwe]
author | jwe |
---|---|
date | Thu, 28 Sep 1995 05:38:26 +0000 |
parents | 89c587478067 |
children | 4d6c168ff235 |
files | src/dirfns.cc src/error.cc src/error.h src/help.cc src/lex.l src/octave.cc src/parse.y src/pt-cmd.cc src/pt-cmd.h src/token.h src/variables.cc src/variables.h |
diffstat | 12 files changed, 377 insertions(+), 113 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dirfns.cc +++ b/src/dirfns.cc @@ -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
--- a/src/error.cc +++ b/src/error.cc @@ -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); } /*
--- a/src/error.h +++ b/src/error.h @@ -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
--- a/src/help.cc +++ b/src/help.cc @@ -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.", },
--- a/src/lex.l +++ b/src/lex.l @@ -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);
--- a/src/octave.cc +++ b/src/octave.cc @@ -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 (); }
--- a/src/parse.y +++ b/src/parse.y @@ -223,6 +223,7 @@ %token <tok_val> TEXT STYLE %token <tok_val> FOR WHILE IF ELSEIF ELSE BREAK CONTINUE FUNC_RET %token <tok_val> UNWIND CLEANUP +%token <tok_val> TRY CATCH %token <tok_val> GLOBAL %token <tok_val> 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;
--- a/src/pt-cmd.cc +++ b/src/pt-cmd.cc @@ -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
--- a/src/pt-cmd.h +++ b/src/pt-cmd.h @@ -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
--- a/src/token.h +++ b/src/token.h @@ -51,6 +51,7 @@ function_end, if_end, while_end, + try_catch_end, unwind_protect_end, };
--- a/src/variables.cc +++ b/src/variables.cc @@ -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\
--- a/src/variables.h +++ b/src/variables.h @@ -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,