Mercurial > hg > octave-lojdl
changeset 10108:06e11df4592d
implement built-in strcmpi/strncmpi, reduce some code duplication
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Thu, 14 Jan 2010 13:48:20 +0100 |
parents | fd262afea1d1 |
children | a8de53a88e07 |
files | scripts/ChangeLog scripts/strings/module.mk scripts/strings/strcmpi.m scripts/strings/strncmpi.m src/ChangeLog src/strfns.cc |
diffstat | 6 files changed, 399 insertions(+), 556 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,9 @@ +2010-01-14 Jaroslav Hajek <highegg@gmail.com> + + * strings/strcmpi.m: Remove. + * strings/strncmpi.m: Remove. + * strings/module.mk: Update. + 2010-01-13 John W. Eaton <jwe@octave.org> * miscellaneous/inputname.m: Use isvarname instead of regexp.
--- a/scripts/strings/module.mk +++ b/scripts/strings/module.mk @@ -21,11 +21,9 @@ strings/str2num.m \ strings/strcat.m \ strings/cstrcat.m \ - strings/strcmpi.m \ strings/strchr.m \ strings/strjust.m \ strings/strmatch.m \ - strings/strncmpi.m \ strings/strtok.m \ strings/strtrim.m \ strings/strtrunc.m \
deleted file mode 100644 --- a/scripts/strings/strcmpi.m +++ /dev/null @@ -1,55 +0,0 @@ -## Copyright (C) 2000, 2005, 2006, 2007, 2009 Bill Lash -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} strcmpi (@var{s1}, @var{s2}) -## Ignoring case, return 1 if the character strings (or character -## arrays) @var{s1} and @var{s2} are the same, and 0 otherwise. -## -## If either @var{s1} or @var{s2} is a cell array of strings, then an array -## of the same size is returned, containing the values described above for -## every member of the cell array. The other argument may also be a cell -## array of strings (of the same size or with only one element), char matrix -## or character string. -## -## @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmpi -## function returns 1 if the character strings are equal, and 0 otherwise. -## This is just the opposite of the corresponding C library function. -## @seealso{strcmp, strncmp, strncmpi} -## @end deftypefn - -## Author: Bill Lash <lash@tellabs.com> -## Adapted-by: jwe - -function retval = strcmpi (s1, s2) - - if (nargin == 2) - if ((ischar(s1) || iscellstr(s1)) && (ischar(s2) || iscellstr(s2))) - ## Note that we don't use tolower here because we need to be able - ## to handle cell arrays of strings. - retval = strcmp (lower (s1), lower (s2)); - else - retval = false; - endif - else - print_usage (); - endif - -endfunction - -%!assert (strcmpi("abc123", "ABC123"), logical(1));
deleted file mode 100644 --- a/scripts/strings/strncmpi.m +++ /dev/null @@ -1,49 +0,0 @@ -## Copyright (C) 2000, 2006, 2007, 2009 Bill Lash -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} strncmpi (@var{s1}, @var{s2}, @var{n}) -## Ignoring case, return 1 if the first @var{n} characters of character -## strings (or character arrays) @var{s1} and @var{s2} are the same, and -## 0 otherwise. -## -## If either @var{s1} or @var{s2} is a cell array of strings, then an array -## of the same size is returned, containing the values described above for -## every member of the cell array. The other argument may also be a cell -## array of strings (of the same size or with only one element), char matrix -## or character string. -## -## @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi -## function returns 1 if the character strings are equal, and 0 otherwise. -## This is just the opposite of the corresponding C library function. -## @seealso{strcmp, strcmpi, strncmp} -## @end deftypefn - -function retval = strncmpi (s1, s2, n) - - if (nargin == 3) - ## Note that we don't use tolower here because we need to be able to - ## handle cell arrays of strings. - retval = strncmp (lower (s1), lower (s2), n); - else - print_usage (); - endif - -endfunction - -%!assert (strncmpi("abc123", "ABC456", 3), logical(1));
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2010-01-14 Jaroslav Hajek <highegg@gmail.com> + + * strfns.cc (do_strcmp_fun, + strcmp_array_op, strcmp_str_op, + strcmpi_array_op, strcmpi_str_op, + strncmp_array_op, strncmp_str_op, + strncmpi_array_op, strncmpi_str_op): New functions. + (Fstrcmp, Fstrncmp): Reimplement using do_strcmp_fun. + (Fstrcmpi, Fstrncmpi): New defuns. + 2010-01-14 Jaroslav Hajek <highegg@gmail.com> * DLD-FUNCTIONS/bsxfun.cc (maybe_fill_table): register relational
--- a/src/strfns.cc +++ b/src/strfns.cc @@ -321,6 +321,227 @@ */ +static octave_value +do_strcmp_fun (const octave_value& arg0, const octave_value& arg1, + octave_idx_type n, const char *fcn_name, + bool (*array_op) (const charNDArray&, const charNDArray&, octave_idx_type), + bool (*str_op) (const std::string&, const std::string&, octave_idx_type)) + +{ + octave_value retval; + + bool s1_string = arg0.is_string (); + bool s1_cell = arg0.is_cell (); + bool s2_string = arg1.is_string (); + bool s2_cell = arg1.is_cell (); + + if (s1_string && s2_string) + retval = array_op (arg0.char_array_value (), arg1.char_array_value (), n); + else if ((s1_string && s2_cell) || (s1_cell && s2_string)) + { + octave_value str_val, cell_val; + + if (s1_string) + { + str_val = arg0; + cell_val = arg1; + } + else + { + str_val = arg1; + cell_val = arg0; + } + + const Cell cell = cell_val.cell_value (); + const string_vector str = str_val.all_strings (); + octave_idx_type r = str.rows (); + + if (r == 0 || r == 1) + { + // Broadcast the string. + + boolNDArray output (cell_val.dims (), false); + + std::string s = r == 0 ? std::string () : str[0]; + + if (cell_val.is_cellstr ()) + { + const Array<std::string> cellstr = cell_val.cellstr_value (); + for (octave_idx_type i = 0; i < cellstr.length (); i++) + output(i) = str_op (cellstr(i), s, n); + } + else + { + // FIXME: should we warn here? + for (octave_idx_type i = 0; i < cell.length (); i++) + { + if (cell(i).is_string ()) + output(i) = str_op (cell(i).string_value (), s, n); + } + } + + retval = output; + } + else if (r > 1) + { + if (cell.length () == 1) + { + // Broadcast the cell. + + const dim_vector dv (r, 1); + boolNDArray output (dv, false); + + if (cell(0).is_string ()) + { + const std::string str2 = cell(0).string_value (); + + for (octave_idx_type i = 0; i < r; i++) + output(i) = str_op (str[i], str2, n); + } + + retval = output; + } + else + { + // Must match in all dimensions. + + boolNDArray output (cell.dims (), false); + + if (cell.length () == r) + { + if (cell_val.is_cellstr ()) + { + const Array<std::string> cellstr = cell_val.cellstr_value (); + for (octave_idx_type i = 0; i < cellstr.length (); i++) + output(i) = str_op (str[i], cellstr(i), n); + } + else + { + // FIXME: should we warn here? + for (octave_idx_type i = 0; i < r; i++) + { + if (cell(i).is_string ()) + output(i) = str_op (str[i], cell(i).string_value (), n); + } + } + + retval = output; + } + else + retval = false; + } + } + } + else if (s1_cell && s2_cell) + { + octave_value cell1_val, cell2_val; + octave_idx_type r1 = arg0.numel (), r2; + + if (r1 == 1) + { + // Make the singleton cell2. + + cell1_val = arg1; + cell2_val = arg0; + } + else + { + cell1_val = arg0; + cell2_val = arg1; + } + + const Cell cell1 = cell1_val.cell_value (); + const Cell cell2 = cell2_val.cell_value (); + r1 = cell1.numel (); + r2 = cell2.numel (); + + const dim_vector size1 = cell1.dims (); + const dim_vector size2 = cell2.dims (); + + boolNDArray output (size1, false); + + if (r2 == 1) + { + // Broadcast cell2. + + if (cell2(0).is_string ()) + { + const std::string str2 = cell2(0).string_value (); + + if (cell1_val.is_cellstr ()) + { + const Array<std::string> cellstr = cell1_val.cellstr_value (); + for (octave_idx_type i = 0; i < cellstr.length (); i++) + output(i) = str_op (cellstr(i), str2, n); + } + else + { + // FIXME: should we warn here? + for (octave_idx_type i = 0; i < r1; i++) + { + if (cell1(i).is_string ()) + { + const std::string str1 = cell1(i).string_value (); + output(i) = str_op (str1, str2, n); + } + } + } + } + } + else + { + if (size1 != size2) + { + error ("%s: nonconformant cell arrays", fcn_name); + return retval; + } + + if (cell1.is_cellstr () && cell2.is_cellstr ()) + { + const Array<std::string> cellstr1 = cell1_val.cellstr_value (); + const Array<std::string> cellstr2 = cell2_val.cellstr_value (); + for (octave_idx_type i = 0; i < r1; i++) + output (i) = str_op (cellstr1(i), cellstr2(i), n); + } + else + { + // FIXME: should we warn here? + for (octave_idx_type i = 0; i < r1; i++) + { + if (cell1(i).is_string () && cell2(i).is_string ()) + { + const std::string str1 = cell1(i).string_value (); + const std::string str2 = cell2(i).string_value (); + output(i) = str_op (str1, str2, n); + } + } + } + } + + retval = output; + } + else + retval = false; + + return retval; +} + +// If both args are arrays, dimensions may be significant. +static bool +strcmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type) +{ + return (s1.dims () == s2.dims () + && std::equal (s1.data (), s1.data () + s1.numel (), s2.data ())); +} + +// Otherwise, just use strings. +static bool +strcmp_str_op (const std::string& s1, const std::string& s2, + octave_idx_type) +{ + return s1 == s2; +} + DEFUN (strcmp, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} strcmp (@var{s1}, @var{s2})\n\ @@ -343,234 +564,8 @@ if (args.length () == 2) { - bool s1_string = args(0).is_string (); - bool s1_cell = args(0).is_cell (); - bool s2_string = args(1).is_string (); - bool s2_cell = args(1).is_cell (); - - if (s1_string && s2_string) - { - // Must match exactly in all dimensions. - - const dim_vector dv1 = args(0).dims (); - const dim_vector dv2 = args(1).dims (); - - if (dv1.length () == dv2.length ()) - { - for (octave_idx_type i = 0; i < dv1.length (); i++) - { - if (dv1(i) != dv2(i)) - { - retval = false; - return retval; - } - } - - if (dv1(0) == 0) - retval = true; - else - { - const charNDArray s1 = args(0).char_array_value (); - const charNDArray s2 = args(1).char_array_value (); - - for (octave_idx_type i = 0; i < dv1.numel (); i++) - { - if (s1(i) != s2(i)) - { - retval = false; - return retval; - } - } - - retval = true; - } - } - } - else if ((s1_string && s2_cell) || (s1_cell && s2_string)) - { - octave_value str_val, cell_val; - - if (s1_string) - { - str_val = args (0); - cell_val = args (1); - } - else - { - str_val = args (1); - cell_val = args (0); - } - - const Cell cell = cell_val.cell_value (); - const string_vector str = str_val.all_strings (); - octave_idx_type r = str.rows (); - - if (r == 0 || r == 1) - { - // Broadcast the string. - - boolNDArray output (cell_val.dims (), false); - - std::string s = r == 0 ? std::string () : str[0]; - - if (cell_val.is_cellstr ()) - { - const Array<std::string> cellstr = cell_val.cellstr_value (); - for (octave_idx_type i = 0; i < cellstr.length (); i++) - output(i) = cellstr(i) == s; - } - else - { - // FIXME: should we warn here? - for (octave_idx_type i = 0; i < cell.length (); i++) - { - if (cell(i).is_string ()) - output(i) = (cell(i).string_value () == s); - } - } - - retval = output; - } - else if (r > 1) - { - if (cell.length () == 1) - { - // Broadcast the cell. - - const dim_vector dv (r, 1); - boolNDArray output (dv, false); - - if (cell(0).is_string ()) - { - const std::string str2 = cell(0).string_value (); - - for (octave_idx_type i = 0; i < r; i++) - output(i) = (str[i] == str2); - } - - retval = output; - } - else - { - // Must match in all dimensions. - - boolNDArray output (cell.dims (), false); - - if (cell.length () == r) - { - if (cell_val.is_cellstr ()) - { - const Array<std::string> cellstr = cell_val.cellstr_value (); - for (octave_idx_type i = 0; i < cellstr.length (); i++) - output(i) = str[i] == cellstr(i); - } - else - { - // FIXME: should we warn here? - for (octave_idx_type i = 0; i < r; i++) - { - if (cell(i).is_string ()) - output(i) = (str[i] == cell(i).string_value ()); - } - } - - retval = output; - } - else - retval = false; - } - } - } - else if (s1_cell && s2_cell) - { - octave_value cell1_val, cell2_val; - octave_idx_type r1 = args(0).numel (), r2; - - if (r1 == 1) - { - // Make the singleton cell2. - - cell1_val = args(1); - cell2_val = args(0); - } - else - { - cell1_val = args(0); - cell2_val = args(1); - } - - const Cell cell1 = cell1_val.cell_value (); - const Cell cell2 = cell2_val.cell_value (); - r1 = cell1.numel (); - r2 = cell2.numel (); - - const dim_vector size1 = cell1.dims (); - const dim_vector size2 = cell2.dims (); - - boolNDArray output (size1, false); - - if (r2 == 1) - { - // Broadcast cell2. - - if (cell2(0).is_string ()) - { - const std::string str2 = cell2(0).string_value (); - - if (cell1_val.is_cellstr ()) - { - const Array<std::string> cellstr = cell1_val.cellstr_value (); - for (octave_idx_type i = 0; i < cellstr.length (); i++) - output(i) = cellstr(i) == str2; - } - else - { - // FIXME: should we warn here? - for (octave_idx_type i = 0; i < r1; i++) - { - if (cell1(i).is_string ()) - { - const std::string str1 = cell1(i).string_value (); - output(i) = (str1 == str2); - } - } - } - } - } - else - { - if (size1 != size2) - { - error ("strcmp: nonconformant cell arrays"); - return retval; - } - - if (cell1.is_cellstr () && cell2.is_cellstr ()) - { - const Array<std::string> cellstr1 = cell1_val.cellstr_value (); - const Array<std::string> cellstr2 = cell2_val.cellstr_value (); - for (octave_idx_type i = 0; i < r1; i++) - output (i) = cellstr1(i) == cellstr2(i); - } - else - { - // FIXME: should we warn here? - for (octave_idx_type i = 0; i < r1; i++) - { - if (cell1(i).is_string () && cell2(i).is_string ()) - { - const std::string str1 = cell1(i).string_value (); - const std::string str2 = cell2(i).string_value (); - output(i) = (str1 == str2); - } - } - } - } - - retval = output; - } - else - retval = false; + retval = do_strcmp_fun (args (0), args (1), 0, + "strcmp", strcmp_array_op, strcmp_str_op); } else print_usage (); @@ -621,6 +616,26 @@ %!assert (all (strcmp (y, {'foo'}) == [false; false])); */ +// Apparently, Matlab ignores the dims with strncmp. It also +static bool +strncmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n) +{ + octave_idx_type l1 = s1.numel (), l2 = s2.numel (); + return (n > 0 && n <= l1 && n <= l2 + && std::equal (s1.data (), s1.data () + n, s2.data ())); +} + +// Otherwise, just use strings. Note that we neither extract substrings (which +// would mean a copy, at least in GCC), nor use string::compare (which is a +// 3-way compare). +static bool +strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n) +{ + octave_idx_type l1 = s1.length (), l2 = s2.length (); + return (n > 0 && n <= l1 && n <= l2 + && std::equal (s1.data (), s1.data () + n, s2.data ())); +} + DEFUN (strncmp, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\ @@ -657,229 +672,18 @@ if (args.length () == 3) { - bool s1_string = args(0).is_string (); - bool s1_cell = args(0).is_cell (); - bool s2_string = args(1).is_string (); - bool s2_cell = args(1).is_cell (); - - // Match only first n strings. - int n = args(2).int_value (); - - if (n <= 0) - { - error ("strncmp: N must be greater than 0"); - return retval; - } - - if (s1_string && s2_string) - { - // The only restriction here is that each string has equal or - // greater than n characters - - const dim_vector dv1 = args(0).dims (); - const dim_vector dv2 = args(1).dims (); - - if (dv1.numel () >= n && dv2.numel () >= n) - { - // Follow Matlab in the sense that the first n characters of - // the two strings (in column major order) need to be the same. - charNDArray s1 = args(0).char_array_value (); - charNDArray s2 = args(1).char_array_value (); - - for (int i = 0; i < n; i++) - { - if (s1(i) != s2(i)) - { - retval = false; - return retval; - } - } - - retval = true; - } - else - retval = false; - } - else if ((s1_string && s2_cell) || (s1_cell && s2_string)) - { - string_vector str; - Cell cell; - octave_idx_type r, c; - - if (s1_string) - { - str = args(0).all_strings (); - r = args(0).rows (); - c = args(0).columns (); - cell = args(1).cell_value (); - } - else - { - str = args(1).all_strings (); - r = args(1).rows (); - c = args(1).columns (); - cell = args(0).cell_value (); - } - - if (r == 1) - { - // Broadcast the string. - - boolNDArray output (cell.dims (), false); - - if (c < n) - { - for (octave_idx_type i = 0; i < cell.length (); i++) - output(i) = false; - } - else - { - for (octave_idx_type i = 0; i < cell.length (); i++) - { - if (cell(i).is_string ()) - { - const std::string str2 = cell(i).string_value (); - - if (str2.length () >= n - && str2.compare (0, n, str[0], 0, n) == 0) - output(i) = true; - } - } - } - - retval = output; - } - else if (r > 1) - { - if (cell.length () == 1) - { - // Broadcast the cell. - - const dim_vector dv (r, 1); - boolNDArray output (dv, false); + octave_idx_type n = args(2).idx_type_value (); - if (cell(0).is_string () && c >= n) - { - const std::string str2 = cell(0).string_value (); - - if (str2.length () >= n) - { - for (octave_idx_type i = 0; i < r; i++) - { - if (str[i].compare (0, n, str2, 0, n) == 0) - output(i) = true; - } - } - } - - retval = output; - } - else - { - // Must match in all dimensions. - - boolNDArray output (cell.dims (), false); - - if (cell.numel () == r) - { - for (octave_idx_type i = 0; i < r; i++) - { - if (cell(i).is_string () && c >= n) - { - std::string str2 = cell(i).string_value (); - - if (str2.length () >= n - && str2.compare (0, n, str[i], 0, n) == 0) - output(i) = true; - } - } - - retval = output; - } - else - { - error ("strncmp: the number of rows of the string matrix must match the number of elements in the cell"); - return retval; - } - } - } - } - else if (s1_cell && s2_cell) - { - Cell cell1; - Cell cell2; - - octave_idx_type r1 = args(0).numel (); - octave_idx_type r2; - - if (r1 == 1) - { - // Make the singleton cell2. - - cell1 = args(1).cell_value (); - cell2 = args(0).cell_value (); - r1 = cell1.length (); - r2 = 1; - } - else - { - cell1 = args(0).cell_value (); - cell2 = args(1).cell_value (); - r2 = cell2.length (); - } - - const dim_vector size1 = cell1.dims (); - const dim_vector size2 = cell2.dims (); - - boolNDArray output (size1, false); - - if (r2 == 1) - { - // Broadcast cell2. - - if (cell2(0).is_string ()) - { - const std::string str2 = cell2(0).string_value (); - - for (octave_idx_type i = 0; i < r1; i++) - { - if (cell1(i).is_string ()) - { - const std::string str1 = cell1(i).string_value (); - - if (str1.length () >= n && str2.length () >= n - && str1.compare (0, n, str2, 0, n) == 0) - output(i) = true; - } - } - } - } - else - { - if (size1 != size2) - { - error ("strncmp: nonconformant cell arrays"); - return retval; - } - - for (octave_idx_type i = 0; i < r1; i++) - { - if (cell1(i).is_string () && cell2(i).is_string ()) - { - const std::string str1 = cell1(i).string_value (); - const std::string str2 = cell2(i).string_value (); - - if (str1.length () >= n && str2.length () >= n - && str1.compare (0, n, str2, 0, n) == 0) - output(i) = true; - } - } - } - - retval = output; - } - else - retval = false; + if (! error_state) + { + if (n > 0) + { + retval = do_strcmp_fun (args(0), args(1), n, "strncmp", + strncmp_array_op, strncmp_str_op); + } + else + error ("strncmp: N must be greater than 0"); + } } else print_usage (); @@ -899,6 +703,135 @@ %!assert (all (strncmp("abc", {"abcd", 10}, 2) == [1, 0])) */ +// case-insensitive character equality functor +struct icmp_char_eq : public std::binary_function<char, char, bool> +{ + bool operator () (char x, char y) const + { return std::toupper (x) == std::toupper (y); } +}; + +// strcmpi is equivalent to strcmp in that it checks all dims. +static bool +strcmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type) +{ + return (s1.dims () == s2.dims () + && std::equal (s1.data (), s1.data () + s1.numel (), s2.data (), + icmp_char_eq ())); +} + +// Ditto for string. +static bool +strcmpi_str_op (const std::string& s1, const std::string& s2, + octave_idx_type) +{ + return (s1.size () == s2.size () + && std::equal (s1.data (), s1.data () + s1.size (), s2.data (), + icmp_char_eq ())); +} + +DEFUN (strcmpi, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} strcmpi (@var{s1}, @var{s2})\n\ +Returns 1 if the character strings @var{s1} and @var{s2} are the same,\n\ +disregarding case of alphabetic characters, and 0 otherwise.\n\ +\n\ +If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\ +of the same size is returned, containing the values described above for\n\ +every member of the cell array. The other argument may also be a cell\n\ +array of strings (of the same size or with only one element), char matrix\n\ +or character string.\n\ +\n\ +@strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\ +function returns 1 if the character strings are equal, and 0 otherwise.\n\ +This is just the opposite of the corresponding C library function.\n\ +\n\ +@strong{Caution:} National alphabets are not supported.\n\ +@seealso{strcmp, strncmp, strncmpi}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 2) + { + retval = do_strcmp_fun (args (0), args (1), 0, + "strcmpi", strcmpi_array_op, strcmpi_str_op); + } + else + print_usage (); + + return retval; +} + +/* +%!assert (strcmpi("abc123", "ABC123"), logical(1)); +*/ + +// Like strncmp. +static bool +strncmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n) +{ + octave_idx_type l1 = s1.numel (), l2 = s2.numel (); + return (n > 0 && n <= l1 && n <= l2 + && std::equal (s1.data (), s1.data () + n, s2.data (), + icmp_char_eq ())); +} + +// Ditto. +static bool +strncmpi_str_op (const std::string& s1, const std::string& s2, octave_idx_type n) +{ + octave_idx_type l1 = s1.length (), l2 = s2.length (); + return (n > 0 && n <= l1 && n <= l2 + && std::equal (s1.data (), s1.data () + n, s2.data (), + icmp_char_eq ())); +} + +DEFUN (strncmpi, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\ +Returns 1 if the first @var{n} character of @var{s1} and @var{s2} are the same,\n\ +disregarding case of alphabetic characters, and 0 otherwise.\n\ +\n\ +If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\ +of the same size is returned, containing the values described above for\n\ +every member of the cell array. The other argument may also be a cell\n\ +array of strings (of the same size or with only one element), char matrix\n\ +or character string.\n\ +\n\ +@strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi\n\ +function returns 1 if the character strings are equal, and 0 otherwise.\n\ +This is just the opposite of the corresponding C library function.\n\ +\n\ +@strong{Caution:} National alphabets are not supported.\n\ +@seealso{strncmp, strcmp, strcmpi}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 3) + { + octave_idx_type n = args(2).idx_type_value (); + + if (! error_state) + { + if (n > 0) + { + retval = do_strcmp_fun (args(0), args(1), n, "strncmpi", + strncmpi_array_op, strncmpi_str_op); + } + else + error ("strncmp: N must be greater than 0"); + } + } + else + print_usage (); + + return retval; +} + +/* +%!assert (strncmpi("abc123", "ABC456", 3), logical(1)); +*/ DEFUN (list_in_columns, args, , "-*- texinfo -*-\n\