diff src/error.cc @ 6361:776e657c9422

[project @ 2007-02-27 09:45:03 by dbateman]
author dbateman
date Tue, 27 Feb 2007 09:45:03 +0000
parents ec88b4ab6d10
children 38df68789f30
line wrap: on
line diff
--- a/src/error.cc	Mon Feb 26 21:08:50 2007 +0000
+++ b/src/error.cc	Tue Feb 27 09:45:03 2007 +0000
@@ -85,6 +85,18 @@
 // The last error message id.
 static std::string Vlast_error_id;
 
+// The last file in which an error occured
+static std::string Vlast_error_file;
+
+// The last function in which an error occured
+static std::string Vlast_error_name;
+
+// The last line in a function at which an error occured
+static int Vlast_error_line = -1;
+
+// The last column in a function at which an error occured
+static int Vlast_error_column = -1;
+
 // Current error state.
 //
 // Valid values:
@@ -214,6 +226,25 @@
 
       Vlast_error_id = id;
       Vlast_error_message = msg_string;
+
+      Vlast_error_line = -1;
+      Vlast_error_column = -1;
+      Vlast_error_name = std::string ();
+      Vlast_error_file = std::string ();
+
+      if (curr_statement)
+	{
+	  octave_function *fcn
+	    = octave_call_stack::caller_user_script_or_function ();
+
+	  if (fcn)
+	    {
+	      Vlast_error_file = fcn->fcn_file_name ();
+	      Vlast_error_name = fcn->name();
+	      Vlast_error_line = curr_statement->line ();
+	      Vlast_error_column = curr_statement->column ();
+	    }
+	}
     }
 
   if (buffer_error_messages)
@@ -692,6 +723,15 @@
 }
 
 void
+rethrow_error (const char *id, const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  error_1 (std::cerr, "error", id, fmt, args);
+  va_end (args);
+}
+
+void
 panic (const char *fmt, ...)
 {
   va_list args;
@@ -782,6 +822,125 @@
   return retval;
 }
 
+DEFUN (rethrow, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} rethrow (@var{err})\n\
+Reissues a previous error as defined by @var{err}. @var{err} is a structure\n\
+that must contain at least the 'message' and 'identifier' fields. @var{err}\n\
+can also contain a field 'stack' that gives information on the assumed\n\
+location of the error. Typically @var{err} is returned from\n\
+@code{lasterror}.\n\
+@seealso{lasterror, lasterr, error}\n\
+@end deftypefn")
+{
+  octave_value retval;
+  int nargin = args.length();
+
+  if (nargin != 1)
+    print_usage();
+  else
+    {
+      Octave_map err = args(0).map_value();
+
+      if (!error_state)
+	{
+	  if (err.contains("message") && err.contains("identifier"))
+	    {
+	      std::string msg = err.contents("message")(0).string_value();
+	      std::string id = err.contents("identifier")(0).string_value();
+	      int len = msg.length();
+	      std::string file;
+	      std::string nm;
+	      int l = -1;
+	      int c = -1;
+
+	      if (err.contains("stack"))
+		{
+		  Octave_map err_stack = err.contents("stack")(0).map_value();
+
+		  if (err_stack.contains("file"))
+		    file = err_stack.contents("file")(0).string_value();
+		  if (err_stack.contains("name"))
+		    nm = err_stack.contents("name")(0).string_value();
+		  if (err_stack.contains("line"))
+		    l = err_stack.contents("line")(0).nint_value();
+		  if (err_stack.contains("column"))
+		    c = err_stack.contents("column")(0).nint_value();
+		}
+
+	      // Ugh.
+	      char *tmp_msg = strsave (msg.c_str());
+	      if (tmp_msg[len-1] == '\n')
+		{
+		  if (len > 1)
+		    {
+		      tmp_msg[len - 1] = '\0';
+		      rethrow_error (id.c_str(), "%s\n", tmp_msg);
+		    }
+		}
+	      else
+		rethrow_error (id.c_str(), "%s", tmp_msg);
+	      delete [] tmp_msg;
+
+	      // FIXME: Need to restore the stack as rethrow_error sets it?
+	      Vlast_error_file = file;
+	      Vlast_error_name = nm;
+	      Vlast_error_line = l;
+	      Vlast_error_column = c;
+
+	      if (err.contains("stack"))
+		{
+		  if (file.empty ())
+		    {
+		      if (nm.empty ())
+			{
+			  if (l > 0)
+			    if (c > 0)
+			      pr_where_1 ("error: near line %d, column %d", 
+					  l, c);
+			    else
+			      pr_where_1 ("error: near line %d", l );
+			}
+		      else
+			{
+			  if (l > 0)
+			    if (c > 0)
+			      pr_where_1 ("error: called from `%s' near line %d, column %d", 
+					  nm.c_str(), l, c);
+			    else
+			      pr_where_1 ("error: called from `%d' near line %d", nm.c_str(), l );
+			}
+		    }
+		  else
+		    {
+		      if (nm.empty ())
+			{
+			  if (l > 0)
+			    if (c > 0)
+			      pr_where_1 ("error: in file %s near line %d, column %d", 
+					  file.c_str(), l, c);
+			    else
+			      pr_where_1 ("error: in file %s near line %d", file.c_str(), l );
+			}
+		      else
+			{
+			  if (l > 0)
+			    if (c > 0)
+			      pr_where_1 ("error: called from `%s' in file %s near line %d, column %d", 
+					  nm.c_str(), file.c_str(), l, c);
+			    else
+			      pr_where_1 ("error: called from `%d' in file %s near line %d", nm.c_str(), file.c_str(), l );
+			}
+		    }
+		}
+	    }
+	  else
+	    error ("rethrow: structure must contain the fields 'message and 'identifier'");
+	}
+    }
+  return retval;
+}
+
 DEFUN (error, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} error (@var{template}, @dots{})\n\
