changeset 6361:776e657c9422

[project @ 2007-02-27 09:45:03 by dbateman]
author dbateman
date Tue, 27 Feb 2007 09:45:03 +0000
parents 6f3902d56db8
children 027389c3e58e
files src/ChangeLog src/DLD-FUNCTIONS/regexp.cc src/error.cc
diffstat 3 files changed, 654 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Mon Feb 26 21:08:50 2007 +0000
+++ b/src/ChangeLog	Tue Feb 27 09:45:03 2007 +0000
@@ -1,3 +1,16 @@
+2007-02-27  David Bateman  <dbateman@free.fr>
+
+	* error.cc (Vlast_error_file, Vlast_erro_name, Vlast_error_row,
+	Vlast_error_column): New static variables.
+	(verror): Use them to store the location of last error.
+	(rethrow_error, Frethrow, Flasterror): New functions.
+
+        * DLD-FUNCTIONS/regexp.cc (octcellregexp): Wrapper to octregexp
+        function for cases when string or pattern are cell arrays
+        (Fregexp, Fregexpi): Use them.
+        (octregexprep): New function with functionality of old Fregexprep.
+        (Fregexprep): Treat cell arguments.
+
 2007-02-26  From Michael Goffioul  <michael.goffioul@swing.be>
 
 	* Makefile.in: Use $(LN_S) instead of ln or ln -s.
--- a/src/DLD-FUNCTIONS/regexp.cc	Mon Feb 26 21:08:50 2007 +0000
+++ b/src/DLD-FUNCTIONS/regexp.cc	Tue Feb 27 09:45:03 2007 +0000
@@ -93,12 +93,6 @@
 
   nopts = nargin - 2;
 
-  if (nargin < 2)
-    {
-      print_usage ();
-      return 0;
-    }
-
   std::string buffer = args(0).string_value ();
   if (error_state)
     {
@@ -581,6 +575,144 @@
   return retval;
 }
 
+static octave_value_list
+octcellregexp (const octave_value_list &args, int nargout, const std::string &nm,
+	       bool case_insensitive)
+{
+  octave_value_list retval;
+
+  if (args(0).is_cell())
+    {
+      OCTAVE_LOCAL_BUFFER (Cell, newretval, nargout);
+      octave_value_list new_args = args;
+      Cell cellstr = args(0).cell_value();
+      if (args(1).is_cell())
+	{
+	  Cell cellpat = args(1).cell_value();
+
+	  if (cellpat.numel() == 1)
+	    {
+	      for (int j = 0; j < nargout; j++)
+		newretval[j].resize(cellstr.dims());
+
+	      new_args(1) = cellpat(0);
+
+	      for (octave_idx_type i = 0; i < cellstr.numel (); i++)
+		{
+		  new_args(0) = cellstr(i);
+		  octave_value_list tmp = octregexp (new_args, nargout, nm, 
+						     case_insensitive);
+
+		  if (error_state)
+		    break;
+
+		  for (int j = 0; j < nargout; j++)
+		    newretval[j](i) = tmp(j);
+		}
+	    }
+	  else if (cellstr.numel() == 1)
+	    {
+	      for (int j = 0; j < nargout; j++)
+		newretval[j].resize(cellpat.dims());
+
+	      new_args(0) = cellstr(0);
+
+	      for (octave_idx_type i = 0; i < cellpat.numel (); i++)
+		{
+		  new_args(1) = cellpat(i);
+		  octave_value_list tmp = octregexp (new_args, nargout, nm, 
+						     case_insensitive);
+
+		  if (error_state)
+		    break;
+
+		  for (int j = 0; j < nargout; j++)
+		    newretval[j](i) = tmp(j);
+		}
+	    }
+	  else if (cellstr.numel() == cellpat.numel())
+	    {
+
+	      if (cellstr.dims() != cellpat.dims())
+		error ("%s: Inconsistent cell array dimensions", nm.c_str());
+	      else
+		{
+		  for (int j = 0; j < nargout; j++)
+		    newretval[j].resize(cellstr.dims());
+
+		  for (octave_idx_type i = 0; i < cellstr.numel (); i++)
+		    {
+		      new_args(0) = cellstr(i);
+		      new_args(1) = cellpat(i);
+
+		      octave_value_list tmp = octregexp (new_args, nargout, nm, 
+							 case_insensitive);
+
+		      if (error_state)
+			break;
+
+		      for (int j = 0; j < nargout; j++)
+			newretval[j](i) = tmp(j);
+		    }
+		}
+	    }
+	  else
+	    error ("regexp: cell array arguments must be scalar or equal size");
+	}
+      else
+	{
+	  for (int j = 0; j < nargout; j++)
+	    newretval[j].resize(cellstr.dims());
+
+	  for (octave_idx_type i = 0; i < cellstr.numel (); i++)
+	    {
+	      new_args(0) = cellstr(i);
+	      octave_value_list tmp = octregexp (new_args, nargout, nm, case_insensitive);
+
+	      if (error_state)
+		break;
+
+	      for (int j = 0; j < nargout; j++)
+		newretval[j](i) = tmp(j);
+	    }
+	}
+
+      if (!error_state)
+	for (int j = 0; j < nargout; j++)
+	  retval(j) = octave_value (newretval[j]);
+    }
+  else if (args(1).is_cell())
+    {
+      OCTAVE_LOCAL_BUFFER (Cell, newretval, nargout);
+      octave_value_list new_args = args;
+      Cell cellpat = args(1).cell_value();
+
+      for (int j = 0; j < nargout; j++)
+	newretval[j].resize(cellpat.dims());
+
+      for (octave_idx_type i = 0; i < cellpat.numel (); i++)
+	{
+	  new_args(1) = cellpat(i);
+	  octave_value_list tmp = octregexp (new_args, nargout, nm, case_insensitive);
+
+	  if (error_state)
+	    break;
+
+	  for (int j = 0; j < nargout; j++)
+	    newretval[j](i) = tmp(j);
+	}
+
+      if (!error_state)
+	for (int j = 0; j < nargout; j++)
+	  retval(j) = octave_value (newretval[j]);
+    }
+  else
+    retval = octregexp (args, nargout, nm, case_insensitive);
+
+  return retval;
+
+}
+
 DEFUN_DLD (regexp, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Loadable Function} {[@var{s}, @var{e}, @var{te}, @var{m}, @var{t}, @var{nm}] =} regexp (@var{str}, @var{pat})\n\
