GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
utils.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cerrno>
31 #include <cstring>
32 
33 #include <fstream>
34 #include <limits>
35 #include <ostream>
36 #include <string>
37 
38 #include "dir-ops.h"
39 #include "file-ops.h"
40 #include "file-stat.h"
41 #include "lo-mappers.h"
42 #include "lo-utils.h"
43 #include "nanosleep-wrapper.h"
44 #include "oct-cmplx.h"
45 #include "oct-env.h"
46 #include "oct-locbuf.h"
47 #include "oct-string.h"
48 #include "pathsearch.h"
49 #include "quit.h"
50 #include "str-vec.h"
51 #include "strcase-wrappers.h"
52 #include "vasprintf-wrapper.h"
53 
54 #include "Cell.h"
55 #include "defun.h"
56 #include "error.h"
57 #include "errwarn.h"
58 #include "graphics.h"
59 #include "interpreter-private.h"
60 #include "interpreter.h"
61 #include "lex.h"
62 #include "load-path.h"
63 #include "oct-errno.h"
64 #include "oct-hist.h"
65 #include "ovl.h"
66 #include "ov-range.h"
67 #include "pager.h"
68 #include "parse.h"
69 #include "sysdep.h"
70 #include "unwind-prot.h"
71 #include "utils.h"
72 #include "variables.h"
73 
75 
76 // Return TRUE if S is a valid identifier.
77 
78 bool valid_identifier (const char *s)
79 {
80  if (! s || ! (isalpha (*s) || *s == '_'))
81  return false;
82 
83  while (*++s != '\0')
84  if (! (isalnum (*s) || *s == '_'))
85  return false;
86 
87  return true;
88 }
89 
90 bool valid_identifier (const std::string& s)
91 {
92  return valid_identifier (s.c_str ());
93 }
94 
95 DEFUN (isvarname, args, ,
96  doc: /* -*- texinfo -*-
97 @deftypefn {} {@var{tf} =} isvarname (@var{name})
98 Return true if @var{name} is a valid variable name.
99 
100 A valid variable name is composed of letters, digits, and underscores ("_"),
101 and the first character must not be a digit.
102 @seealso{iskeyword, exist, who}
103 @end deftypefn */)
104 {
105  if (args.length () != 1)
106  print_usage ();
107 
108  octave_value retval = false;
109 
110  if (args(0).is_string ())
111  {
112  std::string varname = args(0).string_value ();
113 
114  retval = (valid_identifier (varname)
115  && ! iskeyword (varname));
116  }
117 
118  return retval;
119 }
120 
121 /*
122 %!assert (isvarname ("foo"), true)
123 %!assert (isvarname ("_foo"), true)
124 %!assert (isvarname ("_1"), true)
125 %!assert (isvarname ("1foo"), false)
126 %!assert (isvarname (""), false)
127 %!assert (isvarname (12), false)
128 %!assert (isvarname ("foo+bar"), false)
129 
130 %!error isvarname ()
131 %!error isvarname ("foo", "bar")
132 */
133 
134 bool
135 make_valid_name (std::string& str, const make_valid_name_options& options)
136 {
137  // If `isvarname (str)`, no modifications necessary.
138  if (valid_identifier (str) && ! iskeyword (str))
139  return false;
140 
141  // Change whitespace followed by lowercase letter to uppercase, except
142  // for the first
143  bool previous = false;
144  bool any_non_space = false;
145  for (char& c : str)
146  {
147  c = ((any_non_space && previous && std::isalpha (c)) ? std::toupper (c)
148  : c);
149  previous = std::isspace (c);
150  any_non_space |= (! previous); // once true, always true
151  }
152 
153  // Remove any whitespace.
154  str.erase (std::remove_if (str.begin(), str.end(),
155  [] (unsigned char x)
156  { return std::isspace(x); }),
157  str.end());
158  if (str.empty ())
159  str = options.get_prefix ();
160 
161  // Add prefix and capitalize first character, if `str` is a reserved
162  // keyword.
163  if (iskeyword (str))
164  {
165  str[0] = std::toupper (str[0]);
166  str = options.get_prefix () + str;
167  }
168 
169  // Add prefix if first character is not a letter or underscore.
170  if (! std::isalpha (str[0]) && str[0] != '_')
171  str = options.get_prefix () + str;
172 
173  // Replace non alphanumerics or underscores
174  if (options.get_replacement_style () == "underscore")
175  for (char& c : str)
176  c = (std::isalnum (c) ? c : '_');
177  else if (options.get_replacement_style () == "delete")
178  str.erase (std::remove_if (str.begin(), str.end(),
179  [] (unsigned char x)
180  { return ! std::isalnum (x) && x != '_'; }),
181  str.end());
182  else if (options.get_replacement_style () == "hex")
183  {
184  const std::string permitted_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
185  "abcdefghijklmnopqrstuvwxyz"
186  "_0123456789";
187  // Get the first non-permitted char.
188  std::size_t pos = str.find_first_not_of (permitted_chars);
189  // Buffer for hex string "0xFF" (+1 for null terminator).
190  char hex_str[5];
191  // Repeat until end of string.
192  while (pos != std::string::npos)
193  {
194  // Replace non-permitted char by it's hex value.
195  std::snprintf (hex_str, sizeof (hex_str), "0x%02X", str[pos]);
196  str.replace (pos, 1, hex_str);
197  // Get the next occurrence from the last position.
198  // (-1 for null terminator)
199  pos = str.find_first_not_of (permitted_chars,
200  pos + sizeof (hex_str) - 1);
201  }
202  }
203 
204  return true;
205 }
206 
208 (const octave_value_list& args)
209 {
210  auto nargs = args.length ();
211  if (nargs == 0)
212  return;
213 
214  // nargs = 2, 4, 6, ... permitted
215  if (nargs % 2)
216  error ("makeValidName: property/value options must occur in pairs");
217 
218  auto str_to_lower = [] (std::string& s)
219  {
220  std::transform (s.begin(), s.end(), s.begin(),
221  [] (unsigned char c)
222  { return std::tolower(c); });
223  };
224 
225  for (auto i = 0; i < nargs; i = i + 2)
226  {
227  std::string parameter = args(i).xstring_value ("makeValidName: "
228  "option argument must be a string");
229  str_to_lower (parameter);
230  if (parameter == "replacementstyle")
231  {
232  m_replacement_style = args(i + 1).xstring_value ("makeValidName: "
233  "'ReplacementStyle' value must be a string");
234  str_to_lower (m_replacement_style);
235  if ((m_replacement_style != "underscore")
236  && (m_replacement_style != "delete")
237  && (m_replacement_style != "hex"))
238  error ("makeValidName: invalid 'ReplacementStyle' value '%s'",
239  m_replacement_style.c_str ());
240  }
241  else if (parameter == "prefix")
242  {
243  m_prefix = args(i + 1).xstring_value ("makeValidName: "
244  "'Prefix' value must be a string");
245  if (! valid_identifier (m_prefix)
246  || iskeyword (m_prefix))
247  error ("makeValidName: invalid 'Prefix' value '%s'",
248  m_prefix.c_str ());
249  }
250  else
251  error ("makeValidName: unknown property '%s'", parameter.c_str ());
252  }
253 }
254 
255 DEFUN (__make_valid_name__, args, ,
256  doc: /* -*- texinfo -*-
257 @deftypefn {} {@var{varname} =} __make_valid_name__ (@var{str})
258 @deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"})
259 @deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"}, @qcode{"Prefix"})
260 @deftypefnx {} {[@var{varname}, @var{ismodified}] =} __make_valid_name__ (@dots{})
261 Return a valid variable name @var{varname} from input @var{str}.
262 
263 For more documentation, see @code{matlab.lang.makeValidName}.
264 
265 @seealso{isvarname, matlab.lang.makeValidName}
266 @end deftypefn */)
267 {
268  auto nargin = args.length ();
269  if (nargin < 1)
270  print_usage ();
271 
272  make_valid_name_options options (args.slice (1, nargin - 1));
273 
274  if (args(0).is_string ())
275  {
276  std::string varname = args(0).string_value ();
277  bool is_modified = make_valid_name (varname, options);
278  return ovl (varname, is_modified);
279  }
280  else if (args(0).iscellstr ())
281  {
282  Array<std::string> varnames = args(0).cellstr_value ();
283  Array<bool> is_modified (varnames.dims ());
284  for (auto i = 0; i < varnames.numel (); i++)
285  is_modified(i) = make_valid_name (varnames(i), options);
286  return ovl (varnames, is_modified);
287  }
288  else
289  error ("makeValidName: STR must be a string or cellstr");
290 }
291 
292 // Return TRUE if F and G are both names for the same file.
293 
294 bool same_file (const std::string& f, const std::string& g)
295 {
296  return same_file_internal (f, g);
297 }
298 
299 DEFUN (is_same_file, args, ,
300  doc: /* -*- texinfo -*-
301 @deftypefn {} {@var{same} =} is_same_file (@var{filepath1}, @var{filepath2})
302 Return true if @var{filepath1} and @var{filepath2} refer to the same file.
303 
304 If either @var{filepath1} or @var{filepath2} is a cell array of strings, then
305 an array of the same size is returned, containing the values described above
306 for every member of the cell array. The other argument may also be a cell
307 array of strings (of the same size) or a string.
308 
309 Programming Notes: Depending on the operating system and file system, the same
310 file or folder can be referred to with different paths. In particular, paths
311 on the Windows platform may differ in case (@file{file1} vs.@: @file {FILE1}),
312 file separator (@samp{\} vs.@: @samp{/}), and format (@file{A~spaces.txt} (8.3
313 convention) vs.@: @file{A filename with spaces.txt}). This function returns
314 true if the paths in @var{filepath1} and @var{filepath2} actually refer to the
315 same file or folder, and false otherwise.
316 
317 Note that unlike @code{strcmp}, this function requires that @var{filepath1}
318 and @var{filepath2} exist, as well as point to the same location, in order to
319 return true.
320 
321 @seealso{canonicalize_file_name, strcmp}
322 @end deftypefn */)
323 {
324  if (args.length () != 2)
325  print_usage ();
326 
327  octave_value retval;
328 
329  bool s1_string = args(0).is_string ();
330  bool s1_cellstr = args(0).iscellstr ();
331  bool s2_string = args(1).is_string ();
332  bool s2_cellstr = args(1).iscellstr ();
333 
334  if (s1_string && s2_string)
335  {
336  std::string file1 = args(0).string_value ();
337  std::string file2 = args(1).string_value ();
338 
339  retval = same_file (file1, file2);
340  }
341  else if ((s1_string && s2_cellstr) || (s1_cellstr && s2_string))
342  {
343  octave_value str_arg, cellstr_arg;
344 
345  if (s1_string)
346  {
347  str_arg = args(0);
348  cellstr_arg = args(1);
349  }
350  else
351  {
352  str_arg = args(1);
353  cellstr_arg = args(0);
354  }
355 
356  const Array<std::string> cellstr = cellstr_arg.cellstr_value ();
357  const std::string str = str_arg.string_value ();
358 
359  boolNDArray output (cellstr.dims (), false);
360 
361  for (octave_idx_type idx = 0; idx < cellstr.numel (); idx++)
362  output(idx) = same_file (str, cellstr(idx));
363 
364  retval = output;
365  }
366  else if (s1_cellstr && s2_cellstr)
367  {
368  const Array<std::string> cellstr1 = args(0).cellstr_value ();
369  const Array<std::string> cellstr2 = args(1).cellstr_value ();
370 
371  const dim_vector size1 = cellstr1.dims ();
372  const dim_vector size2 = cellstr2.dims ();
373 
374  if (size1 != size2)
375  error ("is_same_file: cellstr arrays FILEPATH1 and FILEPATH2 must be the same size");
376 
377  boolNDArray output (size1, false);
378 
379  for (octave_idx_type idx = 0; idx < cellstr1.numel (); idx++)
380  output(idx) = same_file (cellstr1(idx), cellstr2(idx));
381 
382  retval = output;
383  }
384  else
385  error ("is_same_file: FILEPATH1 and FILEPATH2 must be strings or cell arrays of strings");
386 
387  return retval;
388 }
389 
390 /*
391 %!testif ; ! ispc ()
392 %! assert (is_same_file ("~", tilde_expand ("~")));
393 %!testif ; ispc ()
394 %! assert (is_same_file (tolower (tempdir ()), toupper (tempdir ())), true);
395 %!assert (is_same_file ({pwd(), ".", tempdir()}, canonicalize_file_name (".")),
396 %! [true, true, false])
397 
398 %!error is_same_file ()
399 %!error is_same_file ("foo")
400 %!error is_same_file ("foo", "bar", "baz")
401 %!error <must be strings or cell arrays of strings> is_same_file ("foo", 1)
402 %!error <must be strings or cell arrays of strings> is_same_file (1, "foo")
403 %!error <must be strings or cell arrays of strings> is_same_file ("foo", {1})
404 %!error <must be strings or cell arrays of strings> is_same_file ({1}, "foo")
405 %!error <arrays .* must be the same size> is_same_file ({"1", "2"}, {"1"; "2"})
406 */
407 
408 int almost_match (const std::string& std, const std::string& s,
409  int min_match_len, int case_sens)
410 {
411  int stdlen = std.length ();
412  int slen = s.length ();
413 
414  return (slen <= stdlen
415  && slen >= min_match_len
416  && (case_sens
417  ? (strncmp (std.c_str (), s.c_str (), slen) == 0)
418  : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0)));
419 }
420 
421 // Ugh.
422 
423 int keyword_almost_match (const char *const *std, int *min_len,
424  const std::string& s,
425  int min_toks_to_match, int max_toks)
426 {
427  int status = 0;
428  int tok_count = 0;
429  int toks_matched = 0;
430 
431  if (s.empty () || max_toks < 1)
432  return status;
433 
434  char *kw = strsave (s.c_str ());
435 
436  char *t = kw;
437  while (*t != '\0')
438  {
439  if (*t == '\t')
440  *t = ' ';
441  t++;
442  }
443 
444  char *beg = kw;
445  while (*beg == ' ')
446  beg++;
447 
448  if (*beg == '\0')
449  return status;
450 
451  const char **to_match = new const char *[max_toks + 1];
452  const char *const *s1 = std;
453  const char **s2 = to_match;
454 
455  if (! s1 || ! s2)
456  goto done;
457 
458  s2[tok_count] = beg;
459  char *end;
460  while ((end = strchr (beg, ' ')) != nullptr)
461  {
462  *end = '\0';
463  beg = end + 1;
464 
465  while (*beg == ' ')
466  beg++;
467 
468  if (*beg == '\0')
469  break;
470 
471  tok_count++;
472  if (tok_count >= max_toks)
473  goto done;
474 
475  s2[tok_count] = beg;
476  }
477  s2[tok_count+1] = nullptr;
478 
479  s2 = to_match;
480 
481  for (;;)
482  {
483  if (! almost_match (*s1, *s2, min_len[toks_matched], 0))
484  goto done;
485 
486  toks_matched++;
487 
488  s1++;
489  s2++;
490 
491  if (! *s2)
492  {
493  status = (toks_matched >= min_toks_to_match);
494  goto done;
495  }
496 
497  if (! *s1)
498  goto done;
499  }
500 
501 done:
502 
503  delete [] kw;
504  delete [] to_match;
505 
506  return status;
507 }
508 
509 // See if the given file is in the path.
510 
511 std::string search_path_for_file (const std::string& path,
512  const string_vector& names)
513 {
514  directory_path p (path);
515 
516  return sys::env::make_absolute (p.find_first_of (names.std_list ()));
517 }
518 
519 // Find all locations of the given file in the path.
520 
521 string_vector search_path_for_all_files (const std::string& path,
522  const string_vector& names)
523 {
524  directory_path p (path);
525 
526  string_vector sv = p.find_all_first_of (names.std_list ());
527 
528  octave_idx_type len = sv.numel ();
529 
530  for (octave_idx_type i = 0; i < len; i++)
531  sv[i] = sys::env::make_absolute (sv[i]);
532 
533  return sv;
534 }
535 
537 {
538  octave_idx_type len = sv.numel ();
539 
540  string_vector retval (len);
541 
542  for (octave_idx_type i = 0; i < len; i++)
543  retval[i] = sys::env::make_absolute (sv[i]);
544 
545  return retval;
546 }
547 
548 DEFMETHOD (file_in_loadpath, interp, args, ,
549  doc: /* -*- texinfo -*-
550 @deftypefn {} {@var{fname} =} file_in_loadpath (@var{file})
551 @deftypefnx {} {@var{fname} =} file_in_loadpath (@var{file}, "all")
552 Return the absolute name of @var{file} if it can be found in the list of
553 directories specified by @code{path}.
554 
555 If no file is found, return an empty character string.
556 
557 When @var{file} is already an absolute name, the name is checked against the
558 file system instead of Octave's loadpath. In this case, if @var{file} exists
559 it will be returned in @var{fname}, otherwise an empty string is returned.
560 
561 If the first argument is a cell array of strings, search each directory of
562 the loadpath for element of the cell array and return the first that
563 matches.
564 
565 If the second optional argument @qcode{"all"} is supplied, return a cell
566 array containing the list of all files that have the same name in the path.
567 If no files are found, return an empty cell array.
568 @seealso{file_in_path, dir_in_loadpath, path}
569 @end deftypefn */)
570 {
571  int nargin = args.length ();
572 
573  if (nargin < 1 || nargin > 2)
574  print_usage ();
575 
576  string_vector names = args(
577  0).xstring_vector_value ("file_in_loadpath: FILE argument must be a string");
578 
579  if (names.empty ())
580  error ("file_in_loadpath: FILE argument must not be empty");
581 
582  load_path& lp = interp.get_load_path ();
583 
584  if (nargin == 1)
585  return ovl (sys::env::make_absolute (lp.find_first_of (names)));
586  else
587  {
588  std::string opt = args(
589  1).xstring_value ("file_in_loadpath: optional second argument must be a string");
590 
591  if (opt != "all")
592  error (R"(file_in_loadpath: "all" is only valid second argument)");
593 
594  return ovl (Cell (make_absolute (lp.find_all_first_of (names))));
595  }
596 }
597 
598 /*
599 %!test
600 %! f = file_in_loadpath ("plot.m");
601 %! assert (ischar (f));
602 %! assert (! isempty (f));
603 
604 %!test
605 %! f = file_in_loadpath ("$$probably_!! _not_&&_a_!! _file$$");
606 %! assert (f, "");
607 
608 %!test
609 %! lst = file_in_loadpath ("$$probably_!! _not_&&_a_!! _file$$", "all");
610 %! assert (lst, {});
611 
612 %!error file_in_loadpath ()
613 %!error file_in_loadpath ("foo", "bar", 1)
614 %!error file_in_loadpath ([])
615 %!error file_in_loadpath ("plot.m", "bar")
616 */
617 
618 DEFUN (file_in_path, args, ,
619  doc: /* -*- texinfo -*-
620 @deftypefn {} {@var{fname} =} file_in_path (@var{path}, @var{file})
621 @deftypefnx {} {@var{fname} =} file_in_path (@var{path}, @var{file}, "all")
622 Return the absolute name of @var{file} if it can be found in @var{path}.
623 
624 The value of @var{path} should be a colon-separated list of directories in
625 the format described for @code{path}. If no file is found, return an empty
626 character string. For example:
627 
628 @example
629 @group
630 file_in_path (EXEC_PATH, "sh")
631  @result{} "/bin/sh"
632 @end group
633 @end example
634 
635 If the second argument is a cell array of strings, search each directory of
636 the path for element of the cell array and return the first that matches.
637 
638 If the third optional argument @qcode{"all"} is supplied, return a cell
639 array containing the list of all files that have the same name in the path.
640 If no files are found, return an empty cell array.
641 @seealso{file_in_loadpath, dir_in_loadpath, path}
642 @end deftypefn */)
643 {
644  int nargin = args.length ();
645 
646  if (nargin < 2 || nargin > 3)
647  print_usage ();
648 
649  std::string path = args(0).xstring_value ("file_in_path: PATH must be a string");
650 
651  string_vector names = args(1).xstring_vector_value ("file_in_path: FILE argument must be a string");
652 
653  if (names.empty ())
654  error ("file_in_path: FILE argument must not be empty");
655 
656  if (nargin == 2)
657  return ovl (search_path_for_file (path, names));
658  else
659  {
660  std::string opt = args(2).xstring_value ("file_in_path: optional third argument must be a string");
661 
662  if (opt != "all")
663  error (R"(file_in_path: "all" is only valid third argument)");
664 
665  return ovl (Cell (make_absolute (search_path_for_all_files (path, names))));
666  }
667 }
668 
669 /*
670 %!test
671 %! f = file_in_path (path (), "plot.m");
672 %! assert (ischar (f));
673 %! assert (! isempty (f));
674 
675 %!test
676 %! f = file_in_path (path (), "$$probably_!! _not_&&_a_!! _file$$");
677 %! assert (f, "");
678 
679 %!test
680 %! lst = file_in_path (path (), "$$probably_!! _not_&&_a_!! _file$$", "all");
681 %! assert (lst, {});
682 
683 %!error file_in_path ()
684 %!error file_in_path ("foo")
685 %!error file_in_path ("foo", "bar", "baz", 1)
686 %!error file_in_path ([])
687 %!error file_in_path (path (), [])
688 %!error file_in_path (path (), "plot.m", "bar")
689 */
690 
691 std::string file_in_path (const std::string& name, const std::string& suffix)
692 {
693  std::string nm = name;
694 
695  if (! suffix.empty ())
696  nm.append (suffix);
697 
698  load_path& lp = __get_load_path__ ();
699 
700  return sys::env::make_absolute (lp.find_file (nm));
701 }
702 
703 std::string find_data_file_in_load_path (const std::string& fcn,
704  const std::string& file,
705  bool require_regular_file)
706 {
707  std::string fname = file;
708 
709  if (! (sys::env::absolute_pathname (fname)
710  || sys::env::rooted_relative_pathname (fname)))
711  {
712  // Load path will also search "." first, but we don't want to
713  // issue a warning if the file is found in the current directory,
714  // so do an explicit check for that.
715  sys::file_stat fs (fname);
716 
717  bool local_file_ok
718  = fs.exists () && (fs.is_reg () || ! require_regular_file);
719 
720  if (! local_file_ok)
721  {
722  load_path& lp = __get_load_path__ ();
723 
724  // Not directly found; search load path.
725  std::string tmp = sys::env::make_absolute (lp.find_file (fname));
726 
727  if (! tmp.empty ())
728  {
729  warn_data_file_in_path (fcn, tmp);
730 
731  fname = tmp;
732  }
733  }
734  }
735 
736  return fname;
737 }
738 
739 // See if there is an function file in the path.
740 // If so, return the full path to the file.
741 
742 std::string fcn_file_in_path (const std::string& name)
743 {
744  std::string retval;
745 
746  int len = name.length ();
747 
748  if (len > 0)
749  {
750  if (sys::env::absolute_pathname (name))
751  {
752  sys::file_stat fs (name);
753 
754  if (fs.exists () && ! fs.is_dir ())
755  retval = name;
756  }
757  else if (len > 2 && name[len - 2] == '.' && name[len - 1] == 'm')
758  {
759  load_path& lp = __get_load_path__ ();
760 
761  retval = lp.find_fcn_file (name.substr (0, len-2));
762  }
763  else
764  {
765  std::string fname = name;
766  std::size_t pos = name.find_first_of ('>');
767  if (pos != std::string::npos)
768  fname = name.substr (0, pos);
769 
770  load_path& lp = __get_load_path__ ();
771 
772  retval = lp.find_fcn_file (fname);
773  }
774  }
775 
776  return retval;
777 }
778 
779 // See if there is a directory called "name" in the path and if it
780 // contains a Contents.m file. If so, return the full path to this file.
781 
782 std::string contents_file_in_path (const std::string& dir)
783 {
784  std::string retval;
785 
786  if (! dir.empty ())
787  {
788  load_path& lp = __get_load_path__ ();
789 
790  std::string tcontents
791  = sys::file_ops::concat (lp.find_dir (dir), "Contents.m");
792 
793  sys::file_stat fs (tcontents);
794 
795  if (fs.exists ())
796  retval = sys::env::make_absolute (tcontents);
797  }
798 
799  return retval;
800 }
801 
802 // Replace backslash escapes in a string with the real values.
803 
804 std::string do_string_escapes (const std::string& s)
805 {
806  std::string retval;
807 
808  std::size_t i = 0;
809  std::size_t j = 0;
810  std::size_t len = s.length ();
811 
812  retval.resize (len);
813 
814  while (j < len)
815  {
816  if (s[j] == '\\' && j+1 < len)
817  {
818  switch (s[++j])
819  {
820  case 'a': // alarm
821  retval[i] = '\a';
822  break;
823 
824  case 'b': // backspace
825  retval[i] = '\b';
826  break;
827 
828  case 'f': // formfeed
829  retval[i] = '\f';
830  break;
831 
832  case 'n': // newline
833  retval[i] = '\n';
834  break;
835 
836  case 'r': // carriage return
837  retval[i] = '\r';
838  break;
839 
840  case 't': // horizontal tab
841  retval[i] = '\t';
842  break;
843 
844  case 'v': // vertical tab
845  retval[i] = '\v';
846  break;
847 
848  case '\\': // backslash
849  retval[i] = '\\';
850  break;
851 
852  case '\'': // quote
853  retval[i] = '\'';
854  break;
855 
856  case '"': // double quote
857  retval[i] = '"';
858  break;
859 
860  case '0':
861  case '1':
862  case '2':
863  case '3':
864  case '4':
865  case '5':
866  case '6':
867  case '7': // octal input
868  {
869  std::size_t k;
870  int tmpi = s[j] - '0';
871  for (k = j+1; k < std::min (j+3, len); k++)
872  {
873  int digit = s[k] - '0';
874  if (digit < 0 || digit > 7)
875  break;
876  tmpi <<= 3;
877  tmpi += digit;
878  }
879  retval[i] = tmpi;
880  j = k - 1;
881  break;
882  }
883 
884  case 'x': // hex input
885  {
886  std::size_t k;
887  int tmpi = 0;
888  for (k = j+1; k < std::min (j+3, len); k++)
889  {
890  if (! isxdigit (s[k]))
891  break;
892 
893  tmpi <<= 4;
894  int digit = s[k];
895  if (digit >= 'a')
896  tmpi += digit - 'a' + 10;
897  else if (digit >= 'A')
898  tmpi += digit - 'A' + 10;
899  else
900  tmpi += digit - '0';
901  }
902 
903  if (k == j+1)
904  warning (R"(malformed hex escape sequence '\x' -- converting to '\0')");
905 
906  retval[i] = tmpi;
907  j = k - 1;
908  break;
909  }
910 
911  default:
912  warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]);
913  retval[i] = s[j];
914  break;
915  }
916  }
917  else
918  retval[i] = s[j];
919 
920  i++;
921  j++;
922  }
923 
924  retval.resize (i);
925 
926  return retval;
927 }
928 
929 DEFUN (do_string_escapes, args, ,
930  doc: /* -*- texinfo -*-
931 @deftypefn {} {@var{newstr} =} do_string_escapes (@var{string})
932 Convert escape sequences in @var{string} to the characters they represent.
933 
934 Escape sequences begin with a leading backslash
935 (@qcode{'@backslashchar{}'}) followed by 1--3 characters
936 (.e.g., @qcode{"@backslashchar{}n"} => newline).
937 @seealso{undo_string_escapes}
938 @end deftypefn */)
939 {
940  if (args.length () != 1)
941  print_usage ();
942 
943  std::string str = args(
944  0).xstring_value ("do_string_escapes: STRING argument must be of type string");
945 
946  return ovl (do_string_escapes (str));
947 }
948 
949 /*
950 %!assert (do_string_escapes ('foo\nbar'), "foo\nbar")
951 %!assert (do_string_escapes ("foo\\nbar"), "foo\nbar")
952 %!assert (do_string_escapes ("foo\\nbar"), ["foo", char(10), "bar"])
953 %!assert ("foo\nbar", ["foo", char(10), "bar"])
954 
955 %!assert (do_string_escapes ('\0\a\b\f\n\r\t\v'), "\0\a\b\f\n\r\t\v")
956 %!assert (do_string_escapes ("\\0\\a\\b\\f\\n\\r\\t\\v"), "\0\a\b\f\n\r\t\v")
957 %!assert (do_string_escapes ("\\0\\a\\b\\f\\n\\r\\t\\v"),
958 %! char ([0, 7, 8, 12, 10, 13, 9, 11]))
959 %!assert ("\0\a\b\f\n\r\t\v", char ([0, 7, 8, 12, 10, 13, 9, 11]))
960 
961 %!assert (do_string_escapes ('\\'), "\\")
962 %!assert (do_string_escapes ("\\\\"), "\\")
963 %!assert (do_string_escapes ("\\\\"), char (92))
964 
965 %!assert (do_string_escapes ('\''single-quoted\'''), "'single-quoted'")
966 %!assert (do_string_escapes ("\\'single-quoted\\'"), "'single-quoted'")
967 %!assert (do_string_escapes ('\"double-quoted\"'), "\"double-quoted\"")
968 %!assert (do_string_escapes ("\\\"double-quoted\\\""), "\"double-quoted\"")
969 
970 %!assert (do_string_escapes ('A\4B'), ["A" char(4) "B"])
971 %!assert (do_string_escapes ('A\45B'), ["A" char(37) "B"])
972 %!assert (do_string_escapes ('A\123B'), ["A" char(83) "B"])
973 %!assert (sprintf ('\117\143\164\141\166\145'), "Octave")
974 
975 %!assert (do_string_escapes ('A\x4G'), ["A" char(4) "G"])
976 %!assert (do_string_escapes ('A\x4AG'), ["A" char(74) "G"])
977 %!assert (sprintf ('\x4f\x63\x74\x61\x76\x65'), "Octave")
978 
979 %!error do_string_escapes ()
980 %!error do_string_escapes ("foo", "bar")
981 %!error <STRING argument> do_string_escapes (3)
982 %!warning <malformed hex escape sequence> do_string_escapes ('\xG');
983 %!warning <unrecognized escape sequence> do_string_escapes ('\G');
984 */
985 
986 const char * undo_string_escape (char c)
987 {
988  if (! c)
989  return "";
990 
991  switch (c)
992  {
993  case '\0':
994  return R"(\0)";
995 
996  case '\a':
997  return R"(\a)";
998 
999  case '\b': // backspace
1000  return R"(\b)";
1001 
1002  case '\f': // formfeed
1003  return R"(\f)";
1004 
1005  case '\n': // newline
1006  return R"(\n)";
1007 
1008  case '\r': // carriage return
1009  return R"(\r)";
1010 
1011  case '\t': // horizontal tab
1012  return R"(\t)";
1013 
1014  case '\v': // vertical tab
1015  return R"(\v)";
1016 
1017  case '\\': // backslash
1018  return R"(\\)";
1019 
1020  case '"': // double quote
1021  return R"(\")";
1022 
1023  default:
1024  {
1025  static char retval[2] {'\0', '\0'};
1026 
1027  retval[0] = c;
1028  return retval;
1029  }
1030  }
1031 }
1032 
1033 std::string undo_string_escapes (const std::string& s)
1034 {
1035  std::string retval;
1036 
1037  for (std::size_t i = 0; i < s.length (); i++)
1038  retval.append (undo_string_escape (s[i]));
1039 
1040  return retval;
1041 }
1042 
1043 DEFUN (undo_string_escapes, args, ,
1044  doc: /* -*- texinfo -*-
1045 @deftypefn {} {@var{newstr} =} undo_string_escapes (@var{string})
1046 Convert special characters in @var{string} back to their escaped forms.
1047 
1048 For example, the expression
1049 
1050 @example
1051 @var{bell} = "\a";
1052 @end example
1053 
1054 @noindent
1055 assigns the value of the alert character (control-g, ASCII code 7) to the
1056 string variable @code{bell}. If this string is printed, the system will
1057 ring the terminal bell (if it is possible). This is normally the desired
1058 outcome. However, sometimes it is useful to be able to print the original
1059 representation of the string, with the special characters replaced by their
1060 escape sequences. For example,
1061 
1062 @example
1063 @group
1064 octave:13> undo_string_escapes (bell)
1065 ans = \a
1066 @end group
1067 @end example
1068 
1069 @noindent
1070 replaces the unprintable alert character with its printable representation.
1071 @seealso{do_string_escapes}
1072 @end deftypefn */)
1073 {
1074  if (args.length () != 1)
1075  print_usage ();
1076 
1077  std::string str = args(0).xstring_value ("undo_string_escapes: STRING argument must be a string");
1078 
1079  return ovl (undo_string_escapes (str));
1080 }
1081 
1082 /*
1083 %!assert (undo_string_escapes ("foo\nbar"), 'foo\nbar')
1084 %!assert (undo_string_escapes ("foo\nbar"), "foo\\nbar")
1085 %!assert (undo_string_escapes (["foo", char(10), "bar"]), "foo\\nbar")
1086 
1087 %!assert (undo_string_escapes ("\a\b\f\n\r\t\v"), '\a\b\f\n\r\t\v')
1088 %!assert (undo_string_escapes ("\a\b\f\n\r\t\v"), "\\a\\b\\f\\n\\r\\t\\v")
1089 %!assert (undo_string_escapes (char ([7, 8, 12, 10, 13, 9, 11])),
1090 %! "\\a\\b\\f\\n\\r\\t\\v")
1091 
1092 %!assert (undo_string_escapes ("\\"), '\\')
1093 %!assert (undo_string_escapes ("\\"), "\\\\")
1094 %!assert (undo_string_escapes (char (92)), "\\\\")
1095 
1096 %!assert (undo_string_escapes ("\"double-quoted\""), '\"double-quoted\"')
1097 %!assert (undo_string_escapes ("\"double-quoted\""), "\\\"double-quoted\\\"")
1098 
1099 %!error undo_string_escapes ()
1100 %!error undo_string_escapes ("foo", "bar")
1101 %!error undo_string_escapes (3)
1102 */
1103 
1104 DEFUN (is_absolute_filename, args, ,
1105  doc: /* -*- texinfo -*-
1106 @deftypefn {} {@var{tf} =} is_absolute_filename (@var{file})
1107 Return true if @var{file} is an absolute filename.
1108 @seealso{is_rooted_relative_filename, make_absolute_filename, isfolder}
1109 @end deftypefn */)
1110 {
1111  if (args.length () != 1)
1112  print_usage ();
1113 
1114  return ovl (args(0).is_string ()
1115  && sys::env::absolute_pathname (args(0).string_value ()));
1116 }
1117 
1118 /*
1119 ## FIXME: We need system-dependent tests here.
1120 
1121 %!error is_absolute_filename ()
1122 %!error is_absolute_filename ("foo", "bar")
1123 */
1124 
1125 DEFUN (is_rooted_relative_filename, args, ,
1126  doc: /* -*- texinfo -*-
1127 @deftypefn {} {@var{tf} =} is_rooted_relative_filename (@var{file})
1128 Return true if @var{file} is a rooted-relative filename.
1129 @seealso{is_absolute_filename, make_absolute_filename, isfolder}
1130 @end deftypefn */)
1131 {
1132  if (args.length () != 1)
1133  print_usage ();
1134 
1135  return ovl (args(0).is_string ()
1136  && sys::env::rooted_relative_pathname (args(0).string_value ()));
1137 }
1138 
1139 /*
1140 ## FIXME: We need system-dependent tests here.
1141 
1142 %!error is_rooted_relative_filename ()
1143 %!error is_rooted_relative_filename ("foo", "bar")
1144 */
1145 
1146 DEFUN (make_absolute_filename, args, ,
1147  doc: /* -*- texinfo -*-
1148 @deftypefn {} {@var{abs_fname} =} make_absolute_filename (@var{file})
1149 Return the full name of @var{file} beginning from the root of the file system.
1150 
1151 No check is done for the existence of @var{file}. No tilde expansion of
1152 @var{file} is performed.
1153 @seealso{canonicalize_file_name, is_absolute_filename,
1154 is_rooted_relative_filename, isfolder, tilde_expand}
1155 @end deftypefn */)
1156 {
1157  if (args.length () != 1)
1158  print_usage ();
1159 
1160  std::string nm = args(0).xstring_value ("make_absolute_filename: FILE argument must be a filename");
1161 
1162  return ovl (sys::env::make_absolute (nm));
1163 }
1164 
1165 /*
1166 ## FIXME: We need system-dependent tests here.
1167 
1168 %!error make_absolute_filename ()
1169 %!error make_absolute_filename ("foo", "bar")
1170 */
1171 
1172 DEFMETHOD (dir_in_loadpath, interp, args, ,
1173  doc: /* -*- texinfo -*-
1174 @deftypefn {} {@var{dirname} =} dir_in_loadpath (@var{dir})
1175 @deftypefnx {} {@var{dirname} =} dir_in_loadpath (@var{dir}, "all")
1176 Return the absolute name of the loadpath element matching @var{dir} if it can
1177 be found in the list of directories specified by @code{path}.
1178 
1179 If no match is found, return an empty character string.
1180 
1181 The match is performed at the end of each path element. For example, if
1182 @var{dir} is @qcode{"foo/bar"}, it matches the path element
1183 @nospell{@qcode{"/some/dir/foo/bar"}}, but not
1184 @nospell{@qcode{"/some/dir/foo/bar/baz"}}
1185 @nospell{@qcode{"/some/dir/allfoo/bar"}}. When @var{dir} is an absolute name,
1186 rather than just a path fragment, it is matched against the file system
1187 instead of Octave's loadpath. In this case, if @var{dir} exists it will be
1188 returned in @var{dirname}, otherwise an empty string is returned.
1189 
1190 If the optional second argument is supplied, return a cell array containing
1191 all name matches rather than just the first.
1192 @seealso{file_in_path, file_in_loadpath, path}
1193 @end deftypefn */)
1194 {
1195  int nargin = args.length ();
1196 
1197  if (nargin < 1 || nargin > 2)
1198  print_usage ();
1199 
1200  std::string dir;
1201 
1202  dir = args(0).xstring_value ("dir_in_loadpath: DIR must be a directory name");
1203 
1204  load_path& lp = interp.get_load_path ();
1205 
1206  if (nargin == 1)
1207  return ovl (lp.find_dir (dir));
1208  else
1209  return ovl (Cell (lp.find_matching_dirs (dir)));
1210 }
1211 
1212 /*
1213 %!test
1214 %! f = dir_in_loadpath ("plot");
1215 %! assert (ischar (f));
1216 %! assert (! isempty (f));
1217 
1218 %!test
1219 %! f = dir_in_loadpath ("$$probably_!! _not_&&_a_!! _dir$$");
1220 %! assert (f, "");
1221 
1222 %!test
1223 %! lst = dir_in_loadpath ("$$probably_!! _not_&&_a_!! _dir$$", "all");
1224 %! assert (lst, {});
1225 
1226 %!error dir_in_loadpath ()
1227 %!error dir_in_loadpath ("foo", "bar", 1)
1228 */
1229 
1230 DEFUNX ("errno", Ferrno, args, ,
1231  doc: /* -*- texinfo -*-
1232 @deftypefn {} {@var{err} =} errno ()
1233 @deftypefnx {} {@var{err} =} errno (@var{val})
1234 @deftypefnx {} {@var{err} =} errno (@var{name})
1235 Query or set the system-dependent variable errno.
1236 
1237 When called with no inputs, return the current value of errno.
1238 
1239 When called with a numeric input @var{val}, set the current value of errno
1240 to the specified value. The previous value of errno is returned as @var{err}.
1241 
1242 When called with a character string @var{name}, return the numeric value of
1243 errno which corresponds to the specified error code. If @var{name} is not
1244 a recognized error code then -1 is returned.
1245 
1246 @seealso{errno_list}
1247 @end deftypefn */)
1248 {
1249  int nargin = args.length ();
1250 
1251  if (nargin > 1)
1252  print_usage ();
1253 
1254  octave_value retval;
1255 
1256  if (nargin == 1)
1257  {
1258  if (args(0).is_string ())
1259  {
1260  std::string nm = args(0).string_value ();
1261 
1262  retval = octave_errno::lookup (nm);
1263  }
1264  else
1265  {
1266  int val = args(0).xint_value ("errno: argument must be string or integer");
1267 
1268  retval = octave_errno::set (val);
1269  }
1270  }
1271  else
1272  retval = octave_errno::get ();
1273 
1274  return retval;
1275 }
1276 
1277 /*
1278 %!assert (isnumeric (errno ()))
1279 
1280 %!test
1281 %! lst = errno_list ();
1282 %! fns = fieldnames (lst);
1283 %! oldval = errno (fns{1});
1284 %! assert (isnumeric (oldval));
1285 %! errno (oldval);
1286 %! newval = errno ();
1287 %! assert (oldval, newval);
1288 
1289 %!error errno ("foo", 1)
1290 */
1291 
1292 DEFUN (errno_list, args, ,
1293  doc: /* -*- texinfo -*-
1294 @deftypefn {} {@var{S} =} errno_list ()
1295 Return a structure containing the system-dependent errno values.
1296 @seealso{errno}
1297 @end deftypefn */)
1298 {
1299  if (args.length () != 0)
1300  print_usage ();
1301 
1302  return ovl (octave_errno::list ());
1303 }
1304 
1305 /*
1306 %!assert (isstruct (errno_list ()))
1307 
1308 %!error errno_list ("foo")
1309 */
1310 
1312  const char *warnfor)
1313 {
1314  if (nr < 0 || nc < 0)
1315  {
1316  warning_with_id ("Octave:neg-dim-as-zero",
1317  "%s: converting negative dimension to zero", warnfor);
1318 
1319  nr = (nr < 0) ? 0 : nr;
1320  nc = (nc < 0) ? 0 : nc;
1321  }
1322 }
1323 
1324 void check_dimensions (dim_vector& dim, const char *warnfor)
1325 {
1326  bool neg = false;
1327 
1328  for (int i = 0; i < dim.ndims (); i++)
1329  {
1330  if (dim(i) < 0)
1331  {
1332  dim(i) = 0;
1333  neg = true;
1334  }
1335  }
1336 
1337  if (neg)
1338  warning_with_id ("Octave:neg-dim-as-zero",
1339  "%s: converting negative dimension to zero", warnfor);
1340 }
1341 
1342 void get_dimensions (const octave_value& a, const char *warn_for,
1343  dim_vector& dim)
1344 {
1345  // We support dimensions to be specified by a vector, even if it's empty.
1346  // If the vector is empty, the final dimensions end up being 0x0.
1347  if (! a.dims ().isvector () && a.dims ().numel () != 0)
1348  error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
1349 
1351  const octave_idx_type n = v.numel ();
1352 
1353  dim.resize (n); // even if n < 2, resize sets it back to 2
1354  if (n == 0)
1355  {
1356  dim(0) = 0;
1357  dim(1) = 0;
1358  }
1359  else if (n == 1)
1360  {
1361  dim(0) = v(0);
1362  dim(1) = v(0);
1363  }
1364  else
1365  for (octave_idx_type i = 0; i < n; i++)
1366  dim(i) = v(i);
1367 
1368  check_dimensions (dim, warn_for);
1369 }
1370 
1371 void get_dimensions (const octave_value& a, const char *warn_for,
1373 {
1374  if (a.is_scalar_type ())
1375  {
1376  nr = nc = a.idx_type_value (true);
1377  }
1378  else
1379  {
1380  nr = a.rows ();
1381  nc = a.columns ();
1382 
1383  if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1))
1384  error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
1385 
1387  nr = v(0);
1388  nc = v(1);
1389  }
1390 
1391  check_dimensions (nr, nc, warn_for);
1392 }
1393 
1394 void get_dimensions (const octave_value& a, const octave_value& b,
1395  const char *warn_for, octave_idx_type& nr,
1396  octave_idx_type& nc)
1397 {
1398  nr = (a.isempty () ? 0 : a.idx_type_value (true));
1399  nc = (b.isempty () ? 0 : b.idx_type_value (true));
1400 
1401  check_dimensions (nr, nc, warn_for);
1402 }
1403 
1405  const octave_value_list& idx_arg)
1406 {
1407  octave_idx_type retval;
1408 
1409  octave_idx_type len = idx_arg.length ();
1410 
1411  if (len == 0)
1412  retval = dims.numel ();
1413  else
1414  {
1415  const dim_vector dv = dims.redim (len);
1416  retval = 1;
1417  for (octave_idx_type i = 0; i < len; i++)
1418  {
1419  octave_value idxi = idx_arg(i);
1420  if (idxi.is_magic_colon ())
1421  retval *= dv(i);
1422  else if (idxi.isnumeric ())
1423  retval *= idxi.numel ();
1424  else
1425  {
1426  try
1427  {
1428  idx_vector jdx = idxi.index_vector ();
1429 
1430  retval *= jdx.length (dv(i));
1431  }
1432  catch (const index_exception& ie)
1433  {
1434  error ("dims_to_numel: invalid index %s", ie.what ());
1435  }
1436  }
1437  }
1438  }
1439 
1440  return retval;
1441 }
1442 
1444 {
1445  Matrix m (nr, nc, 0.0);
1446 
1447  if (nr > 0 && nc > 0)
1448  {
1449  octave_idx_type n = std::min (nr, nc);
1450 
1451  for (octave_idx_type i = 0; i < n; i++)
1452  m (i, i) = 1.0;
1453  }
1454 
1455  return m;
1456 }
1457 
1459 {
1460  FloatMatrix m (nr, nc, 0.0);
1461 
1462  if (nr > 0 && nc > 0)
1463  {
1464  octave_idx_type n = std::min (nr, nc);
1465 
1466  for (octave_idx_type i = 0; i < n; i++)
1467  m (i, i) = 1.0;
1468  }
1469 
1470  return m;
1471 }
1472 
1473 std::size_t format (std::ostream& os, const char *fmt, ...)
1474 {
1475  std::size_t retval;
1476 
1477  va_list args;
1478  va_start (args, fmt);
1479 
1480  retval = vformat (os, fmt, args);
1481 
1482  va_end (args);
1483 
1484  return retval;
1485 }
1486 
1487 std::size_t vformat (std::ostream& os, const char *fmt, va_list args)
1488 {
1489  std::string s = vasprintf (fmt, args);
1490 
1491  os << s;
1492 
1493  return s.length ();
1494 }
1495 
1496 std::string vasprintf (const char *fmt, va_list args)
1497 {
1498  std::string retval;
1499 
1500  char *result;
1501 
1502  int status = octave_vasprintf_wrapper (&result, fmt, args);
1503 
1504  if (status >= 0)
1505  {
1506  retval = result;
1507  ::free (result);
1508  }
1509 
1510  return retval;
1511 }
1512 
1513 std::string asprintf (const char *fmt, ...)
1514 {
1515  std::string retval;
1516 
1517  va_list args;
1518  va_start (args, fmt);
1519 
1520  retval = vasprintf (fmt, args);
1521 
1522  va_end (args);
1523 
1524  return retval;
1525 }
1526 
1527 // FIXME: sleep is complicated because we want it to be interruptible.
1528 // With the way this program handles signals, the sleep system call
1529 // won't respond to SIGINT. Maybe there is a better way than
1530 // breaking this up into multiple shorter intervals?
1531 
1532 void sleep (double seconds, bool do_graphics_events)
1533 {
1534  if (seconds <= 0)
1535  return;
1536 
1537  // Allow free access to graphics resources while the interpreter thread
1538  // is asleep
1539 
1540  gh_manager& gh_mgr = __get_gh_manager__ ();
1541 
1542  if (do_graphics_events)
1543  gh_mgr.unlock ();
1544 
1545  if (math::isinf (seconds))
1546  {
1547  // Wait for kbhit
1548  int c = -1;
1549  flush_stdout ();
1550 
1551  struct timespec one_tenth = { 0, 100000000 };
1552 
1553  while (c < 0)
1554  {
1555  octave_nanosleep_wrapper (&one_tenth, nullptr);
1556 
1557  octave_quit ();
1558 
1559  if (do_graphics_events)
1560  gh_mgr.process_events ();
1561 
1562  c = kbhit (false);
1563  }
1564  }
1565  else
1566  {
1567  sys::time now;
1568  double end_time = now.double_value () + seconds;
1569  double remaining_time = seconds;
1570 
1571  // Split pause into 100 ms time steps to allow the execution of
1572  // graphics events and interrupts.
1573  struct timespec nano_laps = { 0, 100000000 };
1574 
1575  while (remaining_time > 0.1)
1576  {
1577  octave_quit ();
1578 
1579  if (do_graphics_events)
1580  {
1581  gh_mgr.process_events ();
1582 
1583  now.stamp ();
1584  remaining_time = end_time - now.double_value ();
1585 
1586  if (remaining_time < 0.1)
1587  break;
1588  }
1589 
1590  octave_nanosleep_wrapper (&nano_laps, nullptr);
1591 
1592  now.stamp ();
1593  remaining_time = end_time - now.double_value ();
1594  }
1595 
1596  if (remaining_time > 0.0)
1597  {
1598  nano_laps = { 0, static_cast<int> (remaining_time * 1e9) };
1599  octave_nanosleep_wrapper (&nano_laps, nullptr);
1600  }
1601  }
1602 }
1603 
1604 DEFMETHOD (isindex, interp, args, ,
1605  doc: /* -*- texinfo -*-
1606 @deftypefn {} {@var{tf} =} isindex (@var{ind})
1607 @deftypefnx {} {@var{tf} =} isindex (@var{ind}, @var{n})
1608 Return true if @var{ind} is a valid index.
1609 
1610 Valid indices are either positive integers (although possibly of real data
1611 type), or logical arrays.
1612 
1613 If present, @var{n} specifies the maximum extent of the dimension to be
1614 indexed. When possible the internal result is cached so that subsequent
1615 indexing using @var{ind} will not perform the check again.
1616 
1617 Implementation Note: Strings are first converted to double values before the
1618 checks for valid indices are made. Unless a string contains the NULL
1619 character @nospell{"@backslashchar{}0"}, it will always be a valid index.
1620 @end deftypefn */)
1621 {
1622  int nargin = args.length ();
1623 
1624  if (nargin < 1 || nargin > 2)
1625  print_usage ();
1626 
1627  octave_idx_type n = 0;
1628  if (nargin == 2)
1629  n = args(1).idx_type_value ();
1630 
1631  octave_value retval;
1632 
1633  try
1634  {
1635  idx_vector idx = args(0).index_vector (true);
1636 
1637  if (nargin == 2)
1638  retval = idx.extent (n) <= n;
1639  else
1640  retval = true;
1641  }
1642  catch (const execution_exception&)
1643  {
1644  interp.recover_from_exception ();
1645 
1646  retval = false;
1647  }
1648 
1649  return retval;
1650 }
1651 
1652 /*
1653 %!assert (isindex ([1, 2, 3]))
1654 %!assert (isindex (1:3))
1655 %!assert (isindex (1:3, 2), false)
1656 %!assert (isindex ([1, 2, -3]), false)
1657 
1658 %!error isindex ()
1659 %!error isindex (1:3, 2, 3)
1660 */
1661 
1664  const char *fcn_name, const octave_value_list& args,
1665  int nargout)
1666 {
1667  octave_value_list new_args = args;
1668  octave_value_list retval;
1669  int nargin = args.length ();
1670  OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
1671  OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
1672  OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
1673 
1674  const Cell *ccells = cells;
1675 
1676  octave_idx_type numel = 1;
1677  dim_vector dims (1, 1);
1678 
1679  for (int i = 0; i < nargin; i++)
1680  {
1681  octave_value arg = new_args(i);
1682  iscell[i] = arg.iscell ();
1683  if (iscell[i])
1684  {
1685  cells[i] = arg.cell_value ();
1686  octave_idx_type n = ccells[i].numel ();
1687  if (n == 1)
1688  {
1689  iscell[i] = false;
1690  new_args(i) = ccells[i](0);
1691  }
1692  else if (numel == 1)
1693  {
1694  numel = n;
1695  dims = ccells[i].dims ();
1696  }
1697  else if (dims != ccells[i].dims ())
1698  error ("%s: cell arguments must have matching sizes", fcn_name);
1699  }
1700  }
1701 
1702  for (int i = 0; i < nargout; i++)
1703  rcells[i].clear (dims);
1704 
1705  for (octave_idx_type j = 0; j < numel; j++)
1706  {
1707  for (int i = 0; i < nargin; i++)
1708  if (iscell[i])
1709  new_args(i) = ccells[i](j);
1710 
1711  octave_quit ();
1712 
1713  const octave_value_list tmp = fcn (new_args, nargout);
1714 
1715  if (tmp.length () < nargout)
1716  error ("%s: do_simple_cellfun: internal error", fcn_name);
1717 
1718  for (int i = 0; i < nargout; i++)
1719  rcells[i](j) = tmp(i);
1720  }
1721 
1722  retval.resize (nargout);
1723 
1724  for (int i = 0; i < nargout; i++)
1725  retval(i) = rcells[i];
1726 
1727  return retval;
1728 }
1729 
1732  const char *fcn_name, const octave_value_list& args)
1733 {
1734  octave_value retval;
1735 
1736  const octave_value_list tmp = do_simple_cellfun (fcn, fcn_name, args, 1);
1737 
1738  if (tmp.length () > 0)
1739  retval = tmp(0);
1740 
1741  return retval;
1742 }
1743 
1744 DEFUN (isstudent, args, ,
1745  doc: /* -*- texinfo -*-
1746 @deftypefn {} {@var{tf} =} isstudent ()
1747 Return true if running in the student edition of @sc{matlab}.
1748 
1749 @code{isstudent} always returns false in Octave.
1750 @seealso{false}
1751 @end deftypefn */)
1752 {
1753  if (args.length () != 0)
1754  print_usage ();
1755 
1756  return ovl (false);
1757 }
1758 
1759 /*
1760 %!assert (isstudent (), false)
1761 
1762 %!error isstudent (1)
1763 */
1764 
OCTAVE_END_NAMESPACE(octave)
ComplexNDArray concat(NDArray &ra, ComplexNDArray &rb, const Array< octave_idx_type > &ra_idx)
Definition: CNDArray.cc:418
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_OVERRIDABLE_FUNC_API const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
Definition: Cell.h:43
Definition: dMatrix.h:42
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
bool isvector(void) const
Definition: dim-vector.h:395
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:257
OCTAVE_API dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
std::string find_first_of(const std::list< std::string > &names)
Definition: pathsearch.cc:86
std::list< std::string > find_all_first_of(const std::list< std::string > &names)
Definition: pathsearch.cc:93
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:538
octave_idx_type extent(octave_idx_type n) const
Definition: idx-vector.h:541
std::string find_first_of(const string_vector &files) const
Definition: load-path.cc:751
string_vector find_matching_dirs(const std::string &dir) const
Definition: load-path.cc:704
string_vector find_all_first_of(const string_vector &files) const
Definition: load-path.cc:828
std::string find_file(const std::string &file) const
Definition: load-path.cc:602
std::string find_dir(const std::string &dir) const
Definition: load-path.cc:657
std::string find_fcn_file(const std::string &fcn, const std::string &pack_name="")
Definition: load-path.h:131
Helper class for make_valid_name function calls.
Definition: utils.h:57
std::string m_prefix
Definition: utils.h:93
std::string m_replacement_style
Definition: utils.h:92
make_valid_name_options()=default
Default options for make_valid_name function calls.
const std::string & get_replacement_style() const
Definition: utils.h:84
const std::string & get_prefix() const
Definition: utils.h:88
static int set(int val)
Definition: oct-errno.h:59
static int lookup(const std::string &name)
static octave_scalar_map list(void)
static int get(void)
Definition: oct-errno.h:57
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
octave_idx_type length(void) const
Definition: ovl.h:113
bool iscell(void) const
Definition: ov.h:649
octave::idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:579
octave_idx_type rows(void) const
Definition: ov.h:590
bool isnumeric(void) const
Definition: ov.h:795
octave_idx_type numel(void) const
Definition: ov.h:604
octave_idx_type idx_type_value(bool req_int=false, bool frc_str_conv=false) const
bool is_scalar_type(void) const
Definition: ov.h:789
bool is_string(void) const
Definition: ov.h:682
Cell cell_value(void) const
octave_idx_type columns(void) const
Definition: ov.h:592
std::string string_value(bool force=false) const
Definition: ov.h:1019
bool isempty(void) const
Definition: ov.h:646
Array< std::string > cellstr_value(void) const
Definition: ov.h:1027
bool is_magic_colon(void) const
Definition: ov.h:718
OCTINTERP_API Array< octave_idx_type > octave_idx_type_vector_value(bool req_int=false, bool frc_str_conv=false, bool frc_vec_conv=false) const
dim_vector dims(void) const
Definition: ov.h:586
octave_idx_type numel(void) const
Definition: str-vec.h:100
bool empty(void) const
Definition: str-vec.h:77
std::list< std::string > std_list(void) const
Definition: str-vec.cc:172
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
#define DEFUNX(name, fname, args_name, nargout_name, doc)
Macro to define a builtin function with certain internal name.
Definition: defun.h:85
void warning(const char *fmt,...)
Definition: error.cc:1054
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1069
void error(const char *fmt,...)
Definition: error.cc:979
void warn_data_file_in_path(const std::string &fcn, const std::string &file)
Definition: errwarn.cc:310
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5819
load_path & __get_load_path__(void)
gh_manager & __get_gh_manager__(void)
bool iskeyword(const std::string &s)
Definition: lex.cc:1359
bool isinf(double x)
Definition: lo-mappers.h:203
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
static char * strsave(const char *s)
Definition: main.in.cc:214
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
int octave_nanosleep_wrapper(const struct timespec *requested, struct timespec *remaining)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
T::size_type numel(const T &str)
Definition: oct-string.cc:71
OCTAVE_API bool strncmp(const T &str_a, const T &str_b, const typename T::size_type n)
True if the first N characters are the same.
void free(void *)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
void flush_stdout(void)
Definition: pager.cc:260
static bool absolute_pathname(const std::string &s)
Definition: shared-fcns.h:148
OCTAVE_API int octave_strncasecmp(const char *s1, const char *s2, size_t n)
int kbhit(bool wait)
Definition: sysdep.cc:722
bool same_file_internal(const std::string &file1, const std::string &file2)
Definition: sysdep.cc:385
std::size_t vformat(std::ostream &os, const char *fmt, va_list args)
Definition: utils.cc:1487
static string_vector make_absolute(const string_vector &sv)
Definition: utils.cc:536
std::string asprintf(const char *fmt,...)
Definition: utils.cc:1513
static void check_dimensions(octave_idx_type &nr, octave_idx_type &nc, const char *warnfor)
Definition: utils.cc:1311
std::string do_string_escapes(const std::string &s)
Definition: utils.cc:804
std::string find_data_file_in_load_path(const std::string &fcn, const std::string &file, bool require_regular_file)
Definition: utils.cc:703
octave_idx_type dims_to_numel(const dim_vector &dims, const octave_value_list &idx_arg)
Definition: utils.cc:1404
std::string contents_file_in_path(const std::string &dir)
Definition: utils.cc:782
std::string undo_string_escapes(const std::string &s)
Definition: utils.cc:1033
int almost_match(const std::string &std, const std::string &s, int min_match_len, int case_sens)
Definition: utils.cc:408
int keyword_almost_match(const char *const *std, int *min_len, const std::string &s, int min_toks_to_match, int max_toks)
Definition: utils.cc:423
Matrix identity_matrix(octave_idx_type nr, octave_idx_type nc)
Definition: utils.cc:1443
std::string file_in_path(const std::string &name, const std::string &suffix)
Definition: utils.cc:691
std::string vasprintf(const char *fmt, va_list args)
Definition: utils.cc:1496
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition: utils.cc:1342
bool valid_identifier(const char *s)
Definition: utils.cc:78
FloatMatrix float_identity_matrix(octave_idx_type nr, octave_idx_type nc)
Definition: utils.cc:1458
std::size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1473
void sleep(double seconds, bool do_graphics_events)
Definition: utils.cc:1532
OCTAVE_EXPORT octave_value_list Ferrno(const octave_value_list &args, int)
Definition: utils.cc:1247
string_vector search_path_for_all_files(const std::string &path, const string_vector &names)
Definition: utils.cc:521
bool make_valid_name(std::string &str, const make_valid_name_options &options)
Modify str to be a valid variable name.
Definition: utils.cc:135
const char * undo_string_escape(char c)
Definition: utils.cc:986
std::string search_path_for_file(const std::string &path, const string_vector &names)
Definition: utils.cc:511
octave_value_list do_simple_cellfun(octave_value_list(*fcn)(const octave_value_list &, int), const char *fcn_name, const octave_value_list &args, int nargout)
Definition: utils.cc:1663
std::string fcn_file_in_path(const std::string &name)
Definition: utils.cc:742
bool same_file(const std::string &f, const std::string &g)
Definition: utils.cc:294
int octave_vasprintf_wrapper(char **buf, const char *fmt, va_list args)
F77_RET_T len
Definition: xerbla.cc:61