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