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