# HG changeset patch # User dbateman # Date 1172569503 0 # Node ID 776e657c94225015bf1a8fe3bf947b4a27c92c15 # Parent 6f3902d56db85adfe8cb7c5af78beb229981ca71 [project @ 2007-02-27 09:45:03 by dbateman] diff -r 6f3902d56db8 -r 776e657c9422 src/ChangeLog --- 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 + + * 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 * Makefile.in: Use $(LN_S) instead of ln or ln -s. diff -r 6f3902d56db8 -r 776e657c9422 src/DLD-FUNCTIONS/regexp.cc --- 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 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 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!"}) + */ /* diff -r 6f3902d56db8 -r 776e657c9422 src/error.cc --- 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\