GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
utils.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-2025 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
79bool 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
91bool
92valid_identifier (const std::string& s)
93{
94 return valid_identifier (s.c_str ());
95}
96
97DEFUN (isvarname, args, ,
98 doc: /* -*- texinfo -*-
99@deftypefn {} {@var{tf} =} isvarname (@var{name})
100Return true if @var{name} is a valid variable name.
101
102A valid variable name is composed of letters, digits, and underscores ("_"),
103and 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
136bool
137make_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
257DEFUN (__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{})
263Return a valid variable name @var{varname} from input @var{str}.
264
265For 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
296bool
297same_file (const std::string& f, const std::string& g)
298{
299 return sys::same_file (f, g);
300}
301
302DEFUN (is_same_file, args, ,
303 doc: /* -*- texinfo -*-
304@deftypefn {} {@var{same} =} is_same_file (@var{filepath1}, @var{filepath2})
305Return true if @var{filepath1} and @var{filepath2} refer to the same file.
306
307If either @var{filepath1} or @var{filepath2} is a cell array of strings, then
308an array of the same size is returned, containing the values described above
309for every member of the cell array. The other argument may also be a cell
310array of strings (of the same size) or a string.
311
312Programming Notes: Depending on the operating system and file system, the same
313file or folder can be referred to with different paths. In particular, paths
314on the Windows platform may differ in case (@file{file1} vs.@: @file {FILE1}),
315file separator (@samp{\} vs.@: @samp{/}), and format (@file{A~spaces.txt} (8.3
316convention) vs.@: @file{A filename with spaces.txt}). This function returns
317true if the paths in @var{filepath1} and @var{filepath2} actually refer to the
318same file or folder, and false otherwise.
319
320Note that unlike @code{strcmp}, this function requires that @var{filepath1}
321and @var{filepath2} exist, as well as point to the same location, in order to
322return 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
411int
412almost_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
427int
428keyword_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
506done:
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
516std::string
517search_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
528search_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
543static string_vector
544make_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
556DEFMETHOD (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")
560Return the absolute name of @var{file} if it can be found in the list of
561directories specified by @code{path}.
562
563If no file is found, return an empty character string.
564
565When @var{file} is already an absolute name, the name is checked against the
566file system instead of Octave's loadpath. In this case, if @var{file} exists
567it will be returned in @var{fname}, otherwise an empty string is returned.
568
569If the first argument is a cell array of strings, search each directory of
570the loadpath for element of the cell array and return the first that
571matches.
572
573If the second optional argument @qcode{"all"} is supplied, return a cell
574array containing the list of all files that have the same name in the path.
575If 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
624DEFUN (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")
628Return the absolute name of @var{file} if it can be found in @var{path}.
629
630The value of @var{path} should be a colon-separated list of directories in
631the format described for @code{path}. If no file is found, return an empty
632character string. For example:
633
634@example
635@group
636file_in_path (EXEC_PATH, "sh")
637 @result{} "/bin/sh"
638@end group
639@end example
640
641If the second argument is a cell array of strings, search each directory of
642the path for element of the cell array and return the first that matches.
643
644If the third optional argument @qcode{"all"} is supplied, return a cell
645array containing the list of all files that have the same name in the path.
646If 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
697std::string
698file_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
706
707 return sys::env::make_absolute (lp.find_file (nm));
708}
709
710std::string
711find_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 {
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
748std::string
749fcn_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 {
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
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
787std::string
788contents_file_in_path (const std::string& dir)
789{
790 std::string retval;
791
792 if (! dir.empty ())
793 {
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
806void
807display_file_lines (std::ostream& os, const std::string& file_name, int start, int end, int target_line, const std::string& marker, const std::string& who)
808{
809 std::ifstream fs = octave::sys::ifstream (file_name.c_str (), std::ios::in);
810
811 if (! fs)
812 os << who << ": unable to open '" << file_name << "' for reading!\n";
813 else
814 {
815 int line_num = 1;
816 std::string text;
817
818 while (std::getline (fs, text) && line_num <= end)
819 {
820 if (line_num >= start)
821 {
822 os << line_num;
823
824 if (line_num == target_line)
825 os << marker;
826
827 os << "\t" << text << "\n";
828 }
829
830 line_num++;
831 }
832 }
833}
834
835// Replace backslash escapes in a string with the real values.
836
837std::string
838do_string_escapes (const std::string& s)
839{
840 std::string retval;
841
842 std::size_t i = 0;
843 std::size_t j = 0;
844 std::size_t len = s.length ();
845
846 retval.resize (len);
847
848 while (j < len)
849 {
850 if (s[j] == '\\' && j+1 < len)
851 {
852 switch (s[++j])
853 {
854 case 'a': // alarm
855 retval[i] = '\a';
856 break;
857
858 case 'b': // backspace
859 retval[i] = '\b';
860 break;
861
862 case 'f': // formfeed
863 retval[i] = '\f';
864 break;
865
866 case 'n': // newline
867 retval[i] = '\n';
868 break;
869
870 case 'r': // carriage return
871 retval[i] = '\r';
872 break;
873
874 case 't': // horizontal tab
875 retval[i] = '\t';
876 break;
877
878 case 'v': // vertical tab
879 retval[i] = '\v';
880 break;
881
882 case '\\': // backslash
883 retval[i] = '\\';
884 break;
885
886 case '\'': // quote
887 retval[i] = '\'';
888 break;
889
890 case '"': // double quote
891 retval[i] = '"';
892 break;
893
894 case '0':
895 case '1':
896 case '2':
897 case '3':
898 case '4':
899 case '5':
900 case '6':
901 case '7': // octal input
902 {
903 std::size_t k;
904 int tmpi = s[j] - '0';
905 for (k = j+1; k < std::min (j+3, len); k++)
906 {
907 int digit = s[k] - '0';
908 if (digit < 0 || digit > 7)
909 break;
910 tmpi <<= 3;
911 tmpi += digit;
912 }
913 retval[i] = tmpi;
914 j = k - 1;
915 break;
916 }
917
918 case 'x': // hex input
919 {
920 std::size_t k;
921 int tmpi = 0;
922 for (k = j+1; k < std::min (j+3, len); k++)
923 {
924 if (! isxdigit (s[k]))
925 break;
926
927 tmpi <<= 4;
928 int digit = s[k];
929 if (digit >= 'a')
930 tmpi += digit - 'a' + 10;
931 else if (digit >= 'A')
932 tmpi += digit - 'A' + 10;
933 else
934 tmpi += digit - '0';
935 }
936
937 if (k == j+1)
938 warning (R"(malformed hex escape sequence '\x' -- converting to '\0')");
939
940 retval[i] = tmpi;
941 j = k - 1;
942 break;
943 }
944
945 default:
946 warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]);
947 retval[i] = s[j];
948 break;
949 }
950 }
951 else
952 retval[i] = s[j];
953
954 i++;
955 j++;
956 }
957
958 retval.resize (i);
959
960 return retval;
961}
962
963DEFUN (do_string_escapes, args, ,
964 doc: /* -*- texinfo -*-
965@deftypefn {} {@var{newstr} =} do_string_escapes (@var{string})
966Convert escape sequences in @var{string} to the characters they represent.
967
968Escape sequences begin with a leading backslash
969(@qcode{'@backslashchar{}'}) followed by 1--3 characters
970(.e.g., @qcode{"@backslashchar{}n"} => newline).
971@seealso{undo_string_escapes}
972@end deftypefn */)
973{
974 if (args.length () != 1)
975 print_usage ();
976
977 std::string str = args(0).xstring_value ("do_string_escapes: STRING argument must be of type string");
978
979 return ovl (do_string_escapes (str));
980}
981
982/*
983%!assert (do_string_escapes ('foo\nbar'), "foo\nbar")
984%!assert (do_string_escapes ("foo\\nbar"), "foo\nbar")
985%!assert (do_string_escapes ("foo\\nbar"), ["foo", char(10), "bar"])
986%!assert ("foo\nbar", ["foo", char(10), "bar"])
987
988%!assert (do_string_escapes ('\0\a\b\f\n\r\t\v'), "\0\a\b\f\n\r\t\v")
989%!assert (do_string_escapes ("\\0\\a\\b\\f\\n\\r\\t\\v"), "\0\a\b\f\n\r\t\v")
990%!assert (do_string_escapes ("\\0\\a\\b\\f\\n\\r\\t\\v"),
991%! char ([0, 7, 8, 12, 10, 13, 9, 11]))
992%!assert ("\0\a\b\f\n\r\t\v", char ([0, 7, 8, 12, 10, 13, 9, 11]))
993
994%!assert (do_string_escapes ('\\'), "\\")
995%!assert (do_string_escapes ("\\\\"), "\\")
996%!assert (do_string_escapes ("\\\\"), char (92))
997
998%!assert (do_string_escapes ('\''single-quoted\'''), "'single-quoted'")
999%!assert (do_string_escapes ("\\'single-quoted\\'"), "'single-quoted'")
1000%!assert (do_string_escapes ('\"double-quoted\"'), "\"double-quoted\"")
1001%!assert (do_string_escapes ("\\\"double-quoted\\\""), "\"double-quoted\"")
1002
1003%!assert (do_string_escapes ('A\4B'), ["A" char(4) "B"])
1004%!assert (do_string_escapes ('A\45B'), ["A" char(37) "B"])
1005%!assert (do_string_escapes ('A\123B'), ["A" char(83) "B"])
1006%!assert (sprintf ('\117\143\164\141\166\145'), "Octave")
1007
1008%!assert (do_string_escapes ('A\x4G'), ["A" char(4) "G"])
1009%!assert (do_string_escapes ('A\x4AG'), ["A" char(74) "G"])
1010%!assert (sprintf ('\x4f\x63\x74\x61\x76\x65'), "Octave")
1011
1012%!error do_string_escapes ()
1013%!error do_string_escapes ("foo", "bar")
1014%!error <STRING argument> do_string_escapes (3)
1015%!warning <malformed hex escape sequence> do_string_escapes ('\xG');
1016%!warning <unrecognized escape sequence> do_string_escapes ('\G');
1017*/
1018
1019const char *
1021{
1022 switch (c)
1023 {
1024 case '\0': // NUL byte
1025 return R"(\0)";
1026
1027 case '\a': // alarm
1028 return R"(\a)";
1029
1030 case '\b': // backspace
1031 return R"(\b)";
1032
1033 case '\f': // formfeed
1034 return R"(\f)";
1035
1036 case '\n': // newline
1037 return R"(\n)";
1038
1039 case '\r': // carriage return
1040 return R"(\r)";
1041
1042 case '\t': // horizontal tab
1043 return R"(\t)";
1044
1045 case '\v': // vertical tab
1046 return R"(\v)";
1047
1048 case '\\': // backslash
1049 return R"(\\)";
1050
1051 case '"': // double quote
1052 return R"(\")";
1053
1054 default:
1055 {
1056 static char retval[2] {'\0', '\0'};
1057
1058 retval[0] = c;
1059 return retval;
1060 }
1061 }
1062}
1063
1064std::string
1065undo_string_escapes (const std::string& s)
1066{
1067 std::string retval;
1068
1069 for (std::size_t i = 0; i < s.length (); i++)
1070 retval.append (undo_string_escape (s[i]));
1071
1072 return retval;
1073}
1074
1075DEFUN (undo_string_escapes, args, ,
1076 doc: /* -*- texinfo -*-
1077@deftypefn {} {@var{newstr} =} undo_string_escapes (@var{string})
1078Convert special characters in @var{string} back to their escaped forms.
1079
1080For example, the expression
1081
1082@example
1083@var{bell} = "\a";
1084@end example
1085
1086@noindent
1087assigns the value of the alert character (control-g, ASCII code 7) to the
1088string variable @code{bell}. If this string is printed, the system will
1089ring the terminal bell (if it is possible). This is normally the desired
1090outcome. However, sometimes it is useful to be able to print the original
1091representation of the string, with the special characters replaced by their
1092escape sequences. For example,
1093
1094@example
1095@group
1096octave:13> undo_string_escapes (bell)
1097ans = \a
1098@end group
1099@end example
1100
1101@noindent
1102replaces the unprintable alert character with its printable representation.
1103@seealso{do_string_escapes}
1104@end deftypefn */)
1105{
1106 if (args.length () != 1)
1107 print_usage ();
1108
1109 std::string str = args(0).xstring_value ("undo_string_escapes: STRING argument must be a string");
1110
1111 return ovl (undo_string_escapes (str));
1112}
1113
1114/*
1115%!assert (undo_string_escapes ("foo\nbar"), 'foo\nbar')
1116%!assert (undo_string_escapes ("foo\nbar"), "foo\\nbar")
1117%!assert (undo_string_escapes (["foo", char(10), "bar"]), "foo\\nbar")
1118
1119%!assert (undo_string_escapes ("\0\a\b\f\n\r\t\v"), '\0\a\b\f\n\r\t\v')
1120%!assert (undo_string_escapes ("\0\a\b\f\n\r\t\v"), "\\0\\a\\b\\f\\n\\r\\t\\v")
1121%!assert (undo_string_escapes (char ([0, 7, 8, 12, 10, 13, 9, 11])),
1122%! "\\0\\a\\b\\f\\n\\r\\t\\v")
1123
1124%!assert (undo_string_escapes ("\\"), '\\')
1125%!assert (undo_string_escapes ("\\"), "\\\\")
1126%!assert (undo_string_escapes (char (92)), "\\\\")
1127
1128%!assert (undo_string_escapes ("\"double-quoted\""), '\"double-quoted\"')
1129%!assert (undo_string_escapes ("\"double-quoted\""), "\\\"double-quoted\\\"")
1130
1131%!error <Invalid call> undo_string_escapes ()
1132%!error <Invalid call> undo_string_escapes ("foo", "bar")
1133%!error <STRING argument> undo_string_escapes (3)
1134*/
1135
1136DEFUN (is_absolute_filename, args, ,
1137 doc: /* -*- texinfo -*-
1138@deftypefn {} {@var{tf} =} is_absolute_filename (@var{file})
1139Return true if @var{file} is an absolute filename.
1140@seealso{is_rooted_relative_filename, make_absolute_filename, isfolder}
1141@end deftypefn */)
1142{
1143 if (args.length () != 1)
1144 print_usage ();
1145
1146 return ovl (args(0).is_string ()
1147 && sys::env::absolute_pathname (args(0).string_value ()));
1148}
1149
1150/*
1151## FIXME: We need system-dependent tests here.
1152
1153%!error is_absolute_filename ()
1154%!error is_absolute_filename ("foo", "bar")
1155*/
1156
1157DEFUN (is_rooted_relative_filename, args, ,
1158 doc: /* -*- texinfo -*-
1159@deftypefn {} {@var{tf} =} is_rooted_relative_filename (@var{file})
1160Return true if @var{file} is a rooted-relative filename.
1161@seealso{is_absolute_filename, make_absolute_filename, isfolder}
1162@end deftypefn */)
1163{
1164 if (args.length () != 1)
1165 print_usage ();
1166
1167 return ovl (args(0).is_string ()
1168 && sys::env::rooted_relative_pathname (args(0).string_value ()));
1169}
1170
1171/*
1172## FIXME: We need system-dependent tests here.
1173
1174%!error is_rooted_relative_filename ()
1175%!error is_rooted_relative_filename ("foo", "bar")
1176*/
1177
1178DEFUN (make_absolute_filename, args, ,
1179 doc: /* -*- texinfo -*-
1180@deftypefn {} {@var{abs_fname} =} make_absolute_filename (@var{file})
1181Return the full name of @var{file} beginning from the root of the file system.
1182
1183No check is done for the existence of @var{file}. No tilde expansion of
1184@var{file} is performed.
1185@seealso{canonicalize_file_name, is_absolute_filename,
1186is_rooted_relative_filename, isfolder, tilde_expand}
1187@end deftypefn */)
1188{
1189 if (args.length () != 1)
1190 print_usage ();
1191
1192 std::string nm = args(0).xstring_value ("make_absolute_filename: FILE argument must be a filename");
1193
1194 return ovl (sys::env::make_absolute (nm));
1195}
1196
1197/*
1198## FIXME: We need system-dependent tests here.
1199
1200%!error make_absolute_filename ()
1201%!error make_absolute_filename ("foo", "bar")
1202*/
1203
1204DEFMETHOD (dir_in_loadpath, interp, args, ,
1205 doc: /* -*- texinfo -*-
1206@deftypefn {} {@var{dirname} =} dir_in_loadpath (@var{dir})
1207@deftypefnx {} {@var{dirname} =} dir_in_loadpath (@var{dir}, "all")
1208Return the absolute name of the loadpath element matching @var{dir} if it can
1209be found in the list of directories specified by @code{path}.
1210
1211If no match is found, return an empty character string.
1212
1213The match is performed at the end of each path element. For example, if
1214@var{dir} is @qcode{"foo/bar"}, it matches the path element
1215@nospell{@qcode{"/some/dir/foo/bar"}}, but not
1216@nospell{@qcode{"/some/dir/foo/bar/baz"}}
1217@nospell{@qcode{"/some/dir/allfoo/bar"}}. When @var{dir} is an absolute name,
1218rather than just a path fragment, it is matched against the file system
1219instead of Octave's loadpath. In this case, if @var{dir} exists it will be
1220returned in @var{dirname}, otherwise an empty string is returned.
1221
1222If the optional second argument is supplied, return a cell array containing
1223all name matches rather than just the first.
1224@seealso{file_in_path, file_in_loadpath, path}
1225@end deftypefn */)
1226{
1227 int nargin = args.length ();
1228
1229 if (nargin < 1 || nargin > 2)
1230 print_usage ();
1231
1232 std::string dir;
1233
1234 dir = args(0).xstring_value ("dir_in_loadpath: DIR must be a directory name");
1235
1236 load_path& lp = interp.get_load_path ();
1237
1238 if (nargin == 1)
1239 return ovl (lp.find_dir (dir));
1240 else
1241 return ovl (Cell (lp.find_matching_dirs (dir)));
1242}
1243
1244/*
1245%!test
1246%! f = dir_in_loadpath ("plot");
1247%! assert (ischar (f));
1248%! assert (! isempty (f));
1249
1250%!test
1251%! f = dir_in_loadpath ("$$probably_!! _not_&&_a_!! _dir$$");
1252%! assert (f, "");
1253
1254%!test
1255%! lst = dir_in_loadpath ("$$probably_!! _not_&&_a_!! _dir$$", "all");
1256%! assert (lst, {});
1257
1258%!error dir_in_loadpath ()
1259%!error dir_in_loadpath ("foo", "bar", 1)
1260*/
1261
1262DEFUNX ("errno", Ferrno, args, ,
1263 doc: /* -*- texinfo -*-
1264@deftypefn {} {@var{err} =} errno ()
1265@deftypefnx {} {@var{err} =} errno (@var{val})
1266@deftypefnx {} {@var{err} =} errno (@var{name})
1267Query or set the system-dependent variable errno.
1268
1269When called with no inputs, return the current value of errno.
1270
1271When called with a numeric input @var{val}, set the current value of errno
1272to the specified value. The previous value of errno is returned as @var{err}.
1273
1274When called with a character string @var{name}, return the numeric value of
1275errno which corresponds to the specified error code. If @var{name} is not
1276a recognized error code then -1 is returned.
1277
1278@seealso{errno_list}
1279@end deftypefn */)
1280{
1281 int nargin = args.length ();
1282
1283 if (nargin > 1)
1284 print_usage ();
1285
1286 octave_value retval;
1287
1288 if (nargin == 1)
1289 {
1290 if (args(0).is_string ())
1291 {
1292 std::string nm = args(0).string_value ();
1293
1294 retval = octave_errno::lookup (nm);
1295 }
1296 else
1297 {
1298 int val = args(0).strict_int_value ("errno: argument must be string or integer");
1299
1300 retval = octave_errno::set (val);
1301 }
1302 }
1303 else
1304 retval = octave_errno::get ();
1305
1306 return retval;
1307}
1308
1309/*
1310%!assert (isnumeric (errno ()))
1311
1312%!test
1313%! lst = errno_list ();
1314%! fns = fieldnames (lst);
1315%! oldval = errno (fns{1});
1316%! assert (isnumeric (oldval));
1317%! errno (oldval);
1318%! newval = errno ();
1319%! assert (oldval, newval);
1320
1321%!error errno ("foo", 1)
1322*/
1323
1324DEFUN (errno_list, args, ,
1325 doc: /* -*- texinfo -*-
1326@deftypefn {} {@var{S} =} errno_list ()
1327Return a structure containing the system-dependent errno values.
1328@seealso{errno}
1329@end deftypefn */)
1330{
1331 if (args.length () != 0)
1332 print_usage ();
1333
1334 return ovl (octave_errno::list ());
1335}
1336
1337/*
1338%!assert (isstruct (errno_list ()))
1339
1340%!error errno_list ("foo")
1341*/
1342
1343static void
1344check_dimensions (octave_idx_type& nr, octave_idx_type& nc,
1345 const char *warnfor)
1346{
1347 if (nr < 0 || nc < 0)
1348 {
1349 warning_with_id ("Octave:neg-dim-as-zero",
1350 "%s: converting negative dimension to zero", warnfor);
1351
1352 nr = (nr < 0) ? 0 : nr;
1353 nc = (nc < 0) ? 0 : nc;
1354 }
1355}
1356
1357void
1358check_dimensions (dim_vector& dim, const char *warnfor)
1359{
1360 bool neg = false;
1361
1362 for (int i = 0; i < dim.ndims (); i++)
1363 {
1364 if (dim(i) < 0)
1365 {
1366 dim(i) = 0;
1367 neg = true;
1368 }
1369 }
1370
1371 if (neg)
1372 warning_with_id ("Octave:neg-dim-as-zero",
1373 "%s: converting negative dimension to zero", warnfor);
1374}
1375
1376void
1377get_dimensions (const octave_value& a, const char *warn_for,
1378 dim_vector& dim)
1379{
1380 // We support dimensions to be specified by a vector, even if it's empty.
1381 // If the vector is empty, the final dimensions end up being 0x0.
1382 if (! a.dims ().isvector () && a.dims ().numel () != 0)
1383 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
1384
1386 const octave_idx_type n = v.numel ();
1387
1388 dim.resize (n); // even if n < 2, resize sets it back to 2
1389 if (n == 0)
1390 {
1391 dim(0) = 0;
1392 dim(1) = 0;
1393 }
1394 else if (n == 1)
1395 {
1396 dim(0) = v(0);
1397 dim(1) = v(0);
1398 }
1399 else
1400 for (octave_idx_type i = 0; i < n; i++)
1401 dim(i) = v(i);
1402
1403 check_dimensions (dim, warn_for);
1404}
1405
1406void
1407get_dimensions (const octave_value& a, const char *warn_for,
1409{
1410 if (a.is_scalar_type ())
1411 {
1412 nr = nc = a.idx_type_value (true);
1413 }
1414 else
1415 {
1416 nr = a.rows ();
1417 nc = a.columns ();
1418
1419 if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1))
1420 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
1421
1423 nr = v(0);
1424 nc = v(1);
1425 }
1426
1427 check_dimensions (nr, nc, warn_for);
1428}
1429
1430void
1432 const char *warn_for, octave_idx_type& nr,
1433 octave_idx_type& nc)
1434{
1435 nr = (a.isempty () ? 0 : a.idx_type_value (true));
1436 nc = (b.isempty () ? 0 : b.idx_type_value (true));
1437
1438 check_dimensions (nr, nc, warn_for);
1439}
1440
1443 const octave_value_list& idx_arg)
1444{
1445 octave_idx_type retval;
1446
1447 octave_idx_type len = idx_arg.length ();
1448
1449 if (len == 0)
1450 retval = dims.numel ();
1451 else
1452 {
1453 const dim_vector dv = dims.redim (len);
1454 retval = 1;
1455 for (octave_idx_type i = 0; i < len; i++)
1456 {
1457 octave_value idxi = idx_arg(i);
1458 if (idxi.is_magic_colon ())
1459 retval *= dv(i);
1460 else if (idxi.isnumeric ())
1461 retval *= idxi.numel ();
1462 else
1463 {
1464 try
1465 {
1466 idx_vector jdx = idxi.index_vector ();
1467
1468 retval *= jdx.length (dv(i));
1469 }
1470 catch (const index_exception& ie)
1471 {
1472 error ("dims_to_numel: invalid index %s", ie.what ());
1473 }
1474 }
1475 }
1476 }
1477
1478 return retval;
1479}
1480
1481Matrix
1483{
1484 Matrix m (nr, nc, 0.0);
1485
1486 if (nr > 0 && nc > 0)
1487 {
1488 octave_idx_type n = std::min (nr, nc);
1489
1490 for (octave_idx_type i = 0; i < n; i++)
1491 m (i, i) = 1.0;
1492 }
1493
1494 return m;
1495}
1496
1499{
1500 FloatMatrix m (nr, nc, 0.0);
1501
1502 if (nr > 0 && nc > 0)
1503 {
1504 octave_idx_type n = std::min (nr, nc);
1505
1506 for (octave_idx_type i = 0; i < n; i++)
1507 m (i, i) = 1.0;
1508 }
1509
1510 return m;
1511}
1512
1513std::size_t
1514format (std::ostream& os, const char *fmt, ...)
1515{
1516 std::size_t retval;
1517
1518 va_list args;
1519 va_start (args, fmt);
1520
1521 retval = vformat (os, fmt, args);
1522
1523 va_end (args);
1524
1525 return retval;
1526}
1527
1528std::size_t
1529vformat (std::ostream& os, const char *fmt, va_list args)
1530{
1531 std::string s = vasprintf (fmt, args);
1532
1533 os << s;
1534
1535 return s.length ();
1536}
1537
1538std::string
1539vasprintf (const char *fmt, va_list args)
1540{
1541 std::string retval;
1542
1543 char *result;
1544
1545 int status = octave_vasprintf_wrapper (&result, fmt, args);
1546
1547 if (status >= 0)
1548 {
1549 retval = result;
1550 ::free (result);
1551 }
1552
1553 return retval;
1554}
1555
1556std::string
1557asprintf (const char *fmt, ...)
1558{
1559 std::string retval;
1560
1561 va_list args;
1562 va_start (args, fmt);
1563
1564 retval = vasprintf (fmt, args);
1565
1566 va_end (args);
1567
1568 return retval;
1569}
1570
1571// FIXME: sleep is complicated because we want it to be interruptible.
1572// With the way this program handles signals, the sleep system call
1573// won't respond to SIGINT. Maybe there is a better way than
1574// breaking this up into multiple shorter intervals?
1575
1576void
1577sleep (double seconds, bool do_graphics_events)
1578{
1579 if (seconds <= 0)
1580 return;
1581
1582 // Allow free access to graphics resources while the interpreter thread
1583 // is asleep
1584
1585 gh_manager& gh_mgr = __get_gh_manager__ ();
1586
1587 if (do_graphics_events)
1588 gh_mgr.unlock ();
1589
1590 if (math::isinf (seconds))
1591 {
1592 // Wait for kbhit
1593 int c = -1;
1594 flush_stdout ();
1595
1596 struct timespec one_tenth = { 0, 100000000 };
1597
1598 while (c < 0)
1599 {
1600 octave_nanosleep_wrapper (&one_tenth, nullptr);
1601
1602 octave_quit ();
1603
1604 if (do_graphics_events)
1605 gh_mgr.process_events ();
1606
1607 c = kbhit (false);
1608 }
1609 }
1610 else
1611 {
1612 sys::time now;
1613 double end_time = now.double_value () + seconds;
1614 double remaining_time = seconds;
1615
1616 // Split pause into 100 ms time steps to allow the execution of
1617 // graphics events and interrupts.
1618 struct timespec nano_laps = { 0, 100000000 };
1619
1620 while (remaining_time > 0.1)
1621 {
1622 octave_quit ();
1623
1624 if (do_graphics_events)
1625 {
1626 gh_mgr.process_events ();
1627
1628 now.stamp ();
1629 remaining_time = end_time - now.double_value ();
1630
1631 if (remaining_time < 0.1)
1632 break;
1633 }
1634
1635 octave_nanosleep_wrapper (&nano_laps, nullptr);
1636
1637 now.stamp ();
1638 remaining_time = end_time - now.double_value ();
1639 }
1640
1641 if (remaining_time > 0.0)
1642 {
1643 nano_laps = { 0, static_cast<int> (remaining_time * 1e9) };
1644 octave_nanosleep_wrapper (&nano_laps, nullptr);
1645 }
1646 }
1647}
1648
1649DEFMETHOD (isindex, interp, args, ,
1650 doc: /* -*- texinfo -*-
1651@deftypefn {} {@var{tf} =} isindex (@var{ind})
1652@deftypefnx {} {@var{tf} =} isindex (@var{ind}, @var{n})
1653Return true if @var{ind} is a valid index.
1654
1655Valid indices are either positive integers (although possibly of real data
1656type), or logical arrays.
1657
1658If present, @var{n} specifies the maximum extent of the dimension to be
1659indexed. When possible the internal result is cached so that subsequent
1660indexing using @var{ind} will not perform the check again.
1661
1662Implementation Note: Strings are first converted to double values before the
1663checks for valid indices are made. Unless a string contains the NULL
1664character @nospell{"@backslashchar{}0"}, it will always be a valid index.
1665@end deftypefn */)
1666{
1667 int nargin = args.length ();
1668
1669 if (nargin < 1 || nargin > 2)
1670 print_usage ();
1671
1672 octave_idx_type n = 0;
1673 if (nargin == 2)
1674 n = args(1).idx_type_value ();
1675
1676 octave_value retval;
1677
1678 try
1679 {
1680 idx_vector idx = args(0).index_vector (true);
1681
1682 if (nargin == 2)
1683 retval = idx.extent (n) <= n;
1684 else
1685 retval = true;
1686 }
1687 catch (const execution_exception&)
1688 {
1689 interp.recover_from_exception ();
1690
1691 retval = false;
1692 }
1693
1694 return retval;
1695}
1696
1697/*
1698%!assert (isindex ([1, 2, 3]))
1699%!assert (isindex (1:3))
1700%!assert (isindex (1:3, 2), false)
1701%!assert (isindex ([1, 2, -3]), false)
1702
1703%!error isindex ()
1704%!error isindex (1:3, 2, 3)
1705*/
1706
1709 const char *fcn_name, const octave_value_list& args,
1710 int nargout)
1711{
1712 octave_value_list new_args = args;
1713 octave_value_list retval;
1714 int nargin = args.length ();
1715 OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
1716 OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
1717 OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
1718
1719 const Cell *ccells = cells;
1720
1722 dim_vector dims (1, 1);
1723
1724 for (int i = 0; i < nargin; i++)
1725 {
1726 octave_value arg = new_args(i);
1727 iscell[i] = arg.iscell ();
1728 if (iscell[i])
1729 {
1730 cells[i] = arg.cell_value ();
1731 octave_idx_type n = ccells[i].numel ();
1732 if (n == 1)
1733 {
1734 iscell[i] = false;
1735 new_args(i) = ccells[i](0);
1736 }
1737 else if (numel == 1)
1738 {
1739 numel = n;
1740 dims = ccells[i].dims ();
1741 }
1742 else if (dims != ccells[i].dims ())
1743 error ("%s: cell arguments must have matching sizes", fcn_name);
1744 }
1745 }
1746
1747 for (int i = 0; i < nargout; i++)
1748 rcells[i].clear (dims);
1749
1750 for (octave_idx_type j = 0; j < numel; j++)
1751 {
1752 for (int i = 0; i < nargin; i++)
1753 if (iscell[i])
1754 new_args(i) = ccells[i](j);
1755
1756 octave_quit ();
1757
1758 const octave_value_list tmp = fcn (new_args, nargout);
1759
1760 if (tmp.length () < nargout)
1761 error ("%s: do_simple_cellfun: internal error", fcn_name);
1762
1763 for (int i = 0; i < nargout; i++)
1764 rcells[i](j) = tmp(i);
1765 }
1766
1767 retval.resize (nargout);
1768
1769 for (int i = 0; i < nargout; i++)
1770 retval(i) = rcells[i];
1771
1772 return retval;
1773}
1774
1777 const char *fcn_name, const octave_value_list& args)
1778{
1779 octave_value retval;
1780
1781 const octave_value_list tmp = do_simple_cellfun (fcn, fcn_name, args, 1);
1782
1783 if (tmp.length () > 0)
1784 retval = tmp(0);
1785
1786 return retval;
1787}
1788
1789DEFUN (isstudent, args, ,
1790 doc: /* -*- texinfo -*-
1791@deftypefn {} {@var{tf} =} isstudent ()
1792Return true if running in the student edition of @sc{matlab}.
1793
1794@code{isstudent} always returns false in Octave.
1795@seealso{false}
1796@end deftypefn */)
1797{
1798 if (args.length () != 0)
1799 print_usage ();
1800
1801 return ovl (false);
1802}
1803
1804/*
1805%!assert (isstudent (), false)
1806
1807%!error isstudent (1)
1808*/
1809
1810OCTAVE_END_NAMESPACE(octave)
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
Definition Cell.h:41
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:253
bool isvector() const
Definition dim-vector.h:391
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
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)
octave_idx_type length(octave_idx_type n=0) const
Definition idx-vector.h:518
octave_idx_type extent(octave_idx_type n) const
Definition idx-vector.h:521
std::string find_first_of(const string_vector &files) const
Definition load-path.cc:714
string_vector find_matching_dirs(const std::string &dir) const
Definition load-path.cc:673
string_vector find_all_first_of(const string_vector &files) const
Definition load-path.cc:787
std::string find_file(const std::string &file) const
Definition load-path.cc:583
std::string find_dir(const std::string &dir) const
Definition load-path.cc:632
std::string find_fcn_file(const std::string &fcn, const std::string &pack_name="")
Definition load-path.h:127
Helper class for make_valid_name function calls.
Definition utils.h:55
const std::string & get_replacement_style() const
Definition utils.h:84
make_valid_name_options()=default
Default options for make_valid_name function calls.
const std::string & get_prefix() const
Definition utils.h:88
static int set(int val)
Definition oct-errno.h:60
static octave_scalar_map list()
static int lookup(const std::string &name)
static int get()
Definition oct-errno.h:58
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition ovl.h:115
octave_idx_type length() const
Definition ovl.h:111
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
Array< std::string > cellstr_value() const
Definition ov.h:991
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
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:983
Array< octave_idx_type > octave_idx_type_vector_value(bool req_int=false, bool frc_str_conv=false, bool frc_vec_conv=false) const
octave_idx_type columns() const
Definition ov.h:547
dim_vector dims() const
Definition ov.h:541
bool empty() const
Definition str-vec.h:75
octave_idx_type numel() const
Definition str-vec.h:98
std::list< std::string > std_list() const
Definition str-vec.cc:172
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
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:1078
void warning_with_id(const char *id, const char *fmt,...)
Definition error.cc:1093
void error(const char *fmt,...)
Definition error.cc:1003
void warn_data_file_in_path(const std::string &fcn, const std::string &file)
Definition errwarn.cc:310
gh_manager & __get_gh_manager__()
load_path & __get_load_path__()
bool iskeyword(const std::string &s)
Definition lex.cc:1335
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
char * strsave(const char *s)
Definition lo-utils.cc:78
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:217
void flush_stdout()
Definition pager.cc:268
int octave_strncasecmp(const char *s1, const char *s2, size_t n)
int kbhit(bool wait)
Definition sysdep.cc:655
std::size_t vformat(std::ostream &os, const char *fmt, va_list args)
Definition utils.cc:1529
std::string asprintf(const char *fmt,...)
Definition utils.cc:1557
std::string do_string_escapes(const std::string &s)
Definition utils.cc:838
std::string find_data_file_in_load_path(const std::string &fcn, const std::string &file, bool require_regular_file)
Definition utils.cc:711
octave_idx_type dims_to_numel(const dim_vector &dims, const octave_value_list &idx_arg)
Definition utils.cc:1442
std::string contents_file_in_path(const std::string &dir)
Definition utils.cc:788
std::string undo_string_escapes(const std::string &s)
Definition utils.cc:1065
int almost_match(const std::string &std, const std::string &s, int min_match_len, int case_sens)
Definition utils.cc:412
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:428
Matrix identity_matrix(octave_idx_type nr, octave_idx_type nc)
Definition utils.cc:1482
std::string file_in_path(const std::string &name, const std::string &suffix)
Definition utils.cc:698
std::string vasprintf(const char *fmt, va_list args)
Definition utils.cc:1539
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition utils.cc:1377
bool valid_identifier(const char *s)
Definition utils.cc:79
FloatMatrix float_identity_matrix(octave_idx_type nr, octave_idx_type nc)
Definition utils.cc:1498
std::size_t format(std::ostream &os, const char *fmt,...)
Definition utils.cc:1514
void sleep(double seconds, bool do_graphics_events)
Definition utils.cc:1577
string_vector search_path_for_all_files(const std::string &path, const string_vector &names)
Definition utils.cc:528
const char * undo_string_escape(char c)
Definition utils.cc:1020
void display_file_lines(std::ostream &os, const std::string &file_name, int start, int end, int target_line, const std::string &marker, const std::string &who)
Definition utils.cc:807
octave_value_list Ferrno(const octave_value_list &args, int)
Definition utils.cc:1279
bool make_valid_name(std::string &str, const make_valid_name_options &options)
Modify str to be a valid variable name.
Definition utils.cc:137
std::string search_path_for_file(const std::string &path, const string_vector &names)
Definition utils.cc:517
octave_value_list do_simple_cellfun(octave_value_list(*fcn)(const octave_value_list &, int), const char *fcn_name, const octave_value_list &args, int nargout)
Definition utils.cc:1708
std::string fcn_file_in_path(const std::string &name)
Definition utils.cc:749
bool same_file(const std::string &f, const std::string &g)
Definition utils.cc:297
bool valid_identifier(const char *s)
Definition utils.cc:79
int octave_vasprintf_wrapper(char **buf, const char *fmt, va_list args)
F77_RET_T len
Definition xerbla.cc:61