Mercurial > hg > octave-lyh
diff src/error.cc @ 5567:80e629357483
[project @ 2005-12-07 06:31:28 by jwe]
author | jwe |
---|---|
date | Wed, 07 Dec 2005 06:31:28 +0000 |
parents | a892ee7ac114 |
children | 6bf56668b01a |
line wrap: on
line diff
--- a/src/error.cc +++ b/src/error.cc @@ -37,6 +37,7 @@ #include "input.h" #include "pager.h" #include "oct-obj.h" +#include "oct-map.h" #include "utils.h" #include "ov.h" #include "ov-usr-fcn.h" @@ -59,19 +60,27 @@ // is encountered. static bool Vdebug_on_warning; +// TRUE means that Octave will try to display a stack trace when a +// warning is encountered. +static bool Vbacktrace_on_warning = false; + +// TRUE means that Octave will print a verbose warning. Currently unused. +static bool Vverbose_warning; + +// A structure containing (most of) the current state of warnings. +static Octave_map warning_options; + // The text of the last error message. static std::string Vlast_error_message; // The text of the last warning message. static std::string Vlast_warning_message; -// The warning frequency for Matlab handle graphics backwards -// compatibility warnings (currently not used). -static std::string Vwarning_frequency = "once"; +// The last warning message id. +static std::string Vlast_warning_id; -// The current warning state. Valid values are "on", "off", -// "backtrace", or "debug". -std::string Vwarning_option = "backtrace"; +// The last error message id. +static std::string Vlast_error_id; // Current error state. // @@ -116,10 +125,19 @@ discard_error_messages = false; } +static void +init_warning_options (const std::string& state = "on") +{ + warning_options.clear (); + + warning_options.assign ("identifier", "all"); + warning_options.assign ("state", state); +} + // Warning messages are never buffered. static void -vwarning (const char *name, const char *fmt, va_list args) +vwarning (const char *name, const char *id, const char *fmt, va_list args) { if (discard_warning_messages) return; @@ -146,6 +164,8 @@ if (! warning_state) { // This is the first warning in a possible series. + + Vlast_warning_id = id; Vlast_warning_message = msg_string; } @@ -156,7 +176,7 @@ static void verror (bool save_last_error, std::ostream& os, - const char *name, const char *fmt, va_list args) + const char *name, const char *id, const char *fmt, va_list args) { if (discard_error_messages) return; @@ -189,6 +209,8 @@ if (! error_state && save_last_error) { // This is the first error in a possible series. + + Vlast_error_id = id; Vlast_error_message = msg_string; } @@ -227,7 +249,8 @@ // just set the error state. static void -error_1 (std::ostream& os, const char *name, const char *fmt, va_list args) +error_1 (std::ostream& os, const char *name, const char *id, + const char *fmt, va_list args) { if (error_state != -2) { @@ -242,14 +265,14 @@ { char *tmp_fmt = strsave (fmt); tmp_fmt[len - 1] = '\0'; - verror (true, os, name, tmp_fmt, args); + verror (true, os, name, id, tmp_fmt, args); delete [] tmp_fmt; } error_state = -2; } else - verror (true, os, name, fmt, args); + verror (true, os, name, id, fmt, args); } } else @@ -265,17 +288,41 @@ { va_list args; va_start (args, fmt); - verror (false, std::cerr, name, fmt, args); + verror (false, std::cerr, name, "", fmt, args); va_end (args); } void +message_with_id (const char *name, const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + verror (false, std::cerr, name, id, fmt, args); + va_end (args); +} + +void +usage_1 (const char *id, const char *fmt, va_list args) +{ + verror (true, std::cerr, "usage", id, fmt, args); + error_state = -1; +} + +void usage (const char *fmt, ...) { va_list args; va_start (args, fmt); - verror (true, std::cerr, "usage", fmt, args); - error_state = -1; + usage_1 ("", fmt, args); + va_end (args); +} + +void +usage_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + usage_1 (id, fmt, args); va_end (args); } @@ -293,12 +340,12 @@ { char *tmp_fmt = strsave (fmt); tmp_fmt[len - 1] = '\0'; - verror (false, std::cerr, 0, tmp_fmt, args); + verror (false, std::cerr, 0, "", tmp_fmt, args); delete [] tmp_fmt; } } else - verror (false, std::cerr, 0, fmt, args); + verror (false, std::cerr, 0, "", fmt, args); } } else @@ -387,21 +434,113 @@ } } -void -warning (const char *fmt, ...) +static int +check_state (const std::string& state) +{ + // -1: not found + // 0: found, "off" + // 1: found, "on" + // 2: found, "error" + + if (state == "off") + return 0; + else if (state == "on") + return 1; + else if (state == "error") + return 2; + else + return -1; +} + +// For given warning ID, return 0 if warnings are disabled, 1 if +// enabled, and 2 if this ID should be an error instead of a warning. + +static int +warning_enabled (const std::string& id) { - if (Vwarning_option != "off") + int retval = 0; + + int all_state = -1; + int id_state = -1; + + octave_idx_type nel = warning_options.numel (); + + if (nel > 0) + { + Cell identifier = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + bool all_found = false; + bool id_found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value ov = identifier(i); + std::string ovs = ov.string_value (); + + if (! all_found && ovs == "all") + { + all_state = check_state (state(i).string_value ()); + + if (all_state >= 0) + all_found = true; + } + + if (! id_found && ovs == id) + { + id_state = check_state (state(i).string_value ()); + + if (id_state >= 0) + id_found = true; + } + + if (all_found && id_found) + break; + } + + } + + if (all_state == -1) + panic_impossible (); + + if (all_state == 0) + { + if (id_state >= 0) + retval = id_state; + } + else if (all_state == 1) + { + if (id_state == 0 || id_state == 2) + retval = id_state; + else + retval = all_state; + } + else if (all_state == 2) + retval = 2; + + return retval; +} + +static void +warning_1 (const char *id, const char *fmt, va_list args) +{ + int warn_opt = warning_enabled (id); + + if (warn_opt == 2) + { + // Handle this warning as an error. + + error (id, fmt, args); + } + else if (warn_opt == 1) { if (curr_sym_tab != top_level_sym_tab - && Vwarning_option == "backtrace" + && Vbacktrace_on_warning && ! warning_state && ! discard_warning_messages) pr_where ("warning", false); - va_list args; - va_start (args, fmt); - vwarning ("warning", fmt, args); - va_end (args); + vwarning ("warning", id, fmt, args); warning_state = 1; @@ -419,14 +558,29 @@ } void -error (const char *fmt, ...) +warning (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + warning_1 ("", fmt, args); + va_end (args); +} + +void +warning_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + warning_1 (id, fmt, args); + va_end (args); +} + +static void +error_2 (const char *id, const char *fmt, va_list args) { int init_state = error_state; - va_list args; - va_start (args, fmt); - error_1 (std::cerr, "error", fmt, args); - va_end (args); + error_1 (std::cerr, "error", id, fmt, args); if ((interactive || forced_interactive) && Vdebug_on_error && init_state == 0 && curr_function) @@ -445,11 +599,38 @@ } void +error (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_2 ("", fmt, args); + va_end (args); +} + +void +error_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_2 (id, fmt, args); + va_end (args); +} + +void parse_error (const char *fmt, ...) { va_list args; va_start (args, fmt); - error_1 (std::cerr, 0, fmt, args); + error_1 (std::cerr, 0, "", fmt, args); + va_end (args); +} + +void +parse_error_with_id (const char *id, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + error_1 (std::cerr, 0, id, fmt, args); va_end (args); } @@ -460,7 +641,7 @@ va_start (args, fmt); buffer_error_messages = 0; discard_error_messages = false; - verror (false, std::cerr, "panic", fmt, args); + verror (false, std::cerr, "panic", "", fmt, args); va_end (args); abort (); } @@ -470,7 +651,7 @@ { va_list args; va_start (args, fmt); - error_1 (octave_stdout, 0, fmt, args); + error_1 (octave_stdout, 0, "", fmt, args); va_end (args); } @@ -480,12 +661,13 @@ defun_usage_message_1 ("%s", msg.c_str ()); } -typedef void (*error_fun)(const char *, ...); +typedef void (*error_fun)(const char *, const char *, ...); extern octave_value_list Fsprintf (const octave_value_list&, int); static std::string -handle_message (error_fun f, const char *msg, const octave_value_list& args) +handle_message (error_fun f, const char *id, const char *msg, + const octave_value_list& args) { std::string retval; @@ -529,14 +711,14 @@ { char *tmp_msg = strsave (msg); tmp_msg[len - 1] = '\0'; - f ("%s\n", tmp_msg); + f (id, "%s\n", tmp_msg); retval = tmp_msg; delete [] tmp_msg; } } else { - f ("%s", msg); + f (id, "%s", msg); retval = msg; } @@ -599,33 +781,15 @@ @end example\n\ @end deftypefn") { + // XXX FIXME XXX -- need to extract and pass message id to + // handle_message. + octave_value_list retval; - handle_message (error, "unspecified error", args); + handle_message (error_with_id, "", "unspecified error", args); return retval; } -static inline octave_value_list -set_warning_option (const std::string& state, - const std::string& frequency, int nargout) -{ - octave_value_list retval; - - if (nargout > 1) - retval(1) = Vwarning_frequency; - - if (nargout >= 0) - retval(0) = Vwarning_option; - - if (! state.empty ()) - Vwarning_option = state; - - if (! frequency.empty ()) - Vwarning_frequency = frequency; - - return retval; -} - -DEFUN (warning, args, nargout, +DEFCMD (warning, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} warning (@var{msg})\n\ Print a warning message @var{msg} prefixed by the string @samp{warning: }. \n\ @@ -635,84 +799,279 @@ to go on.\n\ @end deftypefn") { - octave_value_list retval; + octave_value retval; - int argc = args.length () + 1; + int nargin = args.length (); + int argc = nargin + 1; bool done = false; - if (args.all_strings_p ()) + if (argc > 1 && args.all_strings_p ()) { string_vector argv = args.make_argv ("warning"); if (! error_state) { - if (argc == 1) + std::string arg1 = argv(1); + std::string arg2 = "all"; + + if (argc == 3) + arg2 = argv(2); + + if (arg1 == "on" || arg1 == "off" || arg1 == "error") { - retval = set_warning_option ("", "", nargout); - done = true; - } - else if (argc == 2) - { - std::string arg = argv(1); + Octave_map old_warning_options = warning_options; + + if (arg2 == "all") + { + Octave_map tmp; - if (arg == "on" || arg == "off" || arg == "backtrace") - { - retval = set_warning_option (arg, "", nargout); + tmp.assign ("identifier", arg2); + tmp.assign ("state", arg1); + + warning_options = tmp; + done = true; } - else if (arg == "once" || arg == "always") + else if (arg2 == "backtrace") + { + if (arg1 != "error") + { + Vbacktrace_on_warning = (arg1 == "on"); + done = true; + } + } + else if (arg2 == "debug") + { + if (arg1 != "error") + { + bind_builtin_variable ("debug_on_warning", arg1 == "on"); + done = true; + } + } + else if (arg2 == "verbose") + { + if (arg1 != "error") + { + Vverbose_warning = (arg1 == "on"); + done = true; + } + } + else { - retval = set_warning_option ("", arg, nargout); + if (arg2 == "last") + arg2 = Vlast_warning_id; + + if (arg2 == "all") + init_warning_options (arg1); + else + { + Cell ident = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (ident(i).string_value () == arg2) + { + // XXX FIXME XXX -- if state for "all" is + // same as arg1, we can simply remove the + // item from the list. + + state(i) = arg1; + warning_options.assign ("state", state); + found = true; + break; + } + } + + if (! found) + { + // XXX FIXME XXX -- if state for "all" is + // same as arg1, we don't need to do anything. + + ident.resize (dim_vector (1, nel+1)); + state.resize (dim_vector (1, nel+1)); + + ident(nel) = arg2; + state(nel) = arg1; + + warning_options.clear (); + + warning_options.assign ("identifier", ident); + warning_options.assign ("state", state); + } + } + done = true; } - else if (arg == "debug") + + if (done && nargout > 0) + retval = warning_options; + } + else if (arg1 == "query") + { + if (arg2 == "all") + retval = warning_options; + else if (arg2 == "backtrace" || arg2 == "debug" + || arg2 == "verbose") + { + Octave_map tmp; + tmp.assign ("identifier", arg2); + if (arg2 == "backtrace") + tmp.assign ("state", Vbacktrace_on_warning ? "on" : "off"); + else if (arg2 == "debug") + tmp.assign ("state", Vdebug_on_warning ? "on" : "off"); + else + tmp.assign ("state", Vverbose_warning ? "on" : "off"); + } + else { - bind_builtin_variable ("debug_on_warning", true); - retval = set_warning_option ("", "", nargout); - done = true; + if (arg2 == "last") + arg2 = Vlast_warning_id; + + Cell ident = warning_options.contents ("identifier"); + Cell state = warning_options.contents ("state"); + + octave_idx_type nel = ident.numel (); + + bool found = false; + + std::string val; + + for (octave_idx_type i = 0; i < nel; i++) + { + if (ident(i).string_value () == arg2) + { + val = state(i).string_value (); + found = true; + break; + } + } + + if (found) + { + Octave_map tmp; + + tmp.assign ("identifier", arg2); + tmp.assign ("state", val); + + retval = tmp; + } + else + error ("warning: invalid warning tag `%s'", arg2.c_str ()); } + + done = true; } } } + else if (argc == 1) + { + retval = warning_options; - if (! done) + done = true; + } + else if (argc == 2) + { + octave_value arg = args(0); + + Octave_map old_warning_options = warning_options; + + if (arg.is_map ()) + { + Octave_map m = arg.map_value (); + + if (m.contains ("identifier") && m.contains ("state")) + warning ("warning: setting state with structure not implemented"); + else + error ("warning: expecting structure with fields `identifier' and `state'"); + + done = true; + + if (nargout > 0) + retval = old_warning_options; + } + } + + if (! (error_state || done)) { + octave_value_list nargs = args; + + std::string id; + + if (nargin > 1) + { + std::string arg1 = args(0).string_value (); + + if (! error_state) + { + if (arg1.find ('%') == NPOS) + { + id = arg1; + + nargs.resize (nargin-1); + + for (int i = 1; i < nargin; i++) + nargs(i-1) = args(i); + } + } + else + return retval; + } + + // handle_message. + std::string prev_msg = Vlast_warning_message; - std::string curr_msg - = handle_message (warning, "unspecified warning", args); + std::string curr_msg = handle_message (warning_with_id, id.c_str (), + "unspecified warning", nargs); if (nargout > 0) - retval(0) = Vlast_warning_message; + retval = prev_msg; } return retval; } -DEFUN (lasterr, args, , +DEFUN (lasterr, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} lasterr ()\n\ -@deftypefnx {Built-in Function} {} lasterr (@var{msg})\n\ +@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lasterr (@var{msg}, @var{msgid})\n\ Without any arguments, return the last error message. With one\n\ -argument, set the last error message to @var{msg}.\n\ +argument, set the last error message to @var{msg}. With two arguments,\n\ +also set the last message identifier.\n\ @end deftypefn") { octave_value_list retval; int argc = args.length () + 1; - if (argc == 1 || argc == 2) + if (argc < 4) { string_vector argv = args.make_argv ("lasterr"); if (! error_state) { - if (argc == 1) - retval(0) = Vlast_error_message; - else + std::string prev_error_id = Vlast_error_id; + std::string prev_error_message = Vlast_error_message; + + if (argc > 2) + Vlast_error_id = argv(2); + + if (argc > 1) Vlast_error_message = argv(1); + + if (argc == 1 || nargout > 0) + { + retval(1) = prev_error_id; + retval(0) = prev_error_message; + } } + else + error ("lastwarn: expecting arguments to be character strings"); } else print_usage ("lasterr"); @@ -724,24 +1083,42 @@ DEFALIAS (error_text, lasterr); DEFALIAS (__error_text__, lasterr); -DEFUN (lastwarn, args, , +DEFUN (lastwarn, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} lastwarn ()\n\ -@deftypefnx {Built-in Function} {} lastwarn (@var{msg})\n\ +@deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lastwarn (@var{msg}, @var{msgid})\n\ Without any arguments, return the last warning message. With one\n\ -argument, set the last warning message to @var{msg}.\n\ +argument, set the last warning message to @var{msg}. With two arguments,\n\ +also set the last message identifier.\n\ @end deftypefn") { octave_value_list retval; int argc = args.length () + 1; - string_vector argv = args.make_argv ("lastwarn"); + if (argc < 4) + { + string_vector argv = args.make_argv ("lastwarn"); + + if (! error_state) + { + std::string prev_warning_id = Vlast_warning_id; + std::string prev_warning_message = Vlast_warning_message; + + if (argc > 2) + Vlast_warning_id = argv(2); - if (argc == 1) - retval(0) = Vlast_warning_message; - else if (argc == 2) - Vlast_warning_message = argv(1); + if (argc > 1) + Vlast_warning_message = argv(1); + + if (argc == 1 || nargout > 0) + { + retval(1) = prev_warning_id; + retval(0) = prev_warning_message; + } + } + else + error ("lastwarn: expecting arguments to be character strings"); + } else print_usage ("lastwarn"); @@ -778,7 +1155,7 @@ @end deftypefn") { octave_value_list retval; - handle_message (usage, "unknown", args); + handle_message (usage_with_id, "", "unknown", args); return retval; } @@ -809,6 +1186,8 @@ void symbols_of_error (void) { + init_warning_options (); + DEFVAR (beep_on_error, false, beep_on_error, "-*- texinfo -*-\n\ @defvr {Built-in Variable} beep_on_error\n\