GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
strfns.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1994-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cctype>
28 
29 #include <queue>
30 #include <sstream>
31 
32 #include "dMatrix.h"
33 
34 #include "Cell.h"
35 #include "defun.h"
36 #include "error.h"
37 #include "gripes.h"
38 #include "ov.h"
39 #include "oct-obj.h"
40 #include "unwind-prot.h"
41 #include "utils.h"
42 
43 DEFUN (char, args, ,
44  "-*- texinfo -*-\n\
45 @deftypefn {Built-in Function} {} char (@var{x})\n\
46 @deftypefnx {Built-in Function} {} char (@var{x}, @dots{})\n\
47 @deftypefnx {Built-in Function} {} char (@var{s1}, @var{s2}, @dots{})\n\
48 @deftypefnx {Built-in Function} {} char (@var{cell_array})\n\
49 Create a string array from one or more numeric matrices, character\n\
50 matrices, or cell arrays. Arguments are concatenated vertically.\n\
51 The returned values are padded with blanks as needed to make each row\n\
52 of the string array have the same length. Empty input strings are\n\
53 significant and will concatenated in the output.\n\
54 \n\
55 For numerical input, each element is converted\n\
56 to the corresponding ASCII character. A range error results if an input\n\
57 is outside the ASCII range (0-255).\n\
58 \n\
59 For cell arrays, each element is concatenated separately. Cell arrays\n\
60 converted through\n\
61 @code{char} can mostly be converted back with @code{cellstr}.\n\
62 For example:\n\
63 \n\
64 @example\n\
65 @group\n\
66 char ([97, 98, 99], \"\", @{\"98\", \"99\", 100@}, \"str1\", [\"ha\", \"lf\"])\n\
67  @result{} [\"abc \"\n\
68  \" \"\n\
69  \"98 \"\n\
70  \"99 \"\n\
71  \"d \"\n\
72  \"str1 \"\n\
73  \"half \"]\n\
74 @end group\n\
75 @end example\n\
76 @seealso{strvcat, cellstr}\n\
77 @end deftypefn")
78 {
79  octave_value retval;
80 
81  int nargin = args.length ();
82 
83  if (nargin == 0)
84  retval = "";
85  else if (nargin == 1)
86  retval = args(0).convert_to_str (true, true,
87  args(0).is_dq_string () ? '"' : '\'');
88  else
89  {
90  int n_elts = 0;
91 
92  int max_len = 0;
93 
94  std::queue<string_vector> args_as_strings;
95 
96  for (int i = 0; i < nargin; i++)
97  {
98  string_vector s = args(i).all_strings ();
99 
100  if (error_state)
101  {
102  error ("char: unable to convert some args to strings");
103  return retval;
104  }
105 
106  if (s.length () > 0)
107  n_elts += s.length ();
108  else
109  n_elts += 1;
110 
111  int s_max_len = s.max_length ();
112 
113  if (s_max_len > max_len)
114  max_len = s_max_len;
115 
116  args_as_strings.push (s);
117  }
118 
119  string_vector result (n_elts);
120 
121  int k = 0;
122 
123  for (int i = 0; i < nargin; i++)
124  {
125  string_vector s = args_as_strings.front ();
126  args_as_strings.pop ();
127 
128  int n = s.length ();
129 
130  if (n > 0)
131  {
132  for (int j = 0; j < n; j++)
133  {
134  std::string t = s[j];
135  int t_len = t.length ();
136 
137  if (max_len > t_len)
138  t += std::string (max_len - t_len, ' ');
139 
140  result[k++] = t;
141  }
142  }
143  else
144  result[k++] = std::string (max_len, ' ');
145  }
146 
147  retval = octave_value (result, '\'');
148  }
149 
150  return retval;
151 }
152 
153 /*
154 %!assert (char (), '');
155 %!assert (char (100), "d");
156 %!assert (char (100,100), ["d";"d"])
157 %!assert (char ({100,100}), ["d";"d"])
158 %!assert (char ([100,100]), ["dd"])
159 %!assert (char ({100,{100}}), ["d";"d"])
160 %!assert (char (100, [], 100), ["d";" ";"d"])
161 %!assert (char ({100, [], 100}), ["d";" ";"d"])
162 %!assert (char ({100,{100, {""}}}), ["d";"d";" "])
163 %!assert (char (["a";"be"], {"c", 100}), ["a";"be";"c";"d"])
164 %!assert (char ("a", "bb", "ccc"), ["a "; "bb "; "ccc"])
165 %!assert (char ([65, 83, 67, 73, 73]), "ASCII")
166 
167 %!test
168 %! x = char ("foo", "bar", "foobar");
169 %! assert (x(1,:), "foo ");
170 %! assert (x(2,:), "bar ");
171 %! assert (x(3,:), "foobar");
172 */
173 
174 DEFUN (strvcat, args, ,
175  "-*- texinfo -*-\n\
176 @deftypefn {Built-in Function} {} strvcat (@var{x})\n\
177 @deftypefnx {Built-in Function} {} strvcat (@var{x}, @dots{})\n\
178 @deftypefnx {Built-in Function} {} strvcat (@var{s1}, @var{s2}, @dots{})\n\
179 @deftypefnx {Built-in Function} {} strvcat (@var{cell_array})\n\
180 Create a character array from one or more numeric matrices, character\n\
181 matrices, or cell arrays. Arguments are concatenated vertically.\n\
182 The returned values are padded with blanks as needed to make each row\n\
183 of the string array have the same length. Unlike @code{char}, empty\n\
184 strings are removed and will not appear in the output.\n\
185 \n\
186 For numerical input, each element is converted\n\
187 to the corresponding ASCII character. A range error results if an input\n\
188 is outside the ASCII range (0-255).\n\
189 \n\
190 For cell arrays, each element is concatenated separately. Cell arrays\n\
191 converted through\n\
192 @code{strvcat} can mostly be converted back with @code{cellstr}.\n\
193 For example:\n\
194 \n\
195 @example\n\
196 @group\n\
197 strvcat ([97, 98, 99], \"\", @{\"98\", \"99\", 100@}, \"str1\", [\"ha\", \"lf\"])\n\
198  @result{} [\"abc \"\n\
199  \"98 \"\n\
200  \"99 \"\n\
201  \"d \"\n\
202  \"str1 \"\n\
203  \"half \"]\n\
204 @end group\n\
205 @end example\n\
206 @seealso{char, strcat, cstrcat}\n\
207 @end deftypefn")
208 {
209  octave_value retval;
210 
211  int nargin = args.length ();
212 
213  if (nargin > 0)
214  {
215  int n_elts = 0;
216 
217  size_t max_len = 0;
218 
219  std::queue<string_vector> args_as_strings;
220 
221  for (int i = 0; i < nargin; i++)
222  {
223  string_vector s = args(i).all_strings ();
224 
225  if (error_state)
226  {
227  error ("strvcat: unable to convert some args to strings");
228  return retval;
229  }
230 
231  size_t n = s.length ();
232 
233  // do not count empty strings in calculation of number of elements
234  if (n > 0)
235  {
236  for (size_t j = 0; j < n; j++)
237  {
238  if (s[j].length () > 0)
239  n_elts++;
240  }
241  }
242 
243  size_t s_max_len = s.max_length ();
244 
245  if (s_max_len > max_len)
246  max_len = s_max_len;
247 
248  args_as_strings.push (s);
249  }
250 
251  string_vector result (n_elts);
252 
253  octave_idx_type k = 0;
254 
255  for (int i = 0; i < nargin; i++)
256  {
257  string_vector s = args_as_strings.front ();
258  args_as_strings.pop ();
259 
260  size_t n = s.length ();
261 
262  if (n > 0)
263  {
264  for (size_t j = 0; j < n; j++)
265  {
266  std::string t = s[j];
267  if (t.length () > 0)
268  {
269  size_t t_len = t.length ();
270 
271  if (max_len > t_len)
272  t += std::string (max_len - t_len, ' ');
273 
274  result[k++] = t;
275  }
276  }
277  }
278  }
279 
280  retval = octave_value (result, '\'');
281  }
282  else
283  print_usage ();
284 
285  return retval;
286 }
287 
288 /*
289 %!assert (strvcat (""), "");
290 %!assert (strvcat (100) == "d");
291 %!assert (strvcat (100,100), ["d";"d"])
292 %!assert (strvcat ({100,100}), ["d";"d"])
293 %!assert (strvcat ([100,100]), ["dd"])
294 %!assert (strvcat ({100,{100}}), ["d";"d"])
295 %!assert (strvcat (100, [], 100), ["d";"d"])
296 %!assert (strvcat ({100, [], 100}), ["d";"d"])
297 %!assert (strvcat ({100,{100, {""}}}), ["d";"d"])
298 %!assert (strvcat (["a";"be"], {"c", 100}), ["a";"be";"c";"d"])
299 %!assert (strvcat ("a", "bb", "ccc"), ["a "; "bb "; "ccc"])
300 
301 %!error strvcat ()
302 */
303 
304 
305 DEFUN (ischar, args, ,
306  "-*- texinfo -*-\n\
307 @deftypefn {Built-in Function} {} ischar (@var{x})\n\
308 Return true if @var{x} is a character array.\n\
309 @seealso{isfloat, isinteger, islogical, isnumeric, iscellstr, isa}\n\
310 @end deftypefn")
311 {
312  octave_value retval;
313 
314  int nargin = args.length ();
315 
316  if (nargin == 1 && args(0).is_defined ())
317  retval = args(0).is_string ();
318  else
319  print_usage ();
320 
321  return retval;
322 }
323 
324 /*
325 %!assert (ischar ("a"), true)
326 %!assert (ischar (["ab";"cd"]), true)
327 %!assert (ischar ({"ab"}), false)
328 %!assert (ischar (1), false)
329 %!assert (ischar ([1, 2]), false)
330 %!assert (ischar ([]), false)
331 %!assert (ischar ([1, 2; 3, 4]), false)
332 %!assert (ischar (""), true)
333 %!assert (ischar ("test"), true)
334 %!assert (ischar (["test"; "ing"]), true)
335 %!assert (ischar (struct ("foo", "bar")), false)
336 
337 %!error ischar ()
338 %!error ischar ("test", 1)
339 */
340 
341 static octave_value
342 do_strcmp_fun (const octave_value& arg0, const octave_value& arg1,
343  octave_idx_type n, const char *fcn_name,
344  bool (*array_op) (const charNDArray&, const charNDArray&,
346  bool (*str_op) (const std::string&, const std::string&,
348 
349 {
350  octave_value retval;
351 
352  bool s1_string = arg0.is_string ();
353  bool s1_cell = arg0.is_cell ();
354  bool s2_string = arg1.is_string ();
355  bool s2_cell = arg1.is_cell ();
356 
357  if (s1_string && s2_string)
358  retval = array_op (arg0.char_array_value (), arg1.char_array_value (), n);
359  else if ((s1_string && s2_cell) || (s1_cell && s2_string))
360  {
361  octave_value str_val, cell_val;
362 
363  if (s1_string)
364  {
365  str_val = arg0;
366  cell_val = arg1;
367  }
368  else
369  {
370  str_val = arg1;
371  cell_val = arg0;
372  }
373 
374  const Cell cell = cell_val.cell_value ();
375  const string_vector str = str_val.all_strings ();
376  octave_idx_type r = str.length ();
377 
378  if (r == 0 || r == 1)
379  {
380  // Broadcast the string.
381 
382  boolNDArray output (cell_val.dims (), false);
383 
384  std::string s = r == 0 ? std::string () : str[0];
385 
386  if (cell_val.is_cellstr ())
387  {
388  const Array<std::string> cellstr = cell_val.cellstr_value ();
389  for (octave_idx_type i = 0; i < cellstr.length (); i++)
390  output(i) = str_op (cellstr(i), s, n);
391  }
392  else
393  {
394  // FIXME: should we warn here?
395  for (octave_idx_type i = 0; i < cell.length (); i++)
396  {
397  if (cell(i).is_string ())
398  output(i) = str_op (cell(i).string_value (), s, n);
399  }
400  }
401 
402  retval = output;
403  }
404  else if (r > 1)
405  {
406  if (cell.length () == 1)
407  {
408  // Broadcast the cell.
409 
410  const dim_vector dv (r, 1);
411  boolNDArray output (dv, false);
412 
413  if (cell(0).is_string ())
414  {
415  const std::string str2 = cell(0).string_value ();
416 
417  for (octave_idx_type i = 0; i < r; i++)
418  output(i) = str_op (str[i], str2, n);
419  }
420 
421  retval = output;
422  }
423  else
424  {
425  // Must match in all dimensions.
426 
427  boolNDArray output (cell.dims (), false);
428 
429  if (cell.length () == r)
430  {
431  if (cell_val.is_cellstr ())
432  {
433  const Array<std::string> cellstr
434  = cell_val.cellstr_value ();
435  for (octave_idx_type i = 0; i < cellstr.length (); i++)
436  output(i) = str_op (str[i], cellstr(i), n);
437  }
438  else
439  {
440  // FIXME: should we warn here?
441  for (octave_idx_type i = 0; i < r; i++)
442  {
443  if (cell(i).is_string ())
444  output(i) = str_op (str[i],
445  cell(i).string_value (), n);
446  }
447  }
448 
449  retval = output;
450  }
451  else
452  retval = false;
453  }
454  }
455  }
456  else if (s1_cell && s2_cell)
457  {
458  octave_value cell1_val, cell2_val;
459  octave_idx_type r1 = arg0.numel (), r2;
460 
461  if (r1 == 1)
462  {
463  // Make the singleton cell2.
464 
465  cell1_val = arg1;
466  cell2_val = arg0;
467  }
468  else
469  {
470  cell1_val = arg0;
471  cell2_val = arg1;
472  }
473 
474  const Cell cell1 = cell1_val.cell_value ();
475  const Cell cell2 = cell2_val.cell_value ();
476  r1 = cell1.numel ();
477  r2 = cell2.numel ();
478 
479  const dim_vector size1 = cell1.dims ();
480  const dim_vector size2 = cell2.dims ();
481 
482  boolNDArray output (size1, false);
483 
484  if (r2 == 1)
485  {
486  // Broadcast cell2.
487 
488  if (cell2(0).is_string ())
489  {
490  const std::string str2 = cell2(0).string_value ();
491 
492  if (cell1_val.is_cellstr ())
493  {
494  const Array<std::string> cellstr = cell1_val.cellstr_value ();
495  for (octave_idx_type i = 0; i < cellstr.length (); i++)
496  output(i) = str_op (cellstr(i), str2, n);
497  }
498  else
499  {
500  // FIXME: should we warn here?
501  for (octave_idx_type i = 0; i < r1; i++)
502  {
503  if (cell1(i).is_string ())
504  {
505  const std::string str1 = cell1(i).string_value ();
506  output(i) = str_op (str1, str2, n);
507  }
508  }
509  }
510  }
511  }
512  else
513  {
514  if (size1 != size2)
515  {
516  error ("%s: nonconformant cell arrays", fcn_name);
517  return retval;
518  }
519 
520  if (cell1.is_cellstr () && cell2.is_cellstr ())
521  {
522  const Array<std::string> cellstr1 = cell1_val.cellstr_value ();
523  const Array<std::string> cellstr2 = cell2_val.cellstr_value ();
524  for (octave_idx_type i = 0; i < r1; i++)
525  output (i) = str_op (cellstr1(i), cellstr2(i), n);
526  }
527  else
528  {
529  // FIXME: should we warn here?
530  for (octave_idx_type i = 0; i < r1; i++)
531  {
532  if (cell1(i).is_string () && cell2(i).is_string ())
533  {
534  const std::string str1 = cell1(i).string_value ();
535  const std::string str2 = cell2(i).string_value ();
536  output(i) = str_op (str1, str2, n);
537  }
538  }
539  }
540  }
541 
542  retval = output;
543  }
544  else
545  retval = false;
546 
547  return retval;
548 }
549 
550 // If both args are arrays, dimensions may be significant.
551 static bool
553 {
554  return (s1.dims () == s2.dims ()
555  && std::equal (s1.data (), s1.data () + s1.numel (), s2.data ()));
556 }
557 
558 // Otherwise, just use strings.
559 static bool
560 strcmp_str_op (const std::string& s1, const std::string& s2,
562 {
563  return s1 == s2;
564 }
565 
566 DEFUN (strcmp, args, ,
567  "-*- texinfo -*-\n\
568 @deftypefn {Built-in Function} {} strcmp (@var{s1}, @var{s2})\n\
569 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\
570 and 0 otherwise.\n\
571 \n\
572 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
573 of the same size is returned, containing the values described above for\n\
574 every member of the cell array. The other argument may also be a cell\n\
575 array of strings (of the same size or with only one element), char matrix\n\
576 or character string.\n\
577 \n\
578 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
579 function returns 1 if the character strings are equal, and 0 otherwise.\n\
580 This is just the opposite of the corresponding C library function.\n\
581 @seealso{strcmpi, strncmp, strncmpi}\n\
582 @end deftypefn")
583 {
584  octave_value retval;
585 
586  if (args.length () == 2)
587  {
588  retval = do_strcmp_fun (args (0), args (1), 0,
589  "strcmp", strcmp_array_op, strcmp_str_op);
590  }
591  else
592  print_usage ();
593 
594  return retval;
595 }
596 
597 /*
598 %!shared x
599 %! x = char (zeros (0, 2));
600 %!assert (strcmp ("", x), false)
601 %!assert (strcmp (x, ""), false)
602 %!assert (strcmp (x, x), true)
603 ## %!assert (strcmp ({""}, x), true)
604 ## %!assert (strcmp ({x}, ""), false)
605 ## %!assert (strcmp ({x}, x), true)
606 ## %!assert (strcmp ("", {x}), false)
607 ## %!assert (strcmp (x, {""}), false)
608 ## %!assert (strcmp (x, {x}), true)
609 ## %!assert (strcmp ({x; x}, ""), [false; false])
610 ## %!assert (strcmp ({x; x}, {""}), [false; false])
611 ## %!assert (strcmp ("", {x; x}), [false; false])
612 ## %!assert (strcmp ({""}, {x; x}), [false; false])
613 %!assert (strcmp ({"foo"}, x), false)
614 %!assert (strcmp ({"foo"}, "foo"), true)
615 %!assert (strcmp ({"foo"}, x), false)
616 %!assert (strcmp (x, {"foo"}), false)
617 %!assert (strcmp ("foo", {"foo"}), true)
618 %!assert (strcmp (x, {"foo"}), false)
619 %!shared y
620 %! y = char (zeros (2, 0));
621 %!assert (strcmp ("", y), false)
622 %!assert (strcmp (y, ""), false)
623 %!assert (strcmp (y, y), true)
624 %!assert (strcmp ({""}, y), [true; true])
625 %!assert (strcmp ({y}, ""), true)
626 %!assert (strcmp ({y}, y), [true; true])
627 %!assert (strcmp ("", {y}), true)
628 %!assert (strcmp (y, {""}), [true; true])
629 %!assert (strcmp (y, {y}), [true; true])
630 %!assert (strcmp ({y; y}, ""), [true; true])
631 %!assert (strcmp ({y; y}, {""}), [true; true])
632 %!assert (strcmp ("", {y; y}), [true; true])
633 %!assert (strcmp ({""}, {y; y}), [true; true])
634 %!assert (strcmp ({"foo"}, y), [false; false])
635 %!assert (strcmp ({"foo"}, y), [false; false])
636 %!assert (strcmp (y, {"foo"}), [false; false])
637 %!assert (strcmp (y, {"foo"}), [false; false])
638 %!assert (strcmp ("foobar", "foobar"), true)
639 %!assert (strcmp ("fooba", "foobar"), false)
640 
641 %!error strcmp ()
642 %!error strcmp ("foo", "bar", 3)
643 */
644 
645 // Apparently, Matlab ignores the dims with strncmp. It also
646 static bool
648  octave_idx_type n)
649 {
650  octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
651  return (n > 0 && n <= l1 && n <= l2
652  && std::equal (s1.data (), s1.data () + n, s2.data ()));
653 }
654 
655 // Otherwise, just use strings. Note that we neither extract substrings (which
656 // would mean a copy, at least in GCC), nor use string::compare (which is a
657 // 3-way compare).
658 static bool
659 strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
660 {
661  octave_idx_type l1 = s1.length (), l2 = s2.length ();
662  return (n > 0 && n <= l1 && n <= l2
663  && std::equal (s1.data (), s1.data () + n, s2.data ()));
664 }
665 
666 DEFUN (strncmp, args, ,
667  "-*- texinfo -*-\n\
668 @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\
669 Return 1 if the first @var{n} characters of strings @var{s1} and @var{s2} are\n\
670 the same, and 0 otherwise.\n\
671 \n\
672 @example\n\
673 @group\n\
674 strncmp (\"abce\", \"abcd\", 3)\n\
675  @result{} 1\n\
676 @end group\n\
677 @end example\n\
678 \n\
679 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
680 of the same size is returned, containing the values described above for\n\
681 every member of the cell array. The other argument may also be a cell\n\
682 array of strings (of the same size or with only one element), char matrix\n\
683 or character string.\n\
684 \n\
685 @example\n\
686 @group\n\
687 strncmp (\"abce\", @{\"abcd\", \"bca\", \"abc\"@}, 3)\n\
688  @result{} [1, 0, 1]\n\
689 @end group\n\
690 @end example\n\
691 \n\
692 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmp\n\
693 function returns 1 if the character strings are equal, and 0 otherwise.\n\
694 This is just the opposite of the corresponding C library function.\n\
695 @seealso{strncmpi, strcmp, strcmpi}\n\
696 @end deftypefn")
697 {
698  octave_value retval;
699 
700  if (args.length () == 3)
701  {
702  octave_idx_type n = args(2).idx_type_value ();
703 
704  if (! error_state)
705  {
706  if (n > 0)
707  {
708  retval = do_strcmp_fun (args(0), args(1), n, "strncmp",
710  }
711  else
712  error ("strncmp: N must be greater than 0");
713  }
714  }
715  else
716  print_usage ();
717 
718  return retval;
719 }
720 
721 /*
722 %!assert (strncmp ("abce", "abc", 3), true)
723 %!assert (strncmp (100, 100, 1), false)
724 %!assert (strncmp ("abce", {"abcd", "bca", "abc"}, 3), logical ([1, 0, 1]))
725 %!assert (strncmp ("abc", {"abcd", "bca", "abc"}, 4), logical ([0, 0, 0]))
726 %!assert (strncmp ({"abcd", "bca", "abc"},"abce", 3), logical ([1, 0, 1]))
727 %!assert (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3), logical ([1, 1, 0]))
728 %!assert (strncmp ("abc", {"abcd", 10}, 2), logical ([1, 0]))
729 
730 %!error strncmp ()
731 %!error strncmp ("abc", "def")
732 */
733 
734 // case-insensitive character equality functor
735 struct icmp_char_eq : public std::binary_function<char, char, bool>
736 {
737  bool operator () (char x, char y) const
738  { return std::toupper (x) == std::toupper (y); }
739 };
740 
741 // strcmpi is equivalent to strcmp in that it checks all dims.
742 static bool
744 {
745  return (s1.dims () == s2.dims ()
746  && std::equal (s1.data (), s1.data () + s1.numel (), s2.data (),
747  icmp_char_eq ()));
748 }
749 
750 // Ditto for string.
751 static bool
752 strcmpi_str_op (const std::string& s1, const std::string& s2,
754 {
755  return (s1.size () == s2.size ()
756  && std::equal (s1.data (), s1.data () + s1.size (), s2.data (),
757  icmp_char_eq ()));
758 }
759 
760 DEFUNX ("strcmpi", Fstrcmpi, args, ,
761  "-*- texinfo -*-\n\
762 @deftypefn {Built-in Function} {} strcmpi (@var{s1}, @var{s2})\n\
763 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\
764 disregarding case of alphabetic characters, and 0 otherwise.\n\
765 \n\
766 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
767 of the same size is returned, containing the values described above for\n\
768 every member of the cell array. The other argument may also be a cell\n\
769 array of strings (of the same size or with only one element), char matrix\n\
770 or character string.\n\
771 \n\
772 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
773 function returns 1 if the character strings are equal, and 0 otherwise.\n\
774 This is just the opposite of the corresponding C library function.\n\
775 \n\
776 @strong{Caution:} National alphabets are not supported.\n\
777 @seealso{strcmp, strncmp, strncmpi}\n\
778 @end deftypefn")
779 {
780  octave_value retval;
781 
782  if (args.length () == 2)
783  {
784  retval = do_strcmp_fun (args (0), args (1), 0,
785  "strcmpi", strcmpi_array_op, strcmpi_str_op);
786  }
787  else
788  print_usage ();
789 
790  return retval;
791 }
792 
793 /*
794 %!assert (strcmpi ("abc123", "ABC123"), true)
795 */
796 
797 // Like strncmp.
798 static bool
800  octave_idx_type n)
801 {
802  octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
803  return (n > 0 && n <= l1 && n <= l2
804  && std::equal (s1.data (), s1.data () + n, s2.data (),
805  icmp_char_eq ()));
806 }
807 
808 // Ditto.
809 static bool
810 strncmpi_str_op (const std::string& s1, const std::string& s2,
811  octave_idx_type n)
812 {
813  octave_idx_type l1 = s1.length (), l2 = s2.length ();
814  return (n > 0 && n <= l1 && n <= l2
815  && std::equal (s1.data (), s1.data () + n, s2.data (),
816  icmp_char_eq ()));
817 }
818 
819 DEFUNX ("strncmpi", Fstrncmpi, args, ,
820  "-*- texinfo -*-\n\
821 @deftypefn {Built-in Function} {} strncmpi (@var{s1}, @var{s2}, @var{n})\n\
822 Return 1 if the first @var{n} character of @var{s1} and @var{s2} are the\n\
823 same, disregarding case of alphabetic characters, and 0 otherwise.\n\
824 \n\
825 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
826 of the same size is returned, containing the values described above for\n\
827 every member of the cell array. The other argument may also be a cell\n\
828 array of strings (of the same size or with only one element), char matrix\n\
829 or character string.\n\
830 \n\
831 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi\n\
832 function returns 1 if the character strings are equal, and 0 otherwise.\n\
833 This is just the opposite of the corresponding C library function.\n\
834 \n\
835 @strong{Caution:} National alphabets are not supported.\n\
836 @seealso{strncmp, strcmp, strcmpi}\n\
837 @end deftypefn")
838 {
839  octave_value retval;
840 
841  if (args.length () == 3)
842  {
843  octave_idx_type n = args(2).idx_type_value ();
844 
845  if (! error_state)
846  {
847  if (n > 0)
848  {
849  retval = do_strcmp_fun (args(0), args(1), n, "strncmpi",
851  }
852  else
853  error ("strncmpi: N must be greater than 0");
854  }
855  }
856  else
857  print_usage ();
858 
859  return retval;
860 }
861 
862 /*
863 %!assert (strncmpi ("abc123", "ABC456", 3), true)
864 */
865 
866 DEFUN (list_in_columns, args, ,
867  "-*- texinfo -*-\n\
868 @deftypefn {Built-in Function} {} list_in_columns (@var{arg}, @var{width}, @var{prefix})\n\
869 Return a string containing the elements of @var{arg} listed in\n\
870 columns with an overall maximum width of @var{width} and optional\n\
871 prefix @var{prefix}. The argument @var{arg} must be a cell array\n\
872 of character strings or a character array. If @var{width} is not\n\
873 specified or is an empty matrix, or less than or equal to zero,\n\
874 the width of the terminal screen is used.\n\
875 Newline characters are used to break the lines in the output string.\n\
876 For example:\n\
877 @c Set example in small font to prevent overfull line\n\
878 \n\
879 @smallexample\n\
880 @group\n\
881 list_in_columns (@{\"abc\", \"def\", \"ghijkl\", \"mnop\", \"qrs\", \"tuv\"@}, 20)\n\
882  @result{} abc mnop\n\
883  def qrs\n\
884  ghijkl tuv\n\
885 \n\
886 whos ans\n\
887  @result{}\n\
888  Variables in the current scope:\n\
889 \n\
890  Attr Name Size Bytes Class\n\
891  ==== ==== ==== ===== =====\n\
892  ans 1x37 37 char\n\
893 \n\
894  Total is 37 elements using 37 bytes\n\
895 @end group\n\
896 @end smallexample\n\
897 \n\
898 @seealso{terminal_size}\n\
899 @end deftypefn")
900 {
901  octave_value retval;
902 
903  int nargin = args.length ();
904 
905  if (nargin < 1 || nargin > 3)
906  {
907  print_usage ();
908  return retval;
909  }
910 
911  string_vector s = args(0).all_strings ();
912 
913  if (error_state)
914  {
915  error ("list_in_columns: expecting cellstr or char array");
916  return retval;
917  }
918 
919  int width = -1;
920 
921  if (nargin > 1 && ! args(1).is_empty ())
922  {
923  width = args(1).int_value ();
924 
925  if (error_state)
926  {
927  error ("list_in_columns: WIDTH must be an integer");
928  return retval;
929  }
930  }
931 
932  std::string prefix;
933 
934  if (nargin > 2)
935  {
936  if (args(2).is_string ())
937  {
938  prefix = args(2).string_value ();
939 
940  if (error_state)
941  {
942  error ("list_in_columns: PREFIX must be a character string");
943  return retval;
944  }
945  }
946  else
947  {
948  error ("list_in_columns: PREFIX must be a character string");
949  return retval;
950  }
951  }
952 
953  std::ostringstream buf;
954 
955  s.list_in_columns (buf, width, prefix);
956 
957  retval = buf.str ();
958 
959  return retval;
960 }
961 
962 /*
963 %!test
964 %! input = {"abc", "def", "ghijkl", "mnop", "qrs", "tuv"};
965 %! result = "abc mnop\ndef qrs\nghijkl tuv\n";
966 %! assert (list_in_columns (input, 20), result);
967 %!test
968 %! input = ["abc"; "def"; "ghijkl"; "mnop"; "qrs"; "tuv"];
969 %! result = "abc mnop \ndef qrs \nghijkl tuv \n";
970 %! assert (list_in_columns (input, 20), result);
971 %!test
972 %! input = ["abc"; "def"; "ghijkl"; "mnop"; "qrs"; "tuv"];
973 %! result = " abc mnop \n def qrs \n ghijkl tuv \n";
974 %! assert (list_in_columns (input, 20, " "), result);
975 
976 %!error list_in_columns ()
977 %!error list_in_columns (["abc", "def"], 20, 2)
978 %!error list_in_columns (["abc", "def"], 20, " ", 3)
979 %!error <invalid conversion from string to real scalar> list_in_columns (["abc", "def"], "a")
980 */