@@ -1171,6 +1330,176 @@
   disable_warning ("Octave:variable-switch-label");
 }
 
+DEFUN (lasterror, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {@var{err} =} lasterror (@var{err})\n\
+@deftypefnx {Built-in Function} {} lasterror ('reset')\n\
+Returns or sets the last error message. Called without any arguments\n\
+returns a structure containing the last error message, as well as other\n\
+information related to this error. The elements of this structure are:\n\
+\n\
+@table @asis\n\
+@item 'message'\n\
+The text of the last error message\n\
+@item 'identifier'\n\
+The message identifier of this error message\n\
+@item 'stack'\n\
+A structure containing information on where the message occured. This might\n\
+be an empty structure if this in the case where this information can not\n\
+be obtained. The fields of this structure are:\n\
+\n\
+@table @asis\n\
+@item 'file'\n\
+The name of the file where the error occurred\n\
+@item 'name'\n\
+The name of function in which the error occured\n\
+@item 'line'\n\
+The line number at which the error occured\n\
+@item 'column'\n\
+An optional field with the column number at which the error occurred\n\
+@end table\n\
+@end table\n\
+\n\
+The @var{err} structure may also be passed to @code{lasterror} to set the\n\
+information about the last error. The only constraint on @var{err} in that\n\
+case is that it is a scalar structure. Any fields of @var{err} that match\n\
+the above are set to the value passed in @var{err}, while other fields are\n\
+set to their default values.\n\
+\n\
+If @code{lasterror} is called with the argument 'reset', all values take\n\
+their default values.\n\
+@end deftypefn")
+{
+  octave_value retval;
+  int nargin = args.length();
+
+  if (nargin < 2)
+    {
+      Octave_map err;
+
+      err.assign ("message", Vlast_error_message);
+      err.assign ("identifier", Vlast_error_id);
+
+      if (! (Vlast_error_file.empty() && Vlast_error_name.empty() &&
+	     Vlast_error_line < 0 && Vlast_error_column < 0))
+	{
+	  Octave_map err_stack;
+
+	  err_stack.assign ("file", Vlast_error_file);
+	  err_stack.assign ("name", Vlast_error_name);
+	  err_stack.assign ("line", Vlast_error_line);
+	  err_stack.assign ("column", Vlast_error_column);
+
+	  err.assign ("stack", octave_value (err_stack));
+	}
+      else
+	{
+	  string_vector sv(4);
+	  sv[0] = "file"; 
+	  sv[1] = "name";
+	  sv[2] = "line";
+	  sv[3] = "column";
+	  err.assign ("stack", octave_value (Octave_map (dim_vector (0,1), 
+							 sv)));
+	}
+
+      if (nargin == 1)
+	{
+	  if (args(0).is_string())
+	    {
+	      if (args(0).string_value() == "reset")
+		{
+		  Vlast_error_message = std::string();
+		  Vlast_error_id = std::string();
+		  Vlast_error_file = std::string();
+		  Vlast_error_name = std::string();
+		  Vlast_error_line = -1;
+		  Vlast_error_column = -1;
+		}
+	      else
+		error("lasterror: unrecognized string argument");
+	    }
+	  else if (args(0).is_map ())
+	    {
+	      Octave_map new_err = args(0).map_value();
+	      std::string new_error_message;
+	      std::string new_error_id;
+	      std::string new_error_file;
+	      std::string new_error_name;
+	      int new_error_line = -1;
+	      int new_error_column = -1;
+
+	      if (!error_state && new_err.contains("message"))
+		{
+		  const std::string tmp = 
+		    new_err.contents("message")(0).string_value();
+		  new_error_message = tmp;
+		}
+
+	      if (!error_state && new_err.contains("identifier"))
+		{
+		  const std::string tmp = 
+		    new_err.contents("identifier")(0).string_value();
+		  new_error_id = tmp;
+		}
+
+	      if (!error_state && new_err.contains("stack"))
+		{
+		  Octave_map new_err_stack = 
+		    new_err.contents("identifier")(0).map_value();
+
+		  if (!error_state && new_err_stack.contains("file"))
+		    {
+		      const std::string tmp = 
+			new_err_stack.contents("file")(0).string_value();
+		      new_error_file = tmp;
+		    }
+
+		  if (!error_state && new_err_stack.contains("name"))
+		    {
+		      const std::string tmp = 
+			new_err_stack.contents("name")(0).string_value();
+		      new_error_name = tmp;
+		    }
+
+		  if (!error_state && new_err_stack.contains("line"))
+		    {
+		      const int tmp = 
+			new_err_stack.contents("line")(0).nint_value();
+		      new_error_line = tmp;
+		    }
+		  
+		  if (!error_state && new_err_stack.contains("column"))
+		    {
+		      const int tmp = 
+			new_err_stack.contents("column")(0).nint_value();
+		      new_error_column = tmp;
+		    }
+		}
+
+	      if (! error_state)
+		{
+		  Vlast_error_message = new_error_message;
+		  Vlast_error_id = new_error_id;
+		  Vlast_error_file = new_error_file;
+		  Vlast_error_name = new_error_name;
+		  Vlast_error_line = new_error_line;
+		  Vlast_error_column = new_error_column;
+		}
+	    }
+	  else
+	    error ("lasterror: argument must be a structure or a string");
+	}
+
+      if (!error_state)
+	retval = err;
+    }
+  else
+    print_usage ();
+
+  return retval;  
+}
+
 DEFUN (lasterr, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lasterr (@var{msg}, @var{msgid})\n\