@@ -713,7 +845,17 @@
 @end table\n\
 @end deftypefn")
 {
-  return octregexp (args, nargout, "regexp", false);
+  octave_value_list retval;
+  int nargin = args.length();
+
+  if (nargin < 2)
+    print_usage ();
+  else if (args(0).is_cell() || args(1).is_cell())
+    retval = octcellregexp (args, nargout, "regexp", false);
+  else
+    retval = octregexp (args, nargout, "regexp", false);
+
+  return retval;
 }
 
 /*
@@ -876,6 +1018,11 @@
 %!error regexp('string', 'tri', 'BadArg');
 %!error regexp('string');
 
+%!assert(regexp({'asdfg-dfd';'-dfd-dfd-';'qasfdfdaq'},'-'),{6;[1,5,9];zeros(1,0)})
+%!assert(regexp({'asdfg-dfd','-dfd-dfd-','qasfdfdaq'},'-'),{6,[1,5,9],zeros(1,0)})
+%!assert(regexp({'asdfg-dfd';'-dfd-dfd-';'qasfdfdaq'},{'-';'f';'q'}),{6;[3,7];[1,9]})
+%!assert(regexp('Strings',{'t','s'}),{2,7})
+
 */
 
 DEFUN_DLD(regexpi, args, nargout,
@@ -888,7 +1035,17 @@
 if there are none. See @code{regexp} for more details\n\
 @end deftypefn")
 {
-  return octregexp (args, nargout, "regexp", true);
+  octave_value_list retval;
+  int nargin = args.length();
+
+  if (nargin < 2)
+    print_usage ();
+  else if (args(0).is_cell() || args(1).is_cell())
+    retval = octcellregexp (args, nargout, "regexpi", true);
+  else
+    retval = octregexp (args, nargout, "regexpi", true);
+
+  return retval;
 }
 
 /*
@@ -1035,62 +1192,20 @@
 %!error regexpi('string', 'tri', 'BadArg');
 %!error regexpi('string');
 
+%!assert(regexpi({'asdfg-dfd';'-dfd-dfd-';'qasfdfdaq'},'-'),{6;[1,5,9];zeros(1,0)})
+%!assert(regexpi({'asdfg-dfd','-dfd-dfd-','qasfdfdaq'},'-'),{6,[1,5,9],zeros(1,0)})
+%!assert(regexpi({'asdfg-dfd';'-dfd-dfd-';'qasfdfdaq'},{'-';'f';'q'}),{6;[3,7];[1,9]})
+%!assert(regexpi('Strings',{'t','s'}),{2,[1,7]})
+
 */
 
-DEFUN_DLD(regexprep, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Function File}  @var{string} = regexprep(@var{string}, @var{pat}, @var{repstr}, @var{options})\n\
-Replace matches of @var{pat} in  @var{string} with @var{repstr}.\n\
-\n\
-\n\
-The replacement can contain @code{$i}, which subsubstitutes\n\
-for the ith set of parentheses in the match string.  E.g.,\n\
-@example\n\
-\n\
-   regexprep(\"Bill Dunn\",'(\\w+) (\\w+)','$2, $1')\n\
-\n\
-@end example\n\
-returns \"Dunn, Bill\"\n\
-\n\
-@var{options} may be zero or more of\n\
-@table @samp\n\
-\n\
-@item once\n\
-Replace only the first occurance of @var{pat} in the result.\n\
-\n\
-@item warnings\n\
-This option is present for compatibility but is ignored.\n\
-\n\
-@item ignorecase or matchcase\n\
-Ignore case for the pattern matching (see @code{regexpi}).\n\
-Alternatively, use (?i) or (?-i) in the pattern.\n\
-\n\
-@item lineanchors and stringanchors\n\
-Whether characters ^ and $ match the beginning and ending of lines.\n\
-Alternatively, use (?m) or (?-m) in the pattern.\n\
-\n\
-@item dotexceptnewline and dotall\n\
-Whether . matches newlines in the string.\n\
-Alternatively, use (?s) or (?-s) in the pattern.\n\
-\n\
-@item freespacing or literalspacing\n\
-Whether whitespace and # comments can be used to make the regular expression more readable.\n\
-Alternatively, use (?x) or (?-x) in the pattern.\n\
-\n\
-@end table\n\
-@seealso{regexp,regexpi}\n\
-@end deftypefn")
+
+static octave_value
+octregexprep (const octave_value_list &args, const std::string &nm)
 {
-  octave_value_list retval;
-
+  octave_value retval;
   int nargin = args.length();
 
-  if (nargin < 3)
-    {
-      print_usage ();
-      return retval;
-    }
-
   // Make sure we have string,pattern,replacement
   const std::string buffer = args(0).string_value ();
   if (error_state) return retval;
@@ -1146,14 +1261,13 @@
       std::list<regexp_elem> lst;
       string_vector named;
       int nopts;
-      int sz = octregexp_list (regexpargs, "regexprep", false, lst, named, 
-			       nopts);
+      int sz = octregexp_list (regexpargs, nm , false, lst, named, nopts);
 
       if (error_state)
 	return retval;
       if (sz == 0)
 	{
-	  retval(0) = args(0);
+	  retval = args(0);
 	  return retval;
 	}
 
@@ -1233,14 +1347,13 @@
       std::list<regexp_elem> lst;
       string_vector named;
       int nopts;
-      int sz = octregexp_list (regexpargs, "regexprep", false, lst, named, 
-			       nopts);
+      int sz = octregexp_list (regexpargs, nm, false, lst, named,nopts);
 
       if (error_state)
 	return retval;
       if (sz == 0)
 	{
-	  retval(0) = args(0);
+	  retval = args(0);
 	  return retval;
 	}
 
@@ -1271,7 +1384,135 @@
       rep.append(&buffer[from],buffer.size()-from);
     }
   
-  retval(0) = rep;
+  retval = rep;
+  return retval;
+}
+
+DEFUN_DLD(regexprep, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File}  @var{string} = regexprep(@var{string}, @var{pat}, @var{repstr}, @var{options})\n\
+Replace matches of @var{pat} in  @var{string} with @var{repstr}.\n\
+\n\
+\n\
+The replacement can contain @code{$i}, which subsubstitutes\n\
+for the ith set of parentheses in the match string.  E.g.,\n\
+@example\n\
+\n\
+   regexprep(\"Bill Dunn\",'(\\w+) (\\w+)','$2, $1')\n\
+\n\
+@end example\n\
+returns \"Dunn, Bill\"\n\
+\n\
+@var{options} may be zero or more of\n\
+@table @samp\n\
+\n\
+@item once\n\
+Replace only the first occurance of @var{pat} in the result.\n\
+\n\
+@item warnings\n\
+This option is present for compatibility but is ignored.\n\
+\n\
+@item ignorecase or matchcase\n\
+Ignore case for the pattern matching (see @code{regexpi}).\n\
+Alternatively, use (?i) or (?-i) in the pattern.\n\
+\n\
+@item lineanchors and stringanchors\n\
+Whether characters ^ and $ match the beginning and ending of lines.\n\
+Alternatively, use (?m) or (?-m) in the pattern.\n\
+\n\
+@item dotexceptnewline and dotall\n\
+Whether . matches newlines in the string.\n\
+Alternatively, use (?s) or (?-s) in the pattern.\n\
+\n\
+@item freespacing or literalspacing\n\
+Whether whitespace and # comments can be used to make the regular expression more readable.\n\
+Alternatively, use (?x) or (?-x) in the pattern.\n\
+\n\
+@end table\n\
+@seealso{regexp,regexpi}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+  int nargin = args.length();
+
+  if (nargin < 3)
+    {
+      print_usage ();
+      return retval;
+    }
+
+  if (args(0).is_cell() || args(1).is_cell() || args(2).is_cell())
+    {
+      Cell str;
+      Cell pat;
+      Cell rep;
+      dim_vector dv(1,1);
+
+      if (args(0).is_cell())
+	str = args(0).cell_value();
+      else
+	str = Cell (args(0));
+
+      if (args(1).is_cell())
+	pat = args(1).cell_value();
+      else
+	pat = Cell (args(1));
+
+      if (args(2).is_cell())
+	rep = args(2).cell_value();
+      else
+	rep = Cell (args(2));
+
+      if (str.numel() != 1)
+	{
+	  dv = str.dims();
+	  if ((pat.numel() != 1 && dv != pat.dims()) ||
+	      (rep.numel() != 1 && dv != rep.dims()))
+	    error ("regexprep: Inconsistent cell array dimensions");
+	}
+      else if (pat.numel() != 1)
+	{
+	  dv = pat.dims();
+	  if ((pat.numel() != 1 && dv != pat.dims()) ||
+	      (rep.numel() != 1 && dv != rep.dims()))
+	    error ("regexprep: Inconsistent cell array dimensions");
+	}
+      else if (rep.numel() != 1)
+	dv = rep.dims();
+
+      if (!error_state)
+	{
+	  Cell ret (dv);
+	  octave_value_list new_args = args;
+
+	  if (str.numel() == 1)
+	    new_args(0) = str(0);
+	  if (pat.numel() == 1)
+	    new_args(1) = pat(0);
+	  if (rep.numel() == 1)
+	    new_args(2) = rep(0);
+
+	  for (octave_idx_type i = 0; i < dv.numel(); i++)
+	    {
+	      if (str.numel() != 1)
+		new_args(0) = str(i);
+	      if (pat.numel() != 1)
+		new_args(1) = pat(i);
+	      if (rep.numel() != 1)
+		new_args(2) = rep(i);
+	      ret(i) = octregexprep (new_args, "regexprep");
+
+	      if (error_state)
+		break;
+	    }
+
+	  if (!error_state)
+	    retval = octave_value (ret);
+	}
+    }
+  else
+    retval = octregexprep (args, "regexprep");
+
   return retval;
 }
 
@@ -1322,6 +1563,11 @@
 %!assert(regexprep("abc","(b)","$1."),"ab.c");
 %!assert(regexprep("abc","(b)","$1.."),"ab..c");
 
+## Test cell array arguments
+%!assert(regexprep("abc",{"b","a"},"?"),{"a?c","?bc"})
+%!assert(regexprep({"abc","cba"},"b","?"),{"a?c","c?a"})
+%!assert(regexprep({"abc","cba"},{"b","a"},{"?","!"}),{"a?c","cb!"})
+
 */
 
 /*
--- 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\