strfns.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1994-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cctype>
00028 
00029 #include <queue>
00030 #include <sstream>
00031 
00032 #include "dMatrix.h"
00033 
00034 #include "Cell.h"
00035 #include "defun.h"
00036 #include "error.h"
00037 #include "gripes.h"
00038 #include "ov.h"
00039 #include "oct-obj.h"
00040 #include "unwind-prot.h"
00041 #include "utils.h"
00042 
00043 DEFUN (char, args, ,
00044   "-*- texinfo -*-\n\
00045 @deftypefn  {Built-in Function} {} char (@var{x})\n\
00046 @deftypefnx {Built-in Function} {} char (@var{x}, @dots{})\n\
00047 @deftypefnx {Built-in Function} {} char (@var{s1}, @var{s2}, @dots{})\n\
00048 @deftypefnx {Built-in Function} {} char (@var{cell_array})\n\
00049 Create a string array from one or more numeric matrices, character\n\
00050 matrices, or cell arrays.  Arguments are concatenated vertically.\n\
00051 The returned values are padded with blanks as needed to make each row\n\
00052 of the string array have the same length.  Empty input strings are\n\
00053 significant and will concatenated in the output.\n\
00054 \n\
00055 For numerical input, each element is converted\n\
00056 to the corresponding ASCII character.  A range error results if an input\n\
00057 is outside the ASCII range (0-255).\n\
00058 \n\
00059 For cell arrays, each element is concatenated separately.  Cell arrays\n\
00060 converted through\n\
00061 @code{char} can mostly be converted back with @code{cellstr}.\n\
00062 For example:\n\
00063 \n\
00064 @example\n\
00065 @group\n\
00066 char ([97, 98, 99], \"\", @{\"98\", \"99\", 100@}, \"str1\", [\"ha\", \"lf\"])\n\
00067      @result{} [\"abc    \"\n\
00068          \"       \"\n\
00069          \"98     \"\n\
00070          \"99     \"\n\
00071          \"d      \"\n\
00072          \"str1   \"\n\
00073          \"half   \"]\n\
00074 @end group\n\
00075 @end example\n\
00076 @seealso{strvcat, cellstr}\n\
00077 @end deftypefn")
00078 {
00079   octave_value retval;
00080 
00081   int nargin = args.length ();
00082 
00083   if (nargin == 0)
00084     retval = "";
00085   else if (nargin == 1)
00086     retval = args(0).convert_to_str (true, true,
00087                                      args(0).is_dq_string () ? '"' : '\'');
00088   else
00089     {
00090       int n_elts = 0;
00091 
00092       int max_len = 0;
00093 
00094       std::queue<string_vector> args_as_strings;
00095 
00096       for (int i = 0; i < nargin; i++)
00097         {
00098           string_vector s = args(i).all_strings ();
00099 
00100           if (error_state)
00101             {
00102               error ("char: unable to convert some args to strings");
00103               return retval;
00104             }
00105 
00106           if (s.length () > 0)
00107             n_elts += s.length ();
00108           else
00109             n_elts += 1;
00110 
00111           int s_max_len = s.max_length ();
00112 
00113           if (s_max_len > max_len)
00114             max_len = s_max_len;
00115 
00116           args_as_strings.push (s);
00117         }
00118 
00119       string_vector result (n_elts);
00120 
00121       int k = 0;
00122 
00123       for (int i = 0; i < nargin; i++)
00124         {
00125           string_vector s = args_as_strings.front ();
00126           args_as_strings.pop ();
00127 
00128           int n = s.length ();
00129 
00130           if (n > 0)
00131             {
00132               for (int j = 0; j < n; j++)
00133                 {
00134                   std::string t = s[j];
00135                   int t_len = t.length ();
00136 
00137                   if (max_len > t_len)
00138                     t += std::string (max_len - t_len, ' ');
00139 
00140                   result[k++] = t;
00141                 }
00142             }
00143           else
00144             result[k++] = std::string (max_len, ' ');
00145         }
00146 
00147       retval = octave_value (result, '\'');
00148     }
00149 
00150   return retval;
00151 }
00152 
00153 /*
00154 %!assert (char (), '');
00155 %!assert (char (100) == "d");
00156 %!assert (all(char (100,100) == ["d";"d"]));
00157 %!assert (all(char ({100,100}) == ["d";"d"]));
00158 %!assert (all(char ([100,100]) == ["dd"]));
00159 %!assert (all(char ({100,{100}}) == ["d";"d"]));
00160 %!assert (all(char (100, [], 100) == ["d";" ";"d"]))
00161 %!assert (all(char ({100, [], 100}) == ["d";" ";"d"]))
00162 %!assert (all(char ({100,{100, {""}}}) == ["d";"d";" "]))
00163 %!assert (all(char (["a";"be"], {"c", 100}) == ["a";"be";"c";"d"]))
00164 %!assert(strcmp (char ("a", "bb", "ccc"), ["a  "; "bb "; "ccc"]));
00165 %!assert(strcmp (char ([65, 83, 67, 73, 73]), "ASCII"));
00166 
00167 %!test
00168 %! x = char ("foo", "bar", "foobar");
00169 %! assert((strcmp (x(1,:), "foo   ")
00170 %! && strcmp (x(2,:), "bar   ")
00171 %! && strcmp (x(3,:), "foobar")));
00172 */
00173 
00174 DEFUN (strvcat, args, ,
00175   "-*- texinfo -*-\n\
00176 @deftypefn  {Built-in Function} {} strvcat (@var{x})\n\
00177 @deftypefnx {Built-in Function} {} strvcat (@var{x}, @dots{})\n\
00178 @deftypefnx {Built-in Function} {} strvcat (@var{s1}, @var{s2}, @dots{})\n\
00179 @deftypefnx {Built-in Function} {} strvcat (@var{cell_array})\n\
00180 Create a character array from one or more numeric matrices, character\n\
00181 matrices, or cell arrays.  Arguments are concatenated vertically.\n\
00182 The returned values are padded with blanks as needed to make each row\n\
00183 of the string array have the same length.  Unlike @code{char}, empty\n\
00184 strings are removed and will not appear in the output.\n\
00185 \n\
00186 For numerical input, each element is converted\n\
00187 to the corresponding ASCII character.  A range error results if an input\n\
00188 is outside the ASCII range (0-255).\n\
00189 \n\
00190 For cell arrays, each element is concatenated separately.  Cell arrays\n\
00191 converted through\n\
00192 @code{strvcat} can mostly be converted back with @code{cellstr}.\n\
00193 For example:\n\
00194 \n\
00195 @example\n\
00196 @group\n\
00197 strvcat ([97, 98, 99], \"\", @{\"98\", \"99\", 100@}, \"str1\", [\"ha\", \"lf\"])\n\
00198      @result{} [\"abc    \"\n\
00199          \"98     \"\n\
00200          \"99     \"\n\
00201          \"d      \"\n\
00202          \"str1   \"\n\
00203          \"half   \"]\n\
00204 @end group\n\
00205 @end example\n\
00206 @seealso{char, strcat, cstrcat}\n\
00207 @end deftypefn")
00208 {
00209   octave_value retval;
00210 
00211   int nargin = args.length ();
00212 
00213   if (nargin > 0)
00214     {
00215       int n_elts = 0;
00216 
00217       size_t max_len = 0;
00218 
00219       std::queue<string_vector> args_as_strings;
00220 
00221       for (int i = 0; i < nargin; i++)
00222         {
00223           string_vector s = args(i).all_strings ();
00224 
00225           if (error_state)
00226             {
00227               error ("strvcat: unable to convert some args to strings");
00228               return retval;
00229             }
00230 
00231           size_t n = s.length ();
00232 
00233           // do not count empty strings in calculation of number of elements
00234           if (n > 0)
00235             {
00236               for (size_t j = 0; j < n; j++)
00237                 {
00238                   if (s[j].length () > 0)
00239                     n_elts++;
00240                 }
00241             }
00242 
00243           size_t s_max_len = s.max_length ();
00244 
00245           if (s_max_len > max_len)
00246             max_len = s_max_len;
00247 
00248           args_as_strings.push (s);
00249         }
00250 
00251       string_vector result (n_elts);
00252 
00253       octave_idx_type k = 0;
00254 
00255       for (int i = 0; i < nargin; i++)
00256         {
00257           string_vector s = args_as_strings.front ();
00258           args_as_strings.pop ();
00259 
00260           size_t n = s.length ();
00261 
00262           if (n > 0)
00263             {
00264               for (size_t j = 0; j < n; j++)
00265                 {
00266                   std::string t = s[j];
00267                   if (t.length () > 0)
00268                     {
00269                       size_t t_len = t.length ();
00270 
00271                       if (max_len > t_len)
00272                         t += std::string (max_len - t_len, ' ');
00273 
00274                       result[k++] = t;
00275                     }
00276                 }
00277             }
00278         }
00279 
00280       retval = octave_value (result, '\'');
00281     }
00282   else
00283     print_usage ();
00284 
00285   return retval;
00286 }
00287 
00288 /*
00289 %!error <Invalid call to strvcat> strvcat()
00290 %!assert (strvcat (""), "");
00291 %!assert (strvcat (100) == "d");
00292 %!assert (all(strvcat (100,100) == ["d";"d"]));
00293 %!assert (all(strvcat ({100,100}) == ["d";"d"]));
00294 %!assert (all(strvcat ([100,100]) == ["dd"]));
00295 %!assert (all(strvcat ({100,{100}}) == ["d";"d"]));
00296 %!assert (all(strvcat (100, [], 100) == ["d";"d"]))
00297 %!assert (all(strvcat ({100, [], 100}) == ["d";"d"]))
00298 %!assert (all(strvcat ({100,{100, {""}}}) == ["d";"d"]))
00299 %!assert (all(strvcat (["a";"be"], {"c", 100}) == ["a";"be";"c";"d"]))
00300 %!assert(strcmp (strvcat ("a", "bb", "ccc"), ["a  "; "bb "; "ccc"]));
00301 */
00302 
00303 
00304 DEFUN (ischar, args, ,
00305   "-*- texinfo -*-\n\
00306 @deftypefn {Built-in Function} {} ischar (@var{x})\n\
00307 Return true if @var{x} is a character array.\n\
00308 @seealso{isfloat, isinteger, islogical, isnumeric, iscellstr, isa}\n\
00309 @end deftypefn")
00310 {
00311   octave_value retval;
00312 
00313   int nargin = args.length ();
00314 
00315   if (nargin == 1 && args(0).is_defined ())
00316     retval = args(0).is_string ();
00317   else
00318     print_usage ();
00319 
00320   return retval;
00321 }
00322 
00323 /*
00324 %!assert (ischar ("a"), logical (1));
00325 %!assert (ischar (["ab";"cd"]), logical (1));
00326 %!assert (ischar ({"ab"}), logical (0));
00327 %!assert (ischar (1), logical (0));
00328 %!assert(ischar ([1, 2]), logical (0));
00329 %!assert(ischar ([]), logical (0));
00330 %!assert(ischar ([1, 2; 3, 4]), logical (0));
00331 %!assert(ischar (""), logical (1));
00332 %!assert(ischar ("test"), logical (1));
00333 %!assert(ischar (["test"; "ing"]), logical (1));
00334 %!assert(ischar (struct ("foo", "bar")), logical (0));
00335 %!error <Invalid call to ischar> ischar ();
00336 %!error <Invalid call to ischar> ischar ("test", 1);
00337 */
00338 
00339 static octave_value
00340 do_strcmp_fun (const octave_value& arg0, const octave_value& arg1,
00341                octave_idx_type n, const char *fcn_name,
00342                bool (*array_op) (const charNDArray&, const charNDArray&, octave_idx_type),
00343                bool (*str_op) (const std::string&, const std::string&, octave_idx_type))
00344 
00345 {
00346   octave_value retval;
00347 
00348   bool s1_string = arg0.is_string ();
00349   bool s1_cell = arg0.is_cell ();
00350   bool s2_string = arg1.is_string ();
00351   bool s2_cell = arg1.is_cell ();
00352 
00353   if (s1_string && s2_string)
00354     retval = array_op (arg0.char_array_value (), arg1.char_array_value (), n);
00355   else if ((s1_string && s2_cell) || (s1_cell && s2_string))
00356     {
00357       octave_value str_val, cell_val;
00358 
00359       if (s1_string)
00360         {
00361           str_val = arg0;
00362           cell_val = arg1;
00363         }
00364       else
00365         {
00366           str_val = arg1;
00367           cell_val = arg0;
00368         }
00369 
00370       const Cell cell = cell_val.cell_value ();
00371       const string_vector str = str_val.all_strings ();
00372       octave_idx_type r = str.length ();
00373 
00374       if (r == 0 || r == 1)
00375         {
00376           // Broadcast the string.
00377 
00378           boolNDArray output (cell_val.dims (), false);
00379 
00380           std::string s = r == 0 ? std::string () : str[0];
00381 
00382           if (cell_val.is_cellstr ())
00383             {
00384               const Array<std::string> cellstr = cell_val.cellstr_value ();
00385               for (octave_idx_type i = 0; i < cellstr.length (); i++)
00386                 output(i) = str_op (cellstr(i), s, n);
00387             }
00388           else
00389             {
00390               // FIXME: should we warn here?
00391               for (octave_idx_type i = 0; i < cell.length (); i++)
00392                 {
00393                   if (cell(i).is_string ())
00394                     output(i) = str_op (cell(i).string_value (), s, n);
00395                 }
00396             }
00397 
00398           retval = output;
00399         }
00400       else if (r > 1)
00401         {
00402           if (cell.length () == 1)
00403             {
00404               // Broadcast the cell.
00405 
00406               const dim_vector dv (r, 1);
00407               boolNDArray output (dv, false);
00408 
00409               if (cell(0).is_string ())
00410                 {
00411                   const std::string str2 = cell(0).string_value ();
00412 
00413                   for (octave_idx_type i = 0; i < r; i++)
00414                     output(i) = str_op (str[i], str2, n);
00415                 }
00416 
00417               retval = output;
00418             }
00419           else
00420             {
00421               // Must match in all dimensions.
00422 
00423               boolNDArray output (cell.dims (), false);
00424 
00425               if (cell.length () == r)
00426                 {
00427                   if (cell_val.is_cellstr ())
00428                     {
00429                       const Array<std::string> cellstr = cell_val.cellstr_value ();
00430                       for (octave_idx_type i = 0; i < cellstr.length (); i++)
00431                         output(i) = str_op (str[i], cellstr(i), n);
00432                     }
00433                   else
00434                     {
00435                       // FIXME: should we warn here?
00436                       for (octave_idx_type i = 0; i < r; i++)
00437                         {
00438                           if (cell(i).is_string ())
00439                             output(i) = str_op (str[i], cell(i).string_value (), n);
00440                         }
00441                     }
00442 
00443                   retval = output;
00444                 }
00445               else
00446                 retval = false;
00447             }
00448         }
00449     }
00450   else if (s1_cell && s2_cell)
00451     {
00452       octave_value cell1_val, cell2_val;
00453       octave_idx_type r1 = arg0.numel (), r2;
00454 
00455       if (r1 == 1)
00456         {
00457           // Make the singleton cell2.
00458 
00459           cell1_val = arg1;
00460           cell2_val = arg0;
00461         }
00462       else
00463         {
00464           cell1_val = arg0;
00465           cell2_val = arg1;
00466         }
00467 
00468       const Cell cell1 = cell1_val.cell_value ();
00469       const Cell cell2 = cell2_val.cell_value ();
00470       r1 = cell1.numel ();
00471       r2 = cell2.numel ();
00472 
00473       const dim_vector size1 = cell1.dims ();
00474       const dim_vector size2 = cell2.dims ();
00475 
00476       boolNDArray output (size1, false);
00477 
00478       if (r2 == 1)
00479         {
00480           // Broadcast cell2.
00481 
00482           if (cell2(0).is_string ())
00483             {
00484               const std::string str2 = cell2(0).string_value ();
00485 
00486               if (cell1_val.is_cellstr ())
00487                 {
00488                   const Array<std::string> cellstr = cell1_val.cellstr_value ();
00489                   for (octave_idx_type i = 0; i < cellstr.length (); i++)
00490                     output(i) = str_op (cellstr(i), str2, n);
00491                 }
00492               else
00493                 {
00494                   // FIXME: should we warn here?
00495                   for (octave_idx_type i = 0; i < r1; i++)
00496                     {
00497                       if (cell1(i).is_string ())
00498                         {
00499                           const std::string str1 = cell1(i).string_value ();
00500                           output(i) = str_op (str1, str2, n);
00501                         }
00502                     }
00503                 }
00504             }
00505         }
00506       else
00507         {
00508           if (size1 != size2)
00509             {
00510               error ("%s: nonconformant cell arrays", fcn_name);
00511               return retval;
00512             }
00513 
00514           if (cell1.is_cellstr () && cell2.is_cellstr ())
00515             {
00516               const Array<std::string> cellstr1 = cell1_val.cellstr_value ();
00517               const Array<std::string> cellstr2 = cell2_val.cellstr_value ();
00518               for (octave_idx_type i = 0; i < r1; i++)
00519                 output (i) = str_op (cellstr1(i), cellstr2(i), n);
00520             }
00521           else
00522             {
00523               // FIXME: should we warn here?
00524               for (octave_idx_type i = 0; i < r1; i++)
00525                 {
00526                   if (cell1(i).is_string () && cell2(i).is_string ())
00527                     {
00528                       const std::string str1 = cell1(i).string_value ();
00529                       const std::string str2 = cell2(i).string_value ();
00530                       output(i) = str_op (str1, str2, n);
00531                     }
00532                 }
00533             }
00534         }
00535 
00536       retval = output;
00537     }
00538   else
00539     retval = false;
00540 
00541   return retval;
00542 }
00543 
00544 // If both args are arrays, dimensions may be significant.
00545 static bool
00546 strcmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
00547 {
00548   return (s1.dims () == s2.dims ()
00549           && std::equal (s1.data (), s1.data () + s1.numel (), s2.data ()));
00550 }
00551 
00552 // Otherwise, just use strings.
00553 static bool
00554 strcmp_str_op (const std::string& s1, const std::string& s2,
00555                octave_idx_type)
00556 {
00557   return s1 == s2;
00558 }
00559 
00560 DEFUN (strcmp, args, ,
00561   "-*- texinfo -*-\n\
00562 @deftypefn {Built-in Function} {} strcmp (@var{s1}, @var{s2})\n\
00563 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\
00564 and 0 otherwise.\n\
00565 \n\
00566 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
00567 of the same size is returned, containing the values described above for\n\
00568 every member of the cell array.  The other argument may also be a cell\n\
00569 array of strings (of the same size or with only one element), char matrix\n\
00570 or character string.\n\
00571 \n\
00572 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
00573 function returns 1 if the character strings are equal, and 0 otherwise.\n\
00574 This is just the opposite of the corresponding C library function.\n\
00575 @seealso{strcmpi, strncmp, strncmpi}\n\
00576 @end deftypefn")
00577 {
00578   octave_value retval;
00579 
00580   if (args.length () == 2)
00581     {
00582       retval = do_strcmp_fun (args (0), args (1), 0,
00583                               "strcmp", strcmp_array_op, strcmp_str_op);
00584     }
00585   else
00586     print_usage ();
00587 
00588   return retval;
00589 }
00590 
00591 /*
00592 %!error <Invalid call to strcmp> strcmp ();
00593 %!error <Invalid call to strcmp> strcmp ("foo", "bar", 3);
00594 %!
00595 %!shared x
00596 %!  x = char (zeros (0, 2));
00597 %!assert (strcmp ('', x) == false);
00598 %!assert (strcmp (x, '') == false);
00599 %!assert (strcmp (x, x) == true);
00600 ## %!assert (strcmp ({''}, x) == true);
00601 ## %!assert (strcmp ({x}, '') == false);
00602 ## %!assert (strcmp ({x}, x) == true);
00603 ## %!assert (strcmp ('', {x}) == false);
00604 ## %!assert (strcmp (x, {''}) == false);
00605 ## %!assert (strcmp (x, {x}) == true);
00606 ## %!assert (all (strcmp ({x; x}, '') == [false; false]));
00607 ## %!assert (all (strcmp ({x; x}, {''}) == [false; false]));
00608 ## %!assert (all (strcmp ('', {x; x}) == [false; false]));
00609 ## %!assert (all (strcmp ({''}, {x; x}) == [false; false]));
00610 %!assert (strcmp ({'foo'}, x) == false);
00611 %!assert (strcmp ({'foo'}, 'foo') == true);
00612 %!assert (strcmp ({'foo'}, x) == false);
00613 %!assert (strcmp (x, {'foo'}) == false);
00614 %!assert (strcmp ('foo', {'foo'}) == true);
00615 %!assert (strcmp (x, {'foo'}) == false);
00616 %!shared y
00617 %!  y = char (zeros (2, 0));
00618 %!assert (strcmp ('', y) == false);
00619 %!assert (strcmp (y, '') == false);
00620 %!assert (strcmp (y, y) == true);
00621 %!assert (all (strcmp ({''}, y) == [true; true]));
00622 %!assert (strcmp ({y}, '') == true);
00623 %!assert (all (strcmp ({y}, y) == [true; true]));
00624 %!assert (all (strcmp ('', {y}) == [true; true]));
00625 %!assert (all (strcmp (y, {''}) == [true; true]));
00626 %!assert (all (strcmp (y, {y}) == [true; true]));
00627 %!assert (all (strcmp ({y; y}, '') == [true; true]));
00628 %!assert (all (strcmp ({y; y}, {''}) == [true; true]));
00629 %!assert (all (strcmp ('', {y; y}) == [true; true]));
00630 %!assert (all (strcmp ({''}, {y; y}) == [true; true]));
00631 %!assert (all (strcmp ({'foo'}, y) == [false; false]));
00632 %!assert (all (strcmp ({'foo'}, y) == [false; false]));
00633 %!assert (all (strcmp (y, {'foo'}) == [false; false]));
00634 %!assert (all (strcmp (y, {'foo'}) == [false; false]));
00635 %!assert (strcmp ("foobar", "foobar"), true);
00636 %!assert (strcmp ("fooba", "foobar"), false);
00637 */
00638 
00639 // Apparently, Matlab ignores the dims with strncmp. It also
00640 static bool
00641 strncmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n)
00642 {
00643   octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
00644   return (n > 0 && n <= l1 && n <= l2
00645           && std::equal (s1.data (), s1.data () + n, s2.data ()));
00646 }
00647 
00648 // Otherwise, just use strings. Note that we neither extract substrings (which
00649 // would mean a copy, at least in GCC), nor use string::compare (which is a
00650 // 3-way compare).
00651 static bool
00652 strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
00653 {
00654   octave_idx_type l1 = s1.length (), l2 = s2.length ();
00655   return (n > 0 && n <= l1 && n <= l2
00656           && std::equal (s1.data (), s1.data () + n, s2.data ()));
00657 }
00658 
00659 DEFUN (strncmp, args, ,
00660   "-*- texinfo -*-\n\
00661 @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\
00662 Return 1 if the first @var{n} characters of strings @var{s1} and @var{s2} are\n\
00663 the same, and 0 otherwise.\n\
00664 \n\
00665 @example\n\
00666 @group\n\
00667 strncmp (\"abce\", \"abcd\", 3)\n\
00668      @result{} 1\n\
00669 @end group\n\
00670 @end example\n\
00671 \n\
00672 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
00673 of the same size is returned, containing the values described above for\n\
00674 every member of the cell array.  The other argument may also be a cell\n\
00675 array of strings (of the same size or with only one element), char matrix\n\
00676 or character string.\n\
00677 \n\
00678 @example\n\
00679 @group\n\
00680 strncmp (\"abce\", @{\"abcd\", \"bca\", \"abc\"@}, 3)\n\
00681      @result{} [1, 0, 1]\n\
00682 @end group\n\
00683 @end example\n\
00684 \n\
00685 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmp\n\
00686 function returns 1 if the character strings are equal, and 0 otherwise.\n\
00687 This is just the opposite of the corresponding C library function.\n\
00688 @seealso{strncmpi, strcmp, strcmpi}\n\
00689 @end deftypefn")
00690 {
00691   octave_value retval;
00692 
00693   if (args.length () == 3)
00694     {
00695       octave_idx_type n = args(2).idx_type_value ();
00696 
00697       if (! error_state)
00698         {
00699           if (n > 0)
00700             {
00701               retval = do_strcmp_fun (args(0), args(1), n, "strncmp",
00702                                       strncmp_array_op, strncmp_str_op);
00703             }
00704           else
00705             error ("strncmp: N must be greater than 0");
00706         }
00707     }
00708   else
00709     print_usage ();
00710 
00711   return retval;
00712 }
00713 
00714 /*
00715 %!error <Invalid call to strncmp> strncmp ();
00716 %!error <Invalid call to strncmp> strncmp ("abc", "def");
00717 %!assert (strncmp ("abce", "abc", 3) == 1)
00718 %!assert (strncmp (100, 100, 1) == 0)
00719 %!assert (all (strncmp ("abce", {"abcd", "bca", "abc"}, 3) == [1, 0, 1]))
00720 %!assert (all (strncmp ("abc",  {"abcd", "bca", "abc"}, 4) == [0, 0, 0]))
00721 %!assert (all (strncmp ({"abcd", "bca", "abc"},"abce", 3) == [1, 0, 1]))
00722 %!assert (all (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3) == [1, 1, 0]))
00723 %!assert (all (strncmp("abc", {"abcd", 10}, 2) == [1, 0]))
00724 */
00725 
00726 // case-insensitive character equality functor
00727 struct icmp_char_eq : public std::binary_function<char, char, bool>
00728 {
00729   bool operator () (char x, char y) const
00730     { return std::toupper (x) == std::toupper (y); }
00731 };
00732 
00733 // strcmpi is equivalent to strcmp in that it checks all dims.
00734 static bool
00735 strcmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
00736 {
00737   return (s1.dims () == s2.dims ()
00738           && std::equal (s1.data (), s1.data () + s1.numel (), s2.data (),
00739                          icmp_char_eq ()));
00740 }
00741 
00742 // Ditto for string.
00743 static bool
00744 strcmpi_str_op (const std::string& s1, const std::string& s2,
00745                octave_idx_type)
00746 {
00747   return (s1.size () == s2.size ()
00748           && std::equal (s1.data (), s1.data () + s1.size (), s2.data (),
00749                          icmp_char_eq ()));
00750 }
00751 
00752 DEFUNX ("strcmpi", Fstrcmpi, args, ,
00753   "-*- texinfo -*-\n\
00754 @deftypefn {Built-in Function} {} strcmpi (@var{s1}, @var{s2})\n\
00755 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\
00756 disregarding case of alphabetic characters, and 0 otherwise.\n\
00757 \n\
00758 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
00759 of the same size is returned, containing the values described above for\n\
00760 every member of the cell array.  The other argument may also be a cell\n\
00761 array of strings (of the same size or with only one element), char matrix\n\
00762 or character string.\n\
00763 \n\
00764 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
00765 function returns 1 if the character strings are equal, and 0 otherwise.\n\
00766 This is just the opposite of the corresponding C library function.\n\
00767 \n\
00768 @strong{Caution:} National alphabets are not supported.\n\
00769 @seealso{strcmp, strncmp, strncmpi}\n\
00770 @end deftypefn")
00771 {
00772   octave_value retval;
00773 
00774   if (args.length () == 2)
00775     {
00776       retval = do_strcmp_fun (args (0), args (1), 0,
00777                               "strcmpi", strcmpi_array_op, strcmpi_str_op);
00778     }
00779   else
00780     print_usage ();
00781 
00782   return retval;
00783 }
00784 
00785 /*
00786 %!assert (strcmpi("abc123", "ABC123"), logical(1));
00787 */
00788 
00789 // Like strncmp.
00790 static bool
00791 strncmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n)
00792 {
00793   octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
00794   return (n > 0 && n <= l1 && n <= l2
00795           && std::equal (s1.data (), s1.data () + n, s2.data (),
00796                          icmp_char_eq ()));
00797 }
00798 
00799 // Ditto.
00800 static bool
00801 strncmpi_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
00802 {
00803   octave_idx_type l1 = s1.length (), l2 = s2.length ();
00804   return (n > 0 && n <= l1 && n <= l2
00805           && std::equal (s1.data (), s1.data () + n, s2.data (),
00806                          icmp_char_eq ()));
00807 }
00808 
00809 DEFUNX ("strncmpi", Fstrncmpi, args, ,
00810   "-*- texinfo -*-\n\
00811 @deftypefn {Built-in Function} {} strncmpi (@var{s1}, @var{s2}, @var{n})\n\
00812 Return 1 if the first @var{n} character of @var{s1} and @var{s2} are the\n\
00813 same, disregarding case of alphabetic characters, and 0 otherwise.\n\
00814 \n\
00815 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
00816 of the same size is returned, containing the values described above for\n\
00817 every member of the cell array.  The other argument may also be a cell\n\
00818 array of strings (of the same size or with only one element), char matrix\n\
00819 or character string.\n\
00820 \n\
00821 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi\n\
00822 function returns 1 if the character strings are equal, and 0 otherwise.\n\
00823 This is just the opposite of the corresponding C library function.\n\
00824 \n\
00825 @strong{Caution:} National alphabets are not supported.\n\
00826 @seealso{strncmp, strcmp, strcmpi}\n\
00827 @end deftypefn")
00828 {
00829   octave_value retval;
00830 
00831   if (args.length () == 3)
00832     {
00833       octave_idx_type n = args(2).idx_type_value ();
00834 
00835       if (! error_state)
00836         {
00837           if (n > 0)
00838             {
00839               retval = do_strcmp_fun (args(0), args(1), n, "strncmpi",
00840                                       strncmpi_array_op, strncmpi_str_op);
00841             }
00842           else
00843             error ("strncmpi: N must be greater than 0");
00844         }
00845     }
00846   else
00847     print_usage ();
00848 
00849   return retval;
00850 }
00851 
00852 /*
00853 %!assert (strncmpi("abc123", "ABC456", 3), logical(1));
00854 */
00855 
00856 DEFUN (list_in_columns, args, ,
00857   "-*- texinfo -*-\n\
00858 @deftypefn {Built-in Function} {} list_in_columns (@var{arg}, @var{width})\n\
00859 Return a string containing the elements of @var{arg} listed in\n\
00860 columns with an overall maximum width of @var{width}.  The argument\n\
00861 @var{arg} must be a cell array of character strings or a character array.\n\
00862 If @var{width} is not specified, the width of the terminal screen is used.\n\
00863 Newline characters are used to break the lines in the output string.\n\
00864 For example:\n\
00865 @c Set example in small font to prevent overfull line\n\
00866 \n\
00867 @smallexample\n\
00868 @group\n\
00869 list_in_columns (@{\"abc\", \"def\", \"ghijkl\", \"mnop\", \"qrs\", \"tuv\"@}, 20)\n\
00870      @result{} ans = abc     mnop\n\
00871             def     qrs\n\
00872             ghijkl  tuv\n\
00873 \n\
00874 whos ans\n\
00875      @result{}\n\
00876      Variables in the current scope:\n\
00877 \n\
00878        Attr Name        Size                     Bytes  Class\n\
00879        ==== ====        ====                     =====  =====\n\
00880             ans         1x37                        37  char\n\
00881 \n\
00882      Total is 37 elements using 37 bytes\n\
00883 @end group\n\
00884 @end smallexample\n\
00885 \n\
00886 @seealso{terminal_size}\n\
00887 @end deftypefn")
00888 {
00889   octave_value retval;
00890 
00891   int nargin = args.length ();
00892 
00893   if (nargin == 1 || nargin == 2)
00894     {
00895       string_vector s = args(0).all_strings ();
00896 
00897       if (! error_state)
00898         {
00899           std::ostringstream buf;
00900 
00901           if (nargin == 1)
00902             // Let list_in_columns query terminal width.
00903             s.list_in_columns (buf);
00904           else
00905             {
00906               int width = args(1).int_value ();
00907 
00908               if (! error_state)
00909                 s.list_in_columns (buf, width);
00910               else
00911                 error ("list_in_columns: WIDTH must be an integer");
00912             }
00913 
00914           retval = buf.str ();
00915         }
00916       else
00917         error ("list_in_columns: expecting cellstr or char array");
00918     }
00919   else
00920     print_usage ();
00921 
00922   return retval;
00923 }
00924 
00925 /*
00926 %!error <Invalid call to list_in_columns> list_in_columns ();
00927 %!error <Invalid call to list_in_columns> list_in_columns (["abc", "def"], 20, 2);
00928 %!error <invalid conversion from string to real scalar> list_in_columns (["abc", "def"], "a");
00929 %!test
00930 %!  input  = {"abc", "def", "ghijkl", "mnop", "qrs", "tuv"};
00931 %!  result = "abc     mnop\ndef     qrs\nghijkl  tuv\n";
00932 %!  assert (list_in_columns (input, 20) == result);
00933 %!test
00934 %!  input  = ["abc"; "def"; "ghijkl"; "mnop"; "qrs"; "tuv"];
00935 %!  result = "abc     mnop  \ndef     qrs   \nghijkl  tuv   \n";
00936 %!  assert (list_in_columns (input, 20) == result);
00937 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines