Mercurial > hg > octave-nkf
changeset 13594:b45d772bafbb
Merge with Savannah
author | Jordi Gutiérrez Hermoso <jordigh@gmail.com> |
---|---|
date | Tue, 09 Aug 2011 10:01:51 -0500 |
parents | 9f2679a14366 (diff) fe30859fb540 (current diff) |
children | 56eb9348ff02 |
files | |
diffstat | 67 files changed, 642 insertions(+), 574 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/interpreter/container.txi +++ b/doc/interpreter/container.txi @@ -974,7 +974,7 @@ a = @{1, [2, 3], 4, 5, 6@}; b = [a@{1:4@}] @result{} b = - 1 2 3 4 + 1 2 3 4 5 @end group @end example
--- a/doc/refcard/refcard.tex +++ b/doc/refcard/refcard.tex @@ -863,14 +863,14 @@ gray2ind ({\it i}, {\it n})&convert gray scale to Octave image\cr image ({\it img}, {\it zoom})&display an Octave image matrix\cr imagesc ({\it img}, {\it zoom})&display scaled matrix as image\cr +imread ({\it file})&load an image file\cr imshow ({\it img}, {\it map})&display Octave image\cr imshow ({\it i}, {\it n})&display gray scale image\cr imshow ({\it r}, {\it g}, {\it b})&display RGB image\cr +imwrite ({\it img}, {\it file})&write images in various file formats\cr ind2gray ({\it img}, {\it map})&convert Octave image to gray scale\cr ind2rgb ({\it img}, {\it map})&convert indexed image to RGB\cr -loadimage ({\it file})&load an image file\cr rgb2ind ({\it r}, {\it g}, {\it b})&convert RGB to Octave image\cr -\omit\tt saveimage ({\it file}, {\it img}, {\it fmt}, {\it map})\quad\rm save a matrix to {\it file}\span\cr \endsec
--- a/liboctave/cmd-edit.cc +++ b/liboctave/cmd-edit.cc @@ -765,7 +765,7 @@ default_command_editor::do_readline (const std::string& prompt, bool& eof) { gnulib::fputs (prompt.c_str (), output_stream); - fflush (output_stream); + gnulib::fflush (output_stream); return octave_fgetl (input_stream, eof); }
--- a/liboctave/kpse.cc +++ b/liboctave/kpse.cc @@ -212,7 +212,7 @@ /* A printf for the debugging. */ #define DEBUGF_START() do { gnulib::fputs ("kdebug:", stderr) -#define DEBUGF_END() fflush (stderr); } while (0) +#define DEBUGF_END() gnulib::fflush (stderr); } while (0) #define DEBUGF(str) \ DEBUGF_START (); gnulib::fputs (str, stderr); DEBUGF_END () @@ -432,7 +432,7 @@ } gnulib::putc ('\n', stderr); } - fflush (stderr); + gnulib::fflush (stderr); } #endif @@ -2428,7 +2428,7 @@ gnulib::fprintf (stderr, " %s", (STR_LLIST (*e)).c_str ()); } gnulib::putc ('\n', stderr); - fflush (stderr); + gnulib::fflush (stderr); } #endif /* KPSE_DEBUG */
--- a/liboctave/lo-utils.cc +++ b/liboctave/lo-utils.cc @@ -124,7 +124,7 @@ do { - if (fgets (bufptr, grow_size, f)) + if (gnulib::fgets (bufptr, grow_size, f)) { len = strlen (bufptr); @@ -244,6 +244,8 @@ return d; } +// Read a double value. Discard any sign on NaN and NA. + template <> double octave_read_value (std::istream& is) @@ -261,7 +263,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_inf_nan_na (is, c2, c1); else { @@ -276,7 +278,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_inf_nan_na (is, c2, c1); else { @@ -392,6 +394,8 @@ return d; } +// Read a float value. Discard any sign on NaN and NA. + template <> float octave_read_value (std::istream& is) @@ -409,7 +413,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_float_inf_nan_na (is, c2, c1); else { @@ -424,7 +428,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_float_inf_nan_na (is, c2, c1); else {
--- a/liboctave/sparse-util.cc +++ b/liboctave/sparse-util.cc @@ -52,7 +52,7 @@ va_list args; va_start (args, fmt); int ret = gnulib::vfprintf (stderr, fmt, args); - fflush (stderr); + gnulib::fflush (stderr); va_end (args); return ret; }
--- a/scripts/deprecated/saveimage.m +++ b/scripts/deprecated/saveimage.m @@ -30,8 +30,7 @@ ## Portable pixmap format. ## ## @item "ps" -## PostScript format. Note that images saved in PostScript format cannot -## be read back into Octave with loadimage. +## PostScript format. ## @end table ## ## If the fourth argument is supplied, the specified colormap will also be @@ -42,7 +41,7 @@ ## image is a gray scale image (the entries within each row of the colormap ## are equal) the gray scale ppm and PostScript image formats are used, ## otherwise the full color formats are used. -## @seealso{loadimage, save, load, colormap} +## @seealso{imread, save, load, colormap} ## @end deftypefn ## The conversion to PostScript is based on pbmtolps.c, which was
--- a/scripts/general/accumarray.m +++ b/scripts/general/accumarray.m @@ -72,7 +72,7 @@ endif if (iscell (subs)) - subs = cellfun (@vec, subs, "uniformoutput", false); + subs = cellfun ("vec", subs, "uniformoutput", false); ndims = numel (subs); if (ndims == 1) subs = subs{1}; @@ -149,7 +149,7 @@ if (ndims > 1) if (isempty (sz)) if (iscell (subs)) - sz = cellfun (@max, subs); + sz = cellfun ("max", subs); else sz = max (subs, [], 1); endif
--- a/scripts/general/arrayfun.m +++ b/scripts/general/arrayfun.m @@ -154,7 +154,7 @@ args = varargin(1:nargs); opts = varargin(nargs+1:end); - args = cellfun (@num2cell, args, "UniformOutput", false, + args = cellfun ("num2cell", args, "UniformOutput", false, "ErrorHandler", @arg_class_error); [varargout{1:max(1, nargout)}] = cellfun (func, args{:}, opts{:});
--- a/scripts/general/blkdiag.m +++ b/scripts/general/blkdiag.m @@ -33,7 +33,7 @@ print_usage (); endif - if (! all (cellfun (@isnumeric, varargin))) + if (! all (cellfun ("isnumeric", varargin))) error ("blkdiag: all arguments must be numeric"); endif
--- a/scripts/general/cell2mat.m +++ b/scripts/general/cell2mat.m @@ -43,11 +43,11 @@ else ## We only want numeric, logical, and char matrices. - valid = cellfun (@isnumeric, c); - valid |= cellfun (@islogical, c); - valid |= cellfun (@ischar, c); - validc = cellfun (@iscell, c); - valids = cellfun (@isstruct, c); + valid = cellfun ("isnumeric", c); + valid |= cellfun ("islogical", c); + valid |= cellfun ("isclass", c, "char"); + validc = cellfun ("isclass", c, "cell"); + valids = cellfun ("isclass", c, "struct"); if (! all (valid(:)) && ! all (validc(:)) && ! all (valids(:))) error ("cell2mat: wrong type elements or mixed cells, structs and matrices"); @@ -71,7 +71,7 @@ endif xdim = [1:idim-1, idim+1:nd]; cc = num2cell (c, xdim); - c = cellfun (@cat, {idim}, cc{:}, "uniformoutput", false); + c = cellfun ("cat", {idim}, cc{:}, "uniformoutput", false); endfor m = c{1}; endif
--- a/scripts/general/common_size.m +++ b/scripts/general/common_size.m @@ -52,7 +52,7 @@ endif ## Find scalar args. - nscal = cellfun (@numel, varargin) != 1; + nscal = cellfun ("numel", varargin) != 1; i = find (nscal, 1); @@ -60,7 +60,7 @@ errorcode = 0; varargout = varargin; else - match = cellfun (@size_equal, varargin, varargin(i)); + match = cellfun ("size_equal", varargin, varargin(i)); if (any (nscal &! match)) errorcode = 1; varargout = varargin;
--- a/scripts/general/interp3.m +++ b/scripts/general/interp3.m @@ -92,7 +92,7 @@ error ("interp3: expect 3-dimensional array of values"); endif x = varargin (2:4); - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : 3 if (! size_equal (x{1}, x{i})) error ("interp3: dimensional mismatch"); @@ -109,7 +109,7 @@ error ("interp3: expect 3-dimensional array of values"); endif x = varargin (1:3); - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : 3 if (! size_equal (x{1}, x{i}) || ! size_equal (x{i}, v)) error ("interp3: dimensional mismatch"); @@ -119,7 +119,7 @@ x{1} = permute (x{1}, [2, 1, 3]); endif y = varargin (5:7); - if (any (! cellfun (@isvector, y))) + if (any (! cellfun ("isvector", y))) for i = 2 : 3 if (! size_equal (y{1}, y{i})) error ("interp3: dimensional mismatch");
--- a/scripts/general/interpn.m +++ b/scripts/general/interpn.m @@ -124,7 +124,7 @@ error ("interpn: wrong number or incorrectly formatted input arguments"); endif - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : nd if (! size_equal (x{1}, x{i}) || ! size_equal (x{i}, v)) error ("interpn: dimensional mismatch"); @@ -140,8 +140,8 @@ method = tolower (method); - all_vectors = all (cellfun (@isvector, y)); - different_lengths = numel (unique (cellfun (@numel, y))) > 1; + all_vectors = all (cellfun ("isvector", y)); + different_lengths = numel (unique (cellfun ("numel", y))) > 1; if (all_vectors && different_lengths) [foobar(1:numel(y)).y] = ndgrid (y{:}); y = {foobar.y}; @@ -169,7 +169,7 @@ vi(idx) = extrapval; vi = reshape (vi, yshape); elseif (strcmp (method, "spline")) - if (any (! cellfun (@isvector, y))) + if (any (! cellfun ("isvector", y))) for i = 2 : nd if (! size_equal (y{1}, y{i})) error ("interpn: dimensional mismatch");
--- a/scripts/general/private/__isequal__.m +++ b/scripts/general/private/__isequal__.m @@ -59,16 +59,16 @@ ## All arguments must either be of the same class or they must be ## numeric values. t = (all (strcmp (class(x), - cellfun (@class, varargin, "uniformoutput", false))) + cellfun ("class", varargin, "uniformoutput", false))) || ((isnumeric (x) || islogical (x)) - && all (cellfun (@isnumeric, varargin) - | cellfun (@islogical, varargin)))); + && all (cellfun ("isnumeric", varargin) + | cellfun ("islogical", varargin)))); if (t) ## Test that everything has the same number of dimensions. s_x = size (x); s_v = cellfun (@size, varargin, "uniformoutput", false); - t = all (length (s_x) == cellfun (@length, s_v)); + t = all (length (s_x) == cellfun ("length", s_v)); endif if (t) @@ -96,8 +96,8 @@ ## Test the number of fields. fn_x = fieldnames (x); l_fn_x = length (fn_x); - fn_v = cellfun (@fieldnames, varargin, "uniformoutput", false); - t = all (l_fn_x == cellfun (@length, fn_v)); + fn_v = cellfun ("fieldnames", varargin, "uniformoutput", false); + t = all (l_fn_x == cellfun ("length", fn_v)); ## Test that all the names are equal. idx = 0; @@ -146,7 +146,7 @@ elseif (isa (x, "function_handle")) ## The == operator is overloaded for handles. - t = all (cellfun (@eq, {x}, varargin)); + t = all (cellfun ("eq", {x}, varargin)); else ## Check the numeric types.
--- a/scripts/general/structfun.m +++ b/scripts/general/structfun.m @@ -106,7 +106,7 @@ [varargout{:}] = cellfun (func, struct2cell (S), varargin{:}); if (! uniform_output) - varargout = cellfun (@cell2struct, varargout, {fieldnames(S)}, {1}, uo_str, false); + varargout = cellfun ("cell2struct", varargout, {fieldnames(S)}, {1}, uo_str, false); endif endfunction
--- a/scripts/geometry/voronoi.m +++ b/scripts/geometry/voronoi.m @@ -129,7 +129,7 @@ idx = find (!infi); ll = length (idx); c = c(idx).'; - k = sum (cellfun ('length', c)); + k = sum (cellfun ("length", c)); edges = cell2mat(cellfun (@(x) [x ; [x(end), x(1:end-1)]], c, "uniformoutput", false));
--- a/scripts/io/strread.m +++ b/scripts/io/strread.m @@ -37,18 +37,20 @@ ## @item %s ## The word is parsed as a string. ## +## @itemx %f +## @itemx %n +## The word is parsed as a number and converted to double. +## ## @item %d -## @itemx %f ## @itemx %u -## @itemx %n -## The word is parsed as a number (and converted to double). +## The word is parsed as a number and converted to int32. ## ## @item %*', '%*f', '%*s ## The word is skipped. ## ## For %s and %d, %f, %n, %u and the associated %*s @dots{} specifiers an ## optional width can be specified as %Ns, etc. where N is an integer > 1. -## For %f, formats like %N.Mf are allowed. +## For %f, format specifiers like %N.Mf are allowed. ## ## @item literals ## In addition the format may contain literal character strings; these will be @@ -354,10 +356,17 @@ str = cell2mat (str); ## Remove leading & trailing space, but preserve delimiters. str = strtrim (str); + ## FIXME: Double strrep on str is enormously expensive of CPU time. + ## Can this be eliminated + ## Wipe leading and trailing whitespace on each line (it may be delimiter too) + if (! isempty (eol_char)) + str = strrep (str, [eol_char " "], eol_char); + str = strrep (str, [" " eol_char], eol_char); + endif endif ## Split 'str' into words - words = split_by (str, delimiter_str, mult_dlms_s1); + words = split_by (str, delimiter_str, mult_dlms_s1, eol_char); if (! isempty (white_spaces)) ## Trim leading and trailing white_spaces ## FIXME: Is this correct? strtrim clears what matches isspace(), not @@ -398,7 +407,8 @@ ## 1. Assess "period" in the split-up words array ( < num_words_per_line). ## Could be done using EndOfLine but that prohibits EndOfLine = "" option. - ## Alternative below goes by simply parsing the first "line" of words: + ## Alternative below goes by simply parsing a first grab of words + ## and counting words until the fmt_words array is exhausted: iwrd = 1; iwrdp = 0; iwrdl = length (words{iwrd}); for ii = 1:numel (fmt_words) @@ -480,7 +490,7 @@ if ((idf(ii) || idg(ii)) && (rows(words) < num_words_per_line)) if (idf(ii)) s = strfind (words(icol, 1), fmt_words{ii}); - if (isempty (s)) + if (isempty (s{:})) error ("strread: Literal '%s' not found in column %d", fmt_words{ii}, icol); endif s = s{:}(1); @@ -496,8 +506,8 @@ if (! idg(ii) && ! isempty (s) && s(1) == 1) ## Leading literal. Assign literal to icol, paste rest in icol + 1 ## Apply only to those cells that do have something beyond literal - jptr = find ([cellfun(@(x) length(x), words(icol+1, jptr), ... - "UniformOutput", false){:}] > e(1)); + jptr = find (cellfun("length", words(icol+1, jptr), ... + "UniformOutput", false) > e(1)); words(icol+1, :) = {""}; words(icol+1, jptr) = cellfun ... (@(x) substr(x, e(1)+1, length(x)-e(1)), words(icol, jptr), ... @@ -585,6 +595,11 @@ n = cellfun ("isempty", data); ### FIXME - erroneously formatted data lead to NaN, not an error data = str2double (data); + if (! isempty (regexp (fmt_words{m}, "%[du]"))) + ## Cast to integer + ## FIXME: NaNs will be transformed into zeros + data = int32 (data); + end data(n) = numeric_fill_value; if (pad_out) data(end+1:num_lines) = numeric_fill_value; @@ -607,7 +622,11 @@ if (numel (nfmt) > 1) sprec = str2double (nfmt{2}); data = 10^-sprec * round (10^sprec * data); - endif + elseif (! isempty (regexp (fmt_words{m}, "[du]"))) + ## Cast to integer + ## FIXME: NaNs will be transformed into zeros + data = int32 (data); + end varargout{k} = data.'; k++; case "s" @@ -643,17 +662,16 @@ endfunction -function out = split_by (text, sep, mult_dlms_s1) +function out = split_by (text, sep, mult_dlms_s1, eol_char) ## Check & if needed, process MultipleDelimsAsOne parameter if (mult_dlms_s1) mult_dlms_s1 = true; + ## FIXME: Should re-implement strsplit() function here in order + ## to avoid strrep on megabytes of data. ## If \n is in sep collection we need to enclose it in spaces in text ## to avoid it being included in consecutive delim series - ## FIXME: This only works if eol is LF or CRLF. Won't work on Mac - ## Should probably use eol_char in this case. - ## Also unlikely to work if <space> is not in white_space - text = strrep (text, "\n", " \n "); + text = strrep (text, eol_char, [" " eol_char " "]); else mult_dlms_s1 = false; endif @@ -661,7 +679,7 @@ ## Split text string along delimiters out = strsplit (text, sep, mult_dlms_s1); ## In case of trailing delimiter, strip stray last empty word - if (any (sep == text(end))) + if (!isempty (out) && any (sep == text(end))) out(end) = []; endif @@ -673,13 +691,8 @@ %!test %! [a, b] = strread ("1 2", "%f%f"); -%! assert (a == 1 && b == 2); - -%!test -%! str = "# comment\n# comment\n1 2 3"; -%! [a, b] = strread (str, '%d %s', 'commentstyle', 'shell', 'endofline', "\n"); -%! assert (a, [1; 3]); -%! assert (b, {"2"}); +%! assert (a, 1); +%! assert (b, 2); %!test %! str = ''; @@ -689,7 +702,7 @@ %! str = sprintf ('%s %.6f %s\n', str, a(k), b(k)); %! endfor %! [aa, bb] = strread (str, '%f %s'); -%! assert (a, aa, 1e-5); +%! assert (a, aa, 1e-6); %! assert (cellstr (b), bb); %!test @@ -700,7 +713,7 @@ %! str = sprintf ('%s %.6f %s\n', str, a(k), b(k)); %! endfor %! aa = strread (str, '%f %*s'); -%! assert (a, aa, 1e-5); +%! assert (a, aa, 1e-6); %!test %! str = sprintf ('/* this is\nacomment*/ 1 2 3'); @@ -708,6 +721,12 @@ %! assert (a, [1; 2; 3]); %!test +%! str = "# comment\n# comment\n1 2 3"; +%! [a, b] = strread (str, '%n %s', 'commentstyle', 'shell', 'endofline', "\n"); +%! assert (a, [1; 3]); +%! assert (b, {"2"}); + +%!test %! str = sprintf ("Tom 100 miles/hr\nDick 90 miles/hr\nHarry 80 miles/hr"); %! fmt = "%s %f miles/hr"; %! c = cell (1, 2); @@ -738,14 +757,14 @@ %! assert (double (a{3}(end-5:end)), [32 110 97 109 101 62]); %!test -%! [a, b, c, d] = strread ("1,2,3,,5,6", "%d%d%d%d", 'delimiter', ','); -%! assert (c, 3); +%! [a, b, c, d] = strread ("1,2,3,,5,6", "%d%f%d%f", 'delimiter', ','); +%! assert (c, int32 (3)); %! assert (d, NaN); %!test -%! [a, b, c, d] = strread ("1,2,3,,5,6\n", "%d%d%d%d", 'delimiter', ','); +%! [a, b, c, d] = strread ("1,2,3,,5,6\n", "%d%d%f%d", 'delimiter', ','); %! assert (c, [3; NaN]); -%! assert (d, [NaN; NaN]); +%! assert (d, int32 ([0; 0])); %!test %! # Default format (= %f) @@ -760,24 +779,18 @@ %!test %! # TreatAsEmpty -%! [a, b, c, d] = strread ("1,2,3,NN,5,6\n", "%d%d%d%d", 'delimiter', ',', 'TreatAsEmpty', 'NN'); -%! assert (c, [3; NaN]); +%! [a, b, c, d] = strread ("1,2,3,NN,5,6\n", "%d%d%d%f", 'delimiter', ',', 'TreatAsEmpty', 'NN'); +%! assert (c, int32 ([3; 0])); %! assert (d, [NaN; NaN]); %!test %! # No delimiters at all besides EOL. Plain reading numbers & strings %! str = "Text1Text2Text\nText398Text4Text\nText57Text"; %! c = textscan (str, "Text%dText%1sText"); -%! assert (c{1}, [1; 398; 57]); +%! assert (c{1}, int32 ([1; 398; 57])); %! assert (c{2}(1:2), {'2'; '4'}); %! assert (isempty (c{2}{3}), true); -%!test -%! # No delimiters at all besides EOL. Skip fields, even empty fields -%! str = "Text1Text2Text\nTextText4Text\nText57Text"; -%! c = textscan (str, "Text%*dText%dText"); -%! assert (c{1}, [2; 4; NaN]); - %% MultipleDelimsAsOne %!test %! str = "11, 12, 13,, 15\n21,, 23, 24, 25\n,, 33, 34, 35";
--- a/scripts/io/textscan.m +++ b/scripts/io/textscan.m @@ -34,13 +34,18 @@ ## @code{strread}, this function supports a few more: ## ## @itemize -## @item "headerlines": -## The first @var{value} number of lines of @var{fid} are skipped. +## @item "collectoutput": +## A value of 1 or true instructs textscan to concatenate consecutive columns +## of the same class in the output cell array. A value of 0 or false (default) +## leaves output in distinct columns. ## ## @item "endofline": -## Specify a single character or "\r\n". If no value is given, it will be -## inferred from the file. If set to "" (empty string) EOLs are ignored as -## delimiters. +## Specify "\r", "\n" or "\r\n" (for CR, LF, or CRLF). If no value is given, +## it will be inferred from the file. If set to "" (empty string) EOLs are +## ignored as delimiters and added to whitespace. +## +## @item "headerlines": +## The first @var{value} number of lines of @var{fid} are skipped. ## ## @item "returnonerror": ## If set to numerical 1 or true (default), return normally when read errors @@ -116,6 +121,20 @@ args(end+1:end+2) = {'delimiter', ""}; endif + collop = false; + ipos = find (strcmpi (args, "collectoutput")); + if (! isempty (ipos)) + ## Search & concatenate consecutive columns of same class requested + if (isscalar (args{ipos+1}) + && (islogical (args{ipos+1}) || isnumeric (args{ipos+1}))) + collop = args{ipos+1}; + else + warning ("textscan: illegal value for CollectOutput parameter - ignored"); + endif + ## Remove argument before call to strread() below + args(ipos:ipos+1) = []; + endif + if (any (strcmpi (args, "returnonerror"))) ## Because of the way strread() reads data (columnwise) this parameter ## can't be neatly implemented. strread() will pick it up anyway @@ -143,9 +162,11 @@ str = tmp_str = ""; n = 0; ## FIXME: Can this be done without slow loop? - while (ischar (tmp_str) && n++ <= nlines) - str = strcat (str, tmp_str); + while (ischar (tmp_str) && n++ < nlines) tmp_str = fgets (fid); + if (ischar (tmp_str)) + str = strcat (str, tmp_str); + endif endwhile else str = fread (fid, "char=>char").'; @@ -164,6 +185,9 @@ if (! isempty (endofline)) if (ischar (args{endofline + 1})) eol_char = args{endofline + 1}; + if (isempty (strmatch (eol_char, {"", "\n", "\r", "\r\n"}, 'exact'))) + error ("textscan: illegal EndOfLine character value specified"); + endif else error ("textscan: character value required for EndOfLine"); endif @@ -195,6 +219,11 @@ ## Call strread to make it do the real work C = cell (1, num_fields); [C{:}] = strread (str, format, args{:}); + + ## If requested, collect output columns of same class + if (collop) + C = colloutp (C); + endif if (nargout == 2) position = ftell (fid); @@ -203,6 +232,32 @@ endfunction +## Collect consecutive columns of same class into one cell column +function C = colloutp (C) + + ## Start at rightmost column and work backwards to avoid ptr mixup + ii = numel (C); + while ii > 1 + clss1 = class (C{ii}); + jj = ii; + while (jj > 1 && strcmp (clss1, class (C{jj - 1}))) + ## Column to the left is still same class; check next column to the left + --jj; + endwhile + if (jj < ii) + ## Concatenate columns into current column + C{jj} = [C{jj : ii}]; + ## Wipe concatenated columns to the right, resume search to the left + C(jj+1 : ii) = []; + ii = jj - 1; + else + ## No similar class in column to the left, search from there + --ii; + endif + endwhile + +endfunction + %!test %! str = "1, 2, 3, 4\n 5, , , 8\n 9, 10, 11, 12"; %! fmtstr = "%f %d %f %s"; @@ -218,13 +273,13 @@ %! str = sprintf ("%g miles/hr = %g kilometers/hr\n", b); %! fmt = "%f miles/hr = %f kilometers/hr"; %! c = textscan (str, fmt); -%! assert (b(1,:)', c{1}); -%! assert (b(2,:)', c{2}); +%! assert (b(1,:)', c{1}, 1e-5); +%! assert (b(2,:)', c{2}, 1e-5); #%!test #%! str = "13, 72, NA, str1, 25\r\n// Middle line\r\n36, na, 05, str3, 6"; #%! a = textscan(str, '%d %n %f %s %n', 'delimiter', ',','treatAsEmpty', {'NA', 'na'},'commentStyle', '//'); -#%! assert (a{1}, [13; 36]); +#%! assert (a{1}, int32([13; 36])); #%! assert (a{2}, [72; NaN]); #%! assert (a{3}, [NaN; 5]); #%! assert (a{4}, {"str1"; "str3"}); @@ -237,9 +292,9 @@ %! str = [str "Km:25 = hhhZ\r\n"]; %! fmt = "Km:%d = hhh%1sjjj miles%dhour"; %! a = textscan (str, fmt, 'delimiter', ' '); -%! assert (a{1}', [10 15 2 25], 1e-5); +%! assert (a{1}', int32([10 15 2 25])); %! assert (a{2}', {'B' 'J' 'R' 'Z'}); -%! assert (a{3}', [16 241 3 NaN], 1e-5); +%! assert (a{3}', int32([16 241 3 0])); %% Test with default endofline parameter %!test @@ -251,6 +306,22 @@ %! c = textscan ("L1\nL2", "%s", 'endofline', ''); %! assert (int8(c{:}{:}), int8([ 76, 49, 10, 76, 50 ])); +%!test +%! # No delimiters at all besides EOL. Skip fields, even empty fields +%! str = "Text1Text2Text\nTextText4Text\nText57Text"; +%! c = textscan (str, "Text%*dText%dText"); +%! assert (c{1}, int32 ([2; 4; 0])); + +%!test +%% CollectOutput test +%! b = [10:10:100]; +%! b = [b; 8*b/5; 8*b*1000/5]; +%! str = sprintf ("%g miles/hr = %g (%g) kilometers (meters)/hr\n", b); +%! fmt = "%f miles%s %s %f (%f) kilometers %*s"; +%! c = textscan (str, fmt, 'collectoutput', 1); +%! assert (size(c{3}), [10, 2]); +%! assert (size(c{2}), [10, 2]); + %% Test input validation %!error textscan () %!error textscan (single (4)) @@ -258,3 +329,4 @@ %!error <must be a string> textscan ("Hello World", 2) %!error <cannot provide position information> [C, pos] = textscan ("Hello World") %!error <character value required> textscan ("Hello World", '%s', 'EndOfLine', 3) +
--- a/scripts/linear-algebra/orth.m +++ b/scripts/linear-algebra/orth.m @@ -39,6 +39,11 @@ if (nargin == 1 || nargin == 2) + if (isempty (A)) + retval = []; + return; + endif + [U, S, V] = svd (A); [rows, cols] = size (A);
--- a/scripts/miscellaneous/fullfile.m +++ b/scripts/miscellaneous/fullfile.m @@ -26,7 +26,7 @@ if (nargin > 0) ## Discard all empty arguments - varargin(cellfun (@isempty, varargin)) = []; + varargin(cellfun ("isempty", varargin)) = []; nargs = numel (varargin); if (nargs > 1) filename = varargin{1};
--- a/scripts/miscellaneous/getfield.m +++ b/scripts/miscellaneous/getfield.m @@ -50,8 +50,8 @@ print_usage (); endif subs = varargin; - flds = cellfun (@ischar, subs); - idxs = cellfun (@iscell, subs); + flds = cellfun ("isclass", subs, "char"); + idxs = cellfun ("isclass", subs, "cell"); if (all (flds | idxs)) typs = merge (flds, {"."}, {"()"}); obj = subsref (s, struct ("type", typs, "subs", subs));
--- a/scripts/miscellaneous/private/__xzip__.m +++ b/scripts/miscellaneous/private/__xzip__.m @@ -110,10 +110,10 @@ endfunction function [d, f] = myfileparts (files) - [d, f, ext] = cellfun (@(x) fileparts (x), files, "uniformoutput", false); + [d, f, ext] = cellfun ("fileparts", files, "uniformoutput", false); f = cellfun (@(x, y) sprintf ("%s%s", x, y), f, ext, "uniformoutput", false); - idx = cellfun (@isdir, files); + idx = cellfun ("isdir", files); d(idx) = ""; f(idx) = files(idx); endfunction
--- a/scripts/miscellaneous/setfield.m +++ b/scripts/miscellaneous/setfield.m @@ -50,8 +50,8 @@ endif subs = varargin(1:end-1); rhs = varargin{end}; - flds = cellfun (@ischar, subs); - idxs = cellfun (@iscell, subs); + flds = cellfun ("isclass", subs, "char"); + idxs = cellfun ("isclass", subs, "cell"); if (all (flds | idxs)) typs = merge (flds, {"."}, {"()"}); obj = subsasgn (obj, struct ("type", typs, "subs", subs), rhs);
--- a/scripts/miscellaneous/what.m +++ b/scripts/miscellaneous/what.m @@ -90,7 +90,7 @@ if (length (f) > 0) printf ("%s %s:\n\n", msg, p); - maxlen = max (cellfun (@length, f)); + maxlen = max (cellfun ("length", f)); ncols = max (1, floor (terminal_size()(2) / (maxlen + 3))); fmt = ""; for i = 1: ncols
--- a/scripts/pkg/pkg.m +++ b/scripts/pkg/pkg.m @@ -369,8 +369,8 @@ unwind_protect if (octave_forge) - [urls, local_files] = cellfun (@get_forge_download, files, "uniformoutput", false); - [files, succ] = cellfun (@urlwrite, urls, local_files, "uniformoutput", false); + [urls, local_files] = cellfun ("get_forge_download", files, "uniformoutput", false); + [files, succ] = cellfun ("urlwrite", urls, local_files, "uniformoutput", false); succ = [succ{:}]; if (! all (succ)) i = find (! succ, 1); @@ -382,7 +382,7 @@ global_list, global_install); unwind_protect_cleanup - cellfun (@unlink, local_files); + cellfun ("unlink", local_files); end_unwind_protect case "uninstall" @@ -1418,7 +1418,7 @@ if (isempty (filenames)) idx = []; else - idx = cellfun (@is_architecture_dependent, filenames); + idx = cellfun ("is_architecture_dependent", filenames); endif archdependent = filenames (idx); archindependent = filenames (!idx);
--- a/scripts/plot/axis.m +++ b/scripts/plot/axis.m @@ -323,10 +323,10 @@ data(data<=0) = NaN; end if (iscell (data)) - data = data (find (! cellfun (@isempty, data))); + data = data (find (! cellfun ("isempty", data))); if (! isempty (data)) - lims_min = min (cellfun (@min, cellfun (@min, data, 'uniformoutput', false)(:))); - lims_max = max (cellfun (@max, cellfun (@max, data, 'uniformoutput', false)(:))); + lims_min = min (cellfun ("min", cellfun ("min", data, 'uniformoutput', false)(:))); + lims_max = max (cellfun ("max", cellfun ("max", data, 'uniformoutput', false)(:))); lims = [lims_min, lims_max]; else lims = [0, 1];
--- a/scripts/plot/pareto.m +++ b/scripts/plot/pareto.m @@ -66,11 +66,11 @@ if (ischar (y)) y = cellstr (y); else - y = cellfun (@num2str, num2cell (y), "uniformoutput", false); + y = cellfun ("num2str", num2cell (y), "uniformoutput", false); endif endif else - y = cellfun (@int2str, num2cell (1 : numel(x)), + y = cellfun ("int2str", num2cell (1 : numel(x)), "uniformoutput", false); endif
--- a/scripts/plot/private/__ghostscript__.m +++ b/scripts/plot/private/__ghostscript__.m @@ -44,7 +44,7 @@ cleanup_cmd = ""; args = varargin; - n = find (cellfun (@isstruct, args)); + n = find (cellfun ("isclass", args, "struct")); if (! isempty (n)) f = fieldnames (args{n}); for m = 1:numel(f)
--- a/scripts/plot/private/__go_draw_axes__.m +++ b/scripts/plot/private/__go_draw_axes__.m @@ -1312,7 +1312,7 @@ fputs (plot_stream, "unset hidden3d;\n"); endif - have_data = (! (isempty (data) || all (cellfun (@isempty, data)))); + have_data = (! (isempty (data) || all (cellfun ("isempty", data)))); ## Note we don't use the [xy]2range of gnuplot as we don't use the ## dual axis plotting features of gnuplot. @@ -2328,7 +2328,7 @@ l = length (s) - length (strfind(s,'{')) - length (strfind(s,'}')); m = regexp (s, '/([\w-]+|[\w-]+=\d+)', 'matches'); if (!isempty (m)) - l = l - sum (cellfun (@length, m)); + l = l - sum (cellfun ("length", m)); endif endfunction
--- a/scripts/plot/private/__patch__.m +++ b/scripts/plot/private/__patch__.m @@ -134,7 +134,7 @@ endif else args = varargin; - if (any(cellfun (@(x) strcmpi(x,"faces") || strcmpi(x, "vertices"), args))) + if (any (strcmpi (args, "faces") | strcmpi (args, "vertices"))) args = setdata (args); else args = setvertexdata (args);
--- a/scripts/plot/refreshdata.m +++ b/scripts/plot/refreshdata.m @@ -83,7 +83,7 @@ obj = get (h (i)); fldnames = fieldnames (obj); m = regexpi (fieldnames(obj), '^.+datasource$', "match"); - idx = cellfun (@(x) !isempty(x), m); + idx = ! cellfun ("isempty", m); if (any (idx)) tmp = m(idx); props = [props; {vertcat(tmp{:})}];
--- a/scripts/plot/whitebg.m +++ b/scripts/plot/whitebg.m @@ -74,7 +74,7 @@ if (isroot) fac = get (0, "factory"); fields = fieldnames (fac); - fieldindex = intersect (find (!cellfun (@isempty, regexp(fields, 'color'))), union (find (!cellfun (@isempty, regexp(fields, 'factoryaxes.*'))), find (!cellfun (@isempty, regexp(fields, 'factoryfigure.*'))))); + fieldindex = intersect (find (!cellfun ("isempty", regexp(fields, 'color'))), union (find (!cellfun ("isempty", regexp(fields, 'factoryaxes.*'))), find (!cellfun ("isempty", regexp(fields, 'factoryfigure.*'))))); ## Check whether the factory value has been replaced for nf = 1 : numel (fieldindex); @@ -104,7 +104,7 @@ for nh = 1 : numel(h) p = get (h (nh)); fields = fieldnames (p); - fieldindex = find (!cellfun (@isempty, regexp(fields, 'color'))); + fieldindex = find (!cellfun ("isempty", regexp(fields, 'color'))); if (numel (fieldindex)) for nf = 1 : numel (fieldindex); field = fields {fieldindex (nf)}; @@ -121,7 +121,7 @@ def = get (h (nh), "default"); fields = fieldnames (def); if (! isempty (fields)) - fieldindex = find (!cellfun (@isempty, regexp(fields, 'color'))); + fieldindex = find (!cellfun ("isempty", regexp(fields, 'color'))); for nf = 1 : numel (fieldindex) defaultfield = fields {fieldindex (nf)}; defaultvalue = 1 - subsref (def, struct ("type", ".", "subs", defaultfield));
--- a/scripts/signal/unwrap.m +++ b/scripts/signal/unwrap.m @@ -75,10 +75,10 @@ idx{dim} = [1,1:m-1]; d = x(idx{:}) - x; - ## Find only the peaks, and multiply them by the range so that there - ## are kronecker deltas at each wrap point multiplied by the range - ## value. - p = rng * (((d > tol) > 0) - ((d < -tol) > 0)); + ## Find only the peaks, and multiply them by the appropriate amount + ## of ranges so that there are kronecker deltas at each wrap point + ## multiplied by the appropriate amount of range values. + p = ceil(abs(d)./rng) .* rng .* (((d > tol) > 0) - ((d < -tol) > 0)); ## Now need to "integrate" this so that the deltas become steps. r = cumsum (p, dim); @@ -128,4 +128,28 @@ %! t(++i) = xassert(any(abs(r - unwrap(w,0.8)) > 100)); %! %! assert(all(t)); - +%! +%!test +%! A = [pi*(-4), pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64]; +%! assert (unwrap(A), unwrap(A, pi)); +%! assert (unwrap(A, pi), unwrap(A, pi, 2)); +%! assert (unwrap(A', pi), unwrap(A', pi, 1)); +%! +%!test +%! A = [pi*(-4); pi*(2+1/3); pi*(16+1)]; +%! B = [pi*(-2+1/6); pi*(4+1/2); pi*(32+3/2)]; +%! C = [pi/4; pi*(8+2/3); pi*64]; +%! D = [pi*(-2+1/6); pi*(2+1/3); pi*(8+2/3)]; +%! E(:, :, 1) = [A, B, C, D]; +%! E(:, :, 2) = [A+B, B+C, C+D, D+A]; +%! F(:, :, 1) = [unwrap(A), unwrap(B), unwrap(C), unwrap(D)]; +%! F(:, :, 2) = [unwrap(A+B), unwrap(B+C), unwrap(C+D), unwrap(D+A)]; +%! assert (unwrap(E), F); +%! +%!test +%! A = [0, 2*pi, 4*pi, 8*pi, 16*pi, 65536*pi]; +%! B = [pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64]; +%! assert (unwrap(A), zeros(1, length(A))); +%! assert (diff(unwrap(B), 1)<2*pi, true(1, length(B)-1)); +%! +%!error unwrap()
--- a/scripts/sparse/svds.m +++ b/scripts/sparse/svds.m @@ -251,8 +251,8 @@ %! s = s(idx); %! u = u(:,idx); %! v = v(:,idx); -%! randn('state',42); % Initialize to make normest function reproducible -%! rand('state',42) +%! randn ('state', 42); % Initialize to make normest function reproducible +%! rand ('state', 42) %! opts.v0 = rand (2*n,1); % Initialize eigs ARPACK starting vector %! % to guarantee reproducible results %!test
--- a/scripts/specfun/lcm.m +++ b/scripts/specfun/lcm.m @@ -34,7 +34,7 @@ if (nargin > 1) if (common_size (varargin{:}) != 0) error ("lcm: all args must be of the same size or scalar"); - elseif (! all (cellfun (@isnumeric, varargin))) + elseif (! all (cellfun ("isnumeric", varargin))) error ("lcm: all arguments must be numeric"); endif
--- a/scripts/statistics/base/mode.m +++ b/scripts/statistics/base/mode.m @@ -112,7 +112,9 @@ %! [m2, f2, c2] = mode (full (a)); %! assert (m, sparse (m2)); %! assert (f, sparse (f2)); -%! assert (c, cellfun (@(x) sparse (0), c2, 'uniformoutput', false)); +%! c_exp(1:length(a)) = { sparse (0) }; +%! assert (c ,c_exp); +%! assert (c2,c_exp ); %!assert(mode ([2,3,1,2,3,4],1),[2,3,1,2,3,4]); %!assert(mode ([2,3,1,2,3,4],2),2);
--- a/scripts/strings/deblank.m +++ b/scripts/strings/deblank.m @@ -18,7 +18,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} deblank (@var{s}) -## Remove trailing blanks and nulls from @var{s}. If @var{s} +## Remove trailing whitespace and nulls from @var{s}. If @var{s} ## is a matrix, @var{deblank} trims each row to the length of longest ## string. If @var{s} is a cell array, operate recursively on each ## element of the cell array. @@ -33,53 +33,33 @@ print_usage (); endif - char_arg = ischar (s); - - if (char_arg || isnumeric (s)) + if (ischar (s)) - if (! isempty (s)) - if (char_arg) - k = find (! isspace (s) & s != "\0"); - else - warning ("deblank: expecting character string argument"); - k = find (s != 0); - endif - - if (isempty (k)) - s = resize (s, 0, 0); - else - s = s(:,1:ceil (max (k) / rows (s))); - endif + k = find (! isspace (s) & s != "\0"); + if (isempty (s) || isempty (k)) + s = ""; + else + s = s(:,1:ceil (max (k) / rows (s))); endif - elseif (iscell(s)) + elseif (iscell (s)) - s = cellfun (@deblank, s, "uniformoutput", false); + s = regexprep (s, "[\\s\v\\0]+$", ''); else - error ("deblank: expecting character string argument"); + error ("deblank: S argument must be a string or cellstring"); endif endfunction -%!assert (strcmp (deblank (" f o o "), " f o o")); -%!assert (deblank ([]), []) -%!assert (deblank ({}), {}) -%!assert (deblank (""), "") - -%!assert (deblank ([0,0,0]), []) +%!assert (strcmp (deblank (" f o o \0"), " f o o")); %!assert (deblank (' '), '') %!assert (deblank (" "), "") - -%!assert (typeinfo (deblank (" ")), "string") -%!assert (typeinfo (deblank (' ')), "sq_string") +%!assert (deblank (""), "") +%!assert (deblank ({}), {}) -%!assert (deblank ([1,2,0]), [1,2]) -%!assert (deblank ([1,2,0,32]), [1,2,0,32]) +%!error <Invalid call to deblank> deblank (); +%!error <Invalid call to deblank> deblank ("foo", "bar"); +%!error <argument must be a string> deblank (1); -%!assert (deblank (int8 ([1,2,0])), int8 ([1,2])) - -%!error deblank (); - -%!error deblank ("foo", "bar");
--- a/scripts/strings/index.m +++ b/scripts/strings/index.m @@ -62,13 +62,13 @@ if (strcmp (direction, "last")) if (iscell (f)) - n = cellfun (@min, f); + n = cellfun ("min", f); else n = f(end); endif elseif (strcmp (direction, "first")) if (iscell (f)) - n = cellfun (@max, f); + n = cellfun ("max", f); else n = f(1); endif
--- a/scripts/strings/strcat.m +++ b/scripts/strings/strcat.m @@ -61,14 +61,14 @@ elseif (nargin > 1) ## Convert to cells of strings uo = "uniformoutput"; - reals = cellfun (@isreal, varargin); + reals = cellfun ("isreal", varargin); if (any (reals)) - varargin(reals) = cellfun (@char, varargin(reals), uo, false); + varargin(reals) = cellfun ("char", varargin(reals), uo, false); endif - chars = cellfun (@ischar, varargin); + chars = cellfun ("isclass", varargin, "char"); allchar = all (chars); - varargin(chars) = cellfun (@cellstr, varargin(chars), uo, false); - if (! all (cellfun (@iscell, varargin))) + varargin(chars) = cellfun ("cellstr", varargin(chars), uo, false); + if (! all (cellfun ("isclass", varargin, "cell"))) error ("strcat: inputs must be strings or cells of strings"); endif @@ -81,7 +81,7 @@ endif ## Cellfun handles everything for us. - st = cellfun (@horzcat, varargin{:}, uo, false); + st = cellfun ("horzcat", varargin{:}, uo, false); if (allchar) ## If all inputs were strings, return strings.
--- a/scripts/strings/strmatch.m +++ b/scripts/strings/strmatch.m @@ -19,13 +19,15 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} strmatch (@var{s}, @var{A}, "exact") -## Return indices of entries of @var{A} that match the string @var{s}. -## The second argument @var{A} may be a string matrix or a cell array of -## strings. If the third argument @code{"exact"} is not given, then +## @deftypefn {Function File} {} strmatch (@var{s}, @var{A}) +## @deftypefnx {Function File} {} strmatch (@var{s}, @var{A}, "exact") +## Return indices of entries of @var{A} which begin with the string @var{s}. +## The second argument @var{A} must be a string, character matrix, or a cell +## array of strings. If the third argument @code{"exact"} is not given, then ## @var{s} only needs to match @var{A} up to the length of @var{s}. -## Trailing whitespace is ignored. -## Results are returned as a column vector. +## Trailing spaces and nulls in @var{s} and @var{A} are ignored when matching. +## option. +## ## For example: ## ## @example @@ -33,13 +35,16 @@ ## strmatch ("apple", "apple juice") ## @result{} 1 ## -## strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]) +## strmatch ("apple", ["apple "; "apple juice"; "an apple"]) ## @result{} [1; 2] ## -## strmatch ("apple", @{"apple pie"; "apple juice"; "tomato"@}) -## @result{} [1; 2] +## strmatch ("apple", ["apple "; "apple juice"; "an apple"], "exact") +## @result{} [1] ## @end group ## @end example +## +## @strong{Note:} @code{strmatch} is scheduled for deprecation. Use +## @code{strcmpi} or @code{strncmpi} in all new code. ## @seealso{strfind, findstr, strcmp, strncmp, strcmpi, strncmpi, find} ## @end deftypefn @@ -52,29 +57,19 @@ print_usage (); endif - if (! ischar (s)) + if (! ischar (s) || (! isempty (s) && ! isvector (s))) error ("strmatch: S must be a string"); + elseif (! (ischar (A) || iscellstr (A))) + error ("strmatch: A must be a string or cell array of strings"); endif - ## Truncate trailing whitespace. - s = strtrimr (s); - + ## Trim blanks and nulls from search string + s = regexprep (s, "[ \\0]+$", ''); len = length (s); exact = nargin == 3 && ischar (exact) && strcmp (exact, "exact"); - if (iscell (A)) - if (len > 0) - idx = find (strncmp (s, A, len)); - else - idx = find (strcmp (s, A)); - endif - if (exact) - ## We can't just use strcmp, because we need to ignore whitespace. - B = cellfun (@strtrimr, A(idx), "uniformoutput", false); - idx = idx (strcmp (s, B)); - endif - elseif (ischar (A)) + if (ischar (A)) [nr, nc] = size (A); if (len > nc) idx = []; @@ -82,34 +77,43 @@ match = all (bsxfun (@eq, A(:,1:len), s), 2); if (exact) AA = A(:,len+1:nc); - match &= all (AA == "\0" | AA == " ", 2); + match &= all (AA == " " | AA == "\0", 2); endif idx = find (match); endif else - error ("strmatch: A must be a string or cell array of strings"); + if (len > 0) + idx = find (strncmp (s, A, len)); + else + idx = find (strcmp (s, A)); + endif + if (exact) + ## We can't just use strcmp, because we need to ignore spaces at end. + B = regexprep (A(idx), "[ \\0]+$", ''); + idx = idx(strcmp (s, B)); + endif endif endfunction -## Removes nuls and blanks from the end of the array -function s = strtrimr (s) - blnks = s == "\0" | s == " "; - i = find (blnks, 1, "last"); - if (i && all (blnks(i:end))) - s = s(1:i-1); - endif -endfunction -%!error <Invalid call to strmatch> strmatch(); -%!error <Invalid call to strmatch> strmatch("a", "aaa", "exact", 1); %!assert (strmatch("a", {"aaa", "bab", "bbb"}), 1); %!assert (strmatch ("apple", "apple juice"), 1); -%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), -%! [1; 2]); -%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), -%! [1; 2]); +%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), [1; 2]); +%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), [1; 2]); %!assert (strmatch ("apple pie", "apple"), []); -%!assert (strmatch ("a b", {"a b", "a c", "c d"})); -%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4]) -%!assert (strmatch ('', { '', '% comment line', 'var a = 5', ''}, 'exact'), [1,4]) +%!assert (strmatch ("a ", "a"), 1); +%!assert (strmatch ("a", "a \0", "exact"), 1); +%!assert (strmatch ("a b", {"a b", "a c", "c d"}), 1); +%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4]); +%!assert (strmatch ('', { '', '% comment', 'var a = 5', ''}, 'exact'), [1,4]); + +%% Test input validation +%!error <Invalid call to strmatch> strmatch(); +%!error <Invalid call to strmatch> strmatch("a"); +%!error <Invalid call to strmatch> strmatch("a", "aaa", "exact", 1); +%!error <S must be a string> strmatch(1, "aaa"); +%!error <S must be a string> strmatch(char ("a", "bb"), "aaa"); +%!error <A must be a string> strmatch("a", 1); +%!error <A must be a string> strmatch("a", {"hello", [1]}); +
--- a/scripts/strings/strsplit.m +++ b/scripts/strings/strsplit.m @@ -28,7 +28,7 @@ function s = strsplit (p, sep, strip_empty = false) if (nargin < 2 || nargin > 3 || ! ischar (p) || rows (p) > 1 - || ! ischar (sep) || ! islogical (strip_empty)) + || ! ischar (sep) || ! isscalar (strip_empty)) print_usage (); endif
--- a/scripts/strings/strtrim.m +++ b/scripts/strings/strtrim.m @@ -53,12 +53,12 @@ s = s(:, ceil (min (k) / rows (s)):ceil (max (k) / rows (s))); endif - elseif (iscell(s)) + elseif (iscell (s)) s = regexprep (s, "^[\\s\v]+|[\\s\v]+$", ''); else - error ("strtrim: S argument must be a string"); + error ("strtrim: S argument must be a string or cellstring"); endif endfunction
--- a/scripts/strings/untabify.m +++ b/scripts/strings/untabify.m @@ -52,64 +52,72 @@ function s = untabify (t, tw = 8, dblank = false) - if (nargin > 0 && nargin < 4 && (ischar (t) || iscellstr (t))) - if (ischar (t)) - s = replace_tabs (t, tw); - else - s = cellfun (@(str) replace_tabs (str, tw), t, "uniformoutput", false); - endif - if (dblank) - s = deblank (s); - endif - else - print_usage (); - endif + if (nargin < 1 || nargin > 3) + print_usage (); + elseif (! (ischar (t) || iscellstr (t))) + error ("untabify: T must be a string or cellstring"); + endif + + if (ischar (t)) + s = replace_tabs (t, tw); + else + s = cellfun (@(str) replace_tabs (str, tw), t, "uniformoutput", false); + endif + + if (dblank) + s = deblank (s); + endif endfunction function s = replace_tabs (t, tw) - if (ndims (t) == 2) - if (isempty (t)) - s = t; - else - nr = rows (t); - sc = cell (nr, 1); - for j = 1:nr - n = 1:numel(t(j,:)); - m = find (t(j,:) == "\t"); - t(j,m) = " "; - for i = 1:numel(m) - k = tw * ceil (n(m(i)) / tw); - dn = k - n(m(i)); - n(m(i):end) += dn; - endfor - sc{j} = blanks (n(end)); - sc{j}(n) = t(j,:); - endfor - s = char (sc); - endif - else - error ("untabify: character strings to untabify must have 2 dimensions"); - endif + + if (ndims (t) != 2) + error ("untabify: character strings to untabify must have 2 dimensions"); + endif + + if (isempty (t)) + s = t; + else + nr = rows (t); + sc = cell (nr, 1); + for j = 1:nr + n = 1:numel(t(j,:)); + m = find (t(j,:) == "\t"); + t(j,m) = " "; + for i = 1:numel(m) + k = tw * ceil (n(m(i)) / tw); + dn = k - n(m(i)); + n(m(i):end) += dn; + endfor + sc{j} = blanks (n(end)); + sc{j}(n) = t(j,:); + endfor + s = char (sc); + endif + endfunction + %!test %! s = untabify ("\thello\t"); -%! assert (isequal (s, horzcat (blanks(8), "hello "))) +%! assert (s, [blanks(8) "hello" blanks(3)]); + +%!test +%! s = untabify ("\thello\t", 2); +%! assert (s, [blanks(2) "hello" blanks(1)]); %!test %! s = untabify ("\thello\t", 4, true); -%! assert (isequal (s, horzcat (blanks(4), "hello"))) +%! assert (s, [blanks(4) "hello"]); -%!test -%! s = untabify ("\thello\t", 2, true); -%! assert (isequal (s, horzcat (blanks(2), "hello"))) +%!assert (isempty (untabify (""))) %!test -%! s = untabify (""); -%! assert (isempty (s)) +%! s = char (randi ([97 97+25], 3, 3)); +%! assert (untabify (s), char (untabify (cellstr (s)))); -%!test -%! s = char (fix (100 + 10*rand (3,3))); -%! assert (isequal (untabify (s), untabify ({s}){1})) +%!error untabify () +%!error untabify (1,2,3,4) +%!error <must be a string> untabify (1)
--- a/scripts/strings/validatestring.m +++ b/scripts/strings/validatestring.m @@ -118,7 +118,7 @@ ## are the matches a substring of each other, if so, choose the ## shortest. If not, raise an error. match_idx = find (matches); - match_l = cellfun (@length, strarray(match_idx)); + match_l = cellfun ("length", strarray(match_idx)); longest_idx = find (match_l == max (match_l), 1); shortest_idx = find (match_l == min (match_l), 1); longest = strarray(match_idx)(longest_idx);
--- a/src/DLD-FUNCTIONS/__init_fltk__.cc +++ b/src/DLD-FUNCTIONS/__init_fltk__.cc @@ -861,8 +861,11 @@ void show_canvas (void) { - canvas->show (); - canvas->make_current (); + if (fp.is_visible ()) + { + canvas->show (); + canvas->make_current (); + } } void hide_canvas (void)
--- a/src/DLD-FUNCTIONS/cellfun.cc +++ b/src/DLD-FUNCTIONS/cellfun.cc @@ -122,8 +122,10 @@ @item ndims\n\ Return the number of dimensions of each element.\n\ \n\ -@item prodofsize\n\ -Return the product of dimensions of each element.\n\ +@item numel\n\ +@itemx prodofsize\n\ +Return the number of elements contained within each cell element. The\n\ +number is the product of the dimensions of the object at each cell element.\n\ \n\ @item size\n\ Return the size along the @var{k}-th dimension.\n\ @@ -142,7 +144,7 @@ \n\ @example\n\ @group\n\ -cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\ +cellfun (\"atan2\", @{1, 0@}, @{0, 1@})\n\ @result{}ans = [1.57080 0.00000]\n\ @end group\n\ @end example\n\ @@ -177,7 +179,7 @@ \n\ @example\n\ @group\n\ -cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\ +cellfun (\"tolower\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\ \"UniformOutput\",false)\n\ @result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\ @end group\n\ @@ -200,7 +202,7 @@ @example\n\ @group\n\ function y = foo (s, x), y = NaN; endfunction\n\ -cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\ +cellfun (\"factorial\", @{-1,2@}, 'ErrorHandler', @@foo)\n\ @result{} ans = [NaN 2]\n\ @end group\n\ @end example\n\
--- a/src/DLD-FUNCTIONS/qr.cc +++ b/src/DLD-FUNCTIONS/qr.cc @@ -76,6 +76,8 @@ "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})\n\ @deftypefnx {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A}, '0')\n\ +@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B})\n\ +@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B}, '0')\n\ @cindex QR factorization\n\ Compute the QR@tie{}factorization of @var{A}, using standard @sc{lapack}\n\ subroutines. For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},\n\ @@ -188,7 +190,7 @@ \n\ @example\n\ @group\n\ -[@var{C},@var{R}] = spqr (@var{A},@var{B})\n\ +[@var{C}, @var{R}] = qr (@var{A}, @var{B})\n\ x = @var{R} \\ @var{C}\n\ @end group\n\ @end example\n\
--- a/src/DLD-FUNCTIONS/rand.cc +++ b/src/DLD-FUNCTIONS/rand.cc @@ -179,18 +179,16 @@ octave_idx_type incr = NINTbig (r.inc ()); octave_idx_type lim = NINTbig (r.limit ()); - if (base < 0 || lim < 0) - error ("%s: all dimensions must be positive", fcn); - else + for (octave_idx_type i = 0; i < n; i++) { - for (octave_idx_type i = 0; i < n; i++) - { - dims(i) = base; - base += incr; - } + //Negative dimensions are treated as zero for Matlab + //compatibility + dims(i) = base >= 0 ? base : 0; + base += incr; + } - goto gen_matrix; - } + goto gen_matrix; + } else error ("%s: all elements of range must be integers", @@ -208,15 +206,10 @@ for (octave_idx_type i = 0; i < len; i++) { + //Negative dimensions are treated as zero for Matlab + //compatibility octave_idx_type elt = iv(i); - - if (elt < 0) - { - error ("%s: all dimensions must be positive", fcn); - goto done; - } - - dims(i) = iv(i); + dims(i) = elt >=0 ? elt : 0; } goto gen_matrix; @@ -278,13 +271,14 @@ for (int i = 0; i < nargin; i++) { - dims(i) = args(idx+i).int_value (); - + octave_idx_type elt = args(idx+i).int_value (); if (error_state) { error ("%s: expecting integer arguments", fcn); goto done; } + //Negative is zero for Matlab compatibility + dims(i) = elt >= 0 ? elt : 0; } goto gen_matrix;
--- a/src/DLD-FUNCTIONS/sqrtm.cc +++ b/src/DLD-FUNCTIONS/sqrtm.cc @@ -259,13 +259,15 @@ ## The following two tests are from the reference in the docstring above. -%!assert (isnan (sqrtm ([0 1; 0 0]))) +%!test +%! x = [0 1; 0 0]; +%! assert (any (isnan (sqrtm (x))(:) )) %!test %! x = eye (4); x(2,2) = x(3,3) = 2^-26; x(1,4) = 1; %! z = eye (4); z(2,2) = z(3,3) = 2^-13; z(1,4) = 0.5; %! [y, err] = sqrtm(x); %! assert (y, z) -%! assert (err, 0)## Yes, this one has to hold exactly +%! assert (err, 0) ## Yes, this one has to hold exactly */
--- a/src/c-file-ptr-stream.cc +++ b/src/c-file-ptr-stream.cc @@ -68,7 +68,7 @@ { if (f) { - int_type c = fgetc (f); + int_type c = gnulib::fgetc (f); if (! bump #if defined (CXX_ISO_COMPLIANT_LIBRARY) @@ -112,7 +112,7 @@ c_file_ptr_buf::xsgetn (char *s, std::streamsize n) { if (f) - return fread (s, 1, n, f); + return gnulib::fread (s, 1, n, f); else return 0; } @@ -173,7 +173,7 @@ int c_file_ptr_buf::flush (void) { - return f ? fflush (f) : EOF; + return f ? gnulib::fflush (f) : EOF; } int @@ -193,6 +193,20 @@ } int +c_file_ptr_buf::seek (long offset, int origin) +{ + // gnulib::fseek doesn't seem to work, so don't use it until problem + // can be properly diagnosed and fixed. + return f ? fseek (f, offset, origin) : -1; +} + +long +c_file_ptr_buf::tell (void) +{ + return f ? gnulib::ftell (f) : -1; +} + +int c_file_ptr_buf::file_close (FILE *f) { return gnulib::fclose (f);
--- a/src/c-file-ptr-stream.h +++ b/src/c-file-ptr-stream.h @@ -74,10 +74,9 @@ int file_number () const { return f ? fileno (f) : -1; } - int seek (long offset, int origin) - { return f ? fseek (f, offset, origin) : -1; } + int seek (long offset, int origin); - long tell (void) { return f ? ftell (f) : -1; } + long tell (void); void clear (void) { if (f) clearerr (f); }
--- a/src/data.cc +++ b/src/data.cc @@ -2060,6 +2060,16 @@ @var{a}(@var{idx1}, @var{idx2}, @dots{})\n\ @end example\n\ \n\ +Note that the indices do not have to be numerical. For example\n\ +\n\ +@example\n\ + @var{a} = 1;\n\ + @var{b} = ones (2, 3);\n\ + numel (@var{a}, @var{b});\n\ +@end example\n\ +\n\ +will return 6, as this is the number of ways to index with @var{b}.\n\ +\n\ This method is also called when an object appears as lvalue with cs-list\n\ indexing, i.e., @code{object@{@dots{}@}} or @code{object(@dots{}).field}.\n\ @seealso{size}\n\ @@ -4187,8 +4197,8 @@ @end example\n\ \n\ Calling @code{eye} with no arguments is equivalent to calling it\n\ -with an argument of 1. This odd definition is for compatibility\n\ -with @sc{matlab}.\n\ +with an argument of 1. Any negative dimensions are treated as zero. \n\ +These odd definitions are for compatibility with @sc{matlab}.\n\ @seealso{speye}\n\ @end deftypefn") {
--- a/src/file-io.cc +++ b/src/file-io.cc @@ -1989,7 +1989,7 @@ OCTAVE_LOCAL_BUFFER (char, tmp, tmpl8.size () + 1); strcpy (tmp, tmpl8.c_str ()); - int fd = mkstemp (tmp); + int fd = gnulib::mkstemp (tmp); if (fd < 0) {
--- a/src/graphics.cc +++ b/src/graphics.cc @@ -4330,15 +4330,22 @@ update_title_position (); } +static bool updating_xlabel_position = false; + void axes::properties::update_xlabel_position (void) { + if (updating_xlabel_position) + return; + text::properties& xlabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_xlabel ()).get_properties ()); bool is_empty = xlabel_props.get_string ().empty (); - xlabel_props.set_autopos_tag ("none"); + unwind_protect frame; + frame.protect_var (updating_xlabel_position); + updating_xlabel_position = true; if (! is_empty) { @@ -4412,19 +4419,24 @@ xlabel_props.set_rotationmode ("auto"); } } - - xlabel_props.set_autopos_tag ("xlabel"); -} +} + +static bool updating_ylabel_position = false; void axes::properties::update_ylabel_position (void) { + if (updating_ylabel_position) + return; + text::properties& ylabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_ylabel ()).get_properties ()); bool is_empty = ylabel_props.get_string ().empty (); - ylabel_props.set_autopos_tag ("none"); + unwind_protect frame; + frame.protect_var (updating_ylabel_position); + updating_ylabel_position = true; if (! is_empty) { @@ -4498,20 +4510,25 @@ ylabel_props.set_rotationmode ("auto"); } } - - ylabel_props.set_autopos_tag ("ylabel"); -} +} + +static bool updating_zlabel_position = false; void axes::properties::update_zlabel_position (void) { + if (updating_zlabel_position) + return; + text::properties& zlabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_zlabel ()).get_properties ()); bool camAuto = cameraupvectormode_is ("auto"); bool is_empty = zlabel_props.get_string ().empty (); - zlabel_props.set_autopos_tag ("none"); + unwind_protect frame; + frame.protect_var (updating_zlabel_position); + updating_zlabel_position = true; if (! is_empty) { @@ -4606,17 +4623,22 @@ zlabel_props.set_rotationmode ("auto"); } } - - zlabel_props.set_autopos_tag ("zlabel"); -} +} + +static bool updating_title_position = false; void axes::properties::update_title_position (void) { + if (updating_title_position) + return; + text::properties& title_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_title ()).get_properties ()); - title_props.set_autopos_tag ("none"); + unwind_protect frame; + frame.protect_var (updating_title_position); + updating_title_position = true; if (title_props.positionmode_is ("auto")) { @@ -4630,8 +4652,6 @@ title_props.set_position (p.extract_n(0, 3).transpose ()); title_props.set_positionmode ("auto"); } - - title_props.set_autopos_tag ("title"); } void
--- a/src/help.cc +++ b/src/help.cc @@ -749,6 +749,9 @@ const string_vector bif = symbol_table::built_in_function_names (); const int bif_len = bif.length (); + const string_vector cfl = symbol_table::cmdline_function_names (); + const int cfl_len = cfl.length (); + const string_vector lcl = symbol_table::variable_names (); const int lcl_len = lcl.length (); @@ -758,7 +761,8 @@ const string_vector afl = autoloaded_functions (); const int afl_len = afl.length (); - const int total_len = key_len + bif_len + lcl_len + ffl_len + afl_len; + const int total_len + = key_len + bif_len + cfl_len + lcl_len + ffl_len + afl_len; string_vector list (total_len); @@ -772,6 +776,9 @@ for (i = 0; i < bif_len; i++) list[j++] = bif[i]; + for (i = 0; i < cfl_len; i++) + list[j++] = cfl[i]; + for (i = 0; i < lcl_len; i++) list[j++] = lcl[i];
--- a/src/input.cc +++ b/src/input.cc @@ -213,7 +213,7 @@ FILE *stream = command_editor::get_output_stream (); gnulib::fputs (s.c_str (), stream); - fflush (stream); + gnulib::fflush (stream); } FILE *curr_stream = command_editor::get_input_stream (); @@ -686,93 +686,88 @@ frame.protect_var (VPS1); VPS1 = prompt; - if (stdin_is_tty) + if (! (interactive || forced_interactive) + || (reading_fcn_file + || reading_classdef_file + || reading_script_file + || get_input_from_eval_string + || input_from_startup_file + || input_from_command_line_file)) { - if (! (interactive || forced_interactive) - || (reading_fcn_file - || reading_classdef_file - || reading_script_file - || get_input_from_eval_string - || input_from_startup_file - || input_from_command_line_file)) - { - frame.protect_var (forced_interactive); - forced_interactive = true; + frame.protect_var (forced_interactive); + forced_interactive = true; + + frame.protect_var (reading_fcn_file); + reading_fcn_file = false; + + frame.protect_var (reading_classdef_file); + reading_classdef_file = false; + + frame.protect_var (reading_script_file); + reading_script_file = false; - frame.protect_var (reading_fcn_file); - reading_fcn_file = false; + frame.protect_var (input_from_startup_file); + input_from_startup_file = false; + + frame.protect_var (input_from_command_line_file); + input_from_command_line_file = false; - frame.protect_var (reading_classdef_file); - reading_classdef_file = false; + frame.protect_var (get_input_from_eval_string); + get_input_from_eval_string = false; + + YY_BUFFER_STATE old_buf = current_buffer (); + YY_BUFFER_STATE new_buf = create_buffer (get_input_from_stdin ()); + + // FIXME: are these safe? + frame.add_fcn (switch_to_buffer, old_buf); + frame.add_fcn (delete_buffer, new_buf); - frame.protect_var (reading_script_file); - reading_script_file = false; + switch_to_buffer (new_buf); + } + + while (Vdebugging) + { + reset_error_handler (); + + reset_parser (); - frame.protect_var (input_from_startup_file); - input_from_startup_file = false; + // Save current value of global_command. + frame.protect_var (global_command); + + global_command = 0; - frame.protect_var (input_from_command_line_file); - input_from_command_line_file = false; + // Do this with an unwind-protect cleanup function so that the + // forced variables will be unmarked in the event of an interrupt. + symbol_table::scope_id scope = symbol_table::top_scope (); + frame.add_fcn (symbol_table::unmark_forced_variables, scope); - frame.protect_var (get_input_from_eval_string); - get_input_from_eval_string = false; + // This is the same as yyparse in parse.y. + int retval = octave_parse (); - YY_BUFFER_STATE old_buf = current_buffer (); - YY_BUFFER_STATE new_buf = create_buffer (get_input_from_stdin ()); + if (retval == 0 && global_command) + { + global_command->accept (*current_evaluator); - // FIXME: are these safe? - frame.add_fcn (switch_to_buffer, old_buf); - frame.add_fcn (delete_buffer, new_buf); + // FIXME -- To avoid a memory leak, global_command should be + // deleted, I think. But doing that here causes trouble if + // an error occurs while executing a debugging command + // (dbstep, for example). It's not clear to me why that + // happens. + // + // delete global_command; + // + // global_command = 0; - switch_to_buffer (new_buf); + if (octave_completion_matches_called) + octave_completion_matches_called = false; } - while (Vdebugging) - { - reset_error_handler (); - - reset_parser (); - - // Save current value of global_command. - frame.protect_var (global_command); - - global_command = 0; - - // Do this with an unwind-protect cleanup function so that the - // forced variables will be unmarked in the event of an interrupt. - symbol_table::scope_id scope = symbol_table::top_scope (); - frame.add_fcn (symbol_table::unmark_forced_variables, scope); - - // This is the same as yyparse in parse.y. - int retval = octave_parse (); - - if (retval == 0 && global_command) - { - global_command->accept (*current_evaluator); + // Unmark forced variables. + // Restore previous value of global_command. + frame.run_top (2); - // FIXME -- To avoid a memory leak, global_command should be - // deleted, I think. But doing that here causes trouble if - // an error occurs while executing a debugging command - // (dbstep, for example). It's not clear to me why that - // happens. - // - // delete global_command; - // - // global_command = 0; - - if (octave_completion_matches_called) - octave_completion_matches_called = false; - } - - // Unmark forced variables. - // Restore previous value of global_command. - frame.run_top (2); - - octave_quit (); - } + octave_quit (); } - else - warning ("invalid attempt to debug script read from stdin"); } // If the user simply hits return, this will produce an empty matrix.
--- a/src/oct-parse.yy +++ b/src/oct-parse.yy @@ -3280,13 +3280,13 @@ static int text_getc (FILE *f) { - int c = getc (f); + int c = gnulib::getc (f); // Convert CRLF into just LF and single CR into LF. if (c == '\r') { - c = getc (f); + c = gnulib::getc (f); if (c != '\n') { @@ -3360,16 +3360,16 @@ { bool status = false; - long pos = ftell (ffile); + long pos = gnulib::ftell (ffile); char buf [10]; - fgets (buf, 10, ffile); + gnulib::fgets (buf, 10, ffile); size_t len = strlen (buf); if (len > 8 && strncmp (buf, "classdef", 8) == 0 && ! (isalnum (buf[8]) || buf[8] == '_')) status = true; - fseek (ffile, pos, SEEK_SET); + gnulib::fseek (ffile, pos, SEEK_SET); return status; } @@ -3420,16 +3420,16 @@ { bool status = false; - long pos = ftell (ffile); + long pos = gnulib::ftell (ffile); char buf [10]; - fgets (buf, 10, ffile); + gnulib::fgets (buf, 10, ffile); size_t len = strlen (buf); if (len > 8 && strncmp (buf, "function", 8) == 0 && ! (isalnum (buf[8]) || buf[8] == '_')) status = true; - fseek (ffile, pos, SEEK_SET); + gnulib::fseek (ffile, pos, SEEK_SET); return status; }
--- a/src/oct-stream.cc +++ b/src/oct-stream.cc @@ -1227,151 +1227,9 @@ if (c1 != EOF) { - if (c1 == 'N') - { - int c2 = is.get (); - - if (c2 != EOF) - { - if (c2 == 'A') - { - int c3 = is.get (); - - if (c3 != EOF) - { - is.putback (c3); - - if (isspace (c3) || ispunct (c3)) - ref = octave_NA; - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_NA; - } - } - else if (c2 == 'a') - { - int c3 = is.get (); - - if (c3 != EOF) - { - if (c3 == 'N') - { - int c4 = is.get (); - - if (c4 != EOF) - { - is.putback (c4); - - if (isspace (c4) || ispunct (c4)) - ref = octave_NaN; - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_NaN; - } - } - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - else if (c1 == 'I') - { - int c2 = is.get (); - - if (c2 != EOF) - { - if (c2 == 'n') - { - int c3 = is.get (); - - if (c3 != EOF) - { - if (c3 == 'f') - { - int c4 = is.get (); - - if (c4 != EOF) - { - is.putback (c4); - - if (isspace (c4) || ispunct (c4)) - ref = octave_Inf; - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_Inf; - } - } - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - } - else - { - is.putback (c1); - - is >> ref; - } + is.putback (c1); + + ref = octave_read_value<double> (is); } } break;
--- a/src/ov-builtin.cc +++ b/src/ov-builtin.cc @@ -126,7 +126,7 @@ try { - profile_data_accumulator::enter pe (profiler, *this); + profile_data_accumulator::enter pe (profiler, profiler_name ()); retval = (*f) (args, nargout); // Do not allow null values to be returned from functions.
--- a/src/ov-mex-fcn.cc +++ b/src/ov-mex-fcn.cc @@ -148,7 +148,7 @@ try { - profile_data_accumulator::enter pe (profiler, *this); + profile_data_accumulator::enter pe (profiler, profiler_name ()); retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this); } catch (octave_execution_exception)
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -135,7 +135,8 @@ tree_evaluator::statement_context = tree_evaluator::script; { - profile_data_accumulator::enter pe (profiler, *this); + profile_data_accumulator::enter pe (profiler, + profiler_name ()); cmd_list->accept (*current_evaluator); } @@ -455,7 +456,7 @@ || cmd_list->is_anon_function_body ()); { - profile_data_accumulator::enter pe (profiler, *this); + profile_data_accumulator::enter pe (profiler, profiler_name ()); if (special_expr) {
--- a/src/profiler.cc +++ b/src/profiler.cc @@ -28,28 +28,27 @@ #include "defun.h" #include "oct-time.h" -#include "ov-fcn.h" #include "ov-struct.h" #include "pager.h" #include "profiler.h" profile_data_accumulator::enter::enter (profile_data_accumulator& a, - const octave_function& f) + const std::string& f) : acc (a) { if (acc.is_active ()) { - fcn = &f; - acc.enter_function (*fcn); + fcn = f; + acc.enter_function (fcn); } else - fcn = NULL; + fcn = ""; } profile_data_accumulator::enter::~enter () { - if (fcn) - acc.exit_function (*fcn); + if (fcn != "") + acc.exit_function (fcn); } profile_data_accumulator::stats::stats () @@ -98,7 +97,7 @@ } void -profile_data_accumulator::enter_function (const octave_function& fcn) +profile_data_accumulator::enter_function (const std::string& fcn) { // The enter class will check and only call us if the profiler is active. assert (is_active ()); @@ -109,33 +108,32 @@ add_current_time (); // Update non-timing related data for the function entered. - const std::string name = fcn.profiler_name (); - stats& entry = data[name]; + stats& entry = data[fcn]; ++entry.calls; if (!call_stack.empty ()) { - const std::string parent_name = call_stack.back ()->profiler_name (); + const std::string parent_name = call_stack.back (); entry.parents.insert (parent_name); - data[parent_name].children.insert (name); + data[parent_name].children.insert (fcn); } if (!entry.recursive) for (call_stack_type::iterator i = call_stack.begin (); i != call_stack.end (); ++i) - if (*i == &fcn) + if (*i == fcn) { entry.recursive = true; break; } - call_stack.push_back (&fcn); + call_stack.push_back (fcn); last_time = query_time (); } void -profile_data_accumulator::exit_function (const octave_function& fcn) +profile_data_accumulator::exit_function (const std::string& fcn) { assert (!call_stack.empty ()); - assert (&fcn == call_stack.back ()); + assert (fcn == call_stack.back ()); // Usually, if we are disabled this function is not even called. But the // call disabling the profiler is an exception. So also check here @@ -229,7 +227,7 @@ assert (last_time >= 0.0 && last_time <= t); assert (!call_stack.empty ()); - const std::string name = call_stack.back ()->profiler_name (); + const std::string name = call_stack.back (); // The entry for this function should already be created; namely // when entering the function via the non-timing data collection!
--- a/src/profiler.h +++ b/src/profiler.h @@ -25,9 +25,9 @@ #include <map> #include <set> +#include <string> #include <vector> -class octave_function; class octave_value; class @@ -44,11 +44,11 @@ profile_data_accumulator& acc; - const octave_function* fcn; + std::string fcn; public: - enter (profile_data_accumulator&, const octave_function& fcn); + enter (profile_data_accumulator&, const std::string&); virtual ~enter (void); @@ -101,7 +101,7 @@ bool enabled; - typedef std::vector<const octave_function*> call_stack_type; + typedef std::vector<std::string> call_stack_type; call_stack_type call_stack; typedef std::map<std::string, stats> stats_map; @@ -112,8 +112,8 @@ // These are private as only the unwind-protecting inner class enter // should be allowed to call them. - void enter_function (const octave_function&); - void exit_function (const octave_function&); + void enter_function (const std::string&); + void exit_function (const std::string&); // Query a timestamp, used for timing calls (obviously). // This is not static because in the future, maybe we want a flag
--- a/src/pt-binop.cc +++ b/src/pt-binop.cc @@ -28,6 +28,7 @@ #include "defun.h" #include "oct-obj.h" #include "ov.h" +#include "profiler.h" #include "pt-binop.h" #include "pt-bp.h" #include "pt-walk.h" @@ -120,6 +121,15 @@ if (! error_state && b.is_defined ()) { + profile_data_accumulator::enter pe (profiler, + "binary " + oper ()); + + // Note: The profiler does not catch the braindead + // short-circuit evaluation code above, but that should be + // ok. The evaluation of operands and the operator itself + // is entangled and it's not clear where to start/stop + // timing the operator to make it reasonable. + retval = ::do_binary_op (etype, a, b); if (error_state) @@ -183,6 +193,11 @@ bool result = false; + // This evaluation is not caught by the profiler, since we can't find + // a reasonable place where to time. Note that we don't want to + // include evaluation of LHS or RHS into the timing, but this is + // entangled together with short-circuit evaluation here. + if (op_lhs) { octave_value a = op_lhs->rvalue1 ();
--- a/src/pt-unop.cc +++ b/src/pt-unop.cc @@ -28,6 +28,7 @@ #include "oct-obj.h" #include "oct-lvalue.h" #include "ov.h" +#include "profiler.h" #include "pt-bp.h" #include "pt-unop.h" #include "pt-walk.h" @@ -72,6 +73,9 @@ if (! error_state) { + profile_data_accumulator::enter pe (profiler, + "prefix " + oper ()); + ref.do_unary_op (etype); if (! error_state) @@ -84,6 +88,9 @@ if (! error_state && val.is_defined ()) { + profile_data_accumulator::enter pe (profiler, + "prefix " + oper ()); + // Attempt to do the operation in-place if it is unshared // (a temporary expression). if (val.get_count () == 1) @@ -153,6 +160,9 @@ { retval = ref.value (); + profile_data_accumulator::enter pe (profiler, + "postfix " + oper ()); + ref.do_unary_op (etype); } } @@ -162,6 +172,9 @@ if (! error_state && val.is_defined ()) { + profile_data_accumulator::enter pe (profiler, + "postfix " + oper ()); + retval = ::do_unary_op (etype, val); if (error_state)
--- a/src/symtab.h +++ b/src/symtab.h @@ -790,6 +790,11 @@ return rep->built_in_function; } + octave_value find_cmdline_function (void) const + { + return rep->cmdline_function; + } + octave_value find_autoload (void) { return rep->find_autoload (); @@ -1787,6 +1792,25 @@ return retval; } + static std::list<std::string> cmdline_function_names (void) + { + std::list<std::string> retval; + + for (fcn_table_const_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + octave_value fcn = p->second.find_cmdline_function (); + + if (fcn.is_defined ()) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); + + return retval; + } + static bool is_local_variable (const std::string& name) { if (xcurrent_scope == xglobal_scope)