changelog shortlog tags changeset files revisions annotate raw

src/utils.cc

changeset 10289: 4b124317dc38
parent:2d47356a7a1a
author: John W. Eaton <jwe@octave.org>
date: Tue Feb 09 20:58:55 2010 -0500 (36 minutes ago)
permissions: -rw-r--r--
description: base_properties::set_children: account for hidden children
1/*
2
3Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
4 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton
5
6This file is part of Octave.
7
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <cerrno>
29#include <climits>
30#include <cstring>
31
32#include <fstream>
33#include <iostream>
34#include <string>
35
36#include <sys/types.h>
37#include <unistd.h>
38
39#include "quit.h"
40
41#include "dir-ops.h"
42#include "file-ops.h"
43#include "file-stat.h"
44#include "lo-mappers.h"
45#include "oct-cmplx.h"
46#include "oct-env.h"
47#include "pathsearch.h"
48#include "str-vec.h"
49
50#include "Cell.h"
51#include <defaults.h>
52#include "defun.h"
53#include "dirfns.h"
54#include "error.h"
55#include "gripes.h"
56#include "input.h"
57#include "load-path.h"
58#include "oct-errno.h"
59#include "oct-hist.h"
60#include "oct-obj.h"
61#include "pager.h"
62#include "sysdep.h"
63#include "toplev.h"
64#include "unwind-prot.h"
65#include "utils.h"
66#include "variables.h"
67
68// Return TRUE if S is a valid identifier.
69
70bool
71valid_identifier (const char *s)
72{
73 if (! s || ! (isalpha (*s) || *s == '_' || *s == '$'))
74 return false;
75
76 while (*++s != '\0')
77 if (! (isalnum (*s) || *s == '_' || *s == '$'))
78 return false;
79
80 return true;
81}
82
83bool
84valid_identifier (const std::string& s)
85{
86 return valid_identifier (s.c_str ());
87}
88
89DEFUN (isvarname, args, ,
90 "-*- texinfo -*-\n\
91@deftypefn {Built-in Function} {} isvarname (@var{name})\n\
92Return true if @var{name} is a valid variable name\n\
93@end deftypefn")
94{
95 octave_value retval;
96
97 int argc = args.length () + 1;
98
99 string_vector argv = args.make_argv ("isvarname");
100
101 if (error_state)
102 return retval;
103
104 if (argc == 2)
105 retval = valid_identifier (argv[1]);
106 else
107 print_usage ();
108
109 return retval;
110}
111
112// Return TRUE if F and G are both names for the same file.
113
114bool
115same_file (const std::string& f, const std::string& g)
116{
117 return same_file_internal (f, g);
118}
119
120int
121almost_match (const std::string& std, const std::string& s, int min_match_len,
122 int case_sens)
123{
124 int stdlen = std.length ();
125 int slen = s.length ();
126
127 return (slen <= stdlen
128 && slen >= min_match_len
129 && (case_sens
130 ? (strncmp (std.c_str (), s.c_str (), slen) == 0)
131 : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0)));
132}
133
134// Ugh.
135
136int
137keyword_almost_match (const char * const *std, int *min_len, const std::string& s,
138 int min_toks_to_match, int max_toks)
139{
140 int status = 0;
141 int tok_count = 0;
142 int toks_matched = 0;
143
144 if (s.empty () || max_toks < 1)
145 return status;
146
147 char *kw = strsave (s.c_str ());
148
149 char *t = kw;
150 while (*t != '\0')
151 {
152 if (*t == '\t')
153 *t = ' ';
154 t++;
155 }
156
157 char *beg = kw;
158 while (*beg == ' ')
159 beg++;
160
161 if (*beg == '\0')
162 return status;
163
164
165 const char **to_match = new const char * [max_toks + 1];
166 const char * const *s1 = std;
167 const char **s2 = to_match;
168
169 if (! s1 || ! s2)
170 goto done;
171
172 s2[tok_count] = beg;
173 char *end;
174 while ((end = strchr (beg, ' ')) != 0)
175 {
176 *end = '\0';
177 beg = end + 1;
178
179 while (*beg == ' ')
180 beg++;
181
182 if (*beg == '\0')
183 break;
184
185 tok_count++;
186 if (tok_count >= max_toks)
187 goto done;
188
189 s2[tok_count] = beg;
190 }
191 s2[tok_count+1] = 0;
192
193 s2 = to_match;
194
195 for (;;)
196 {
197 if (! almost_match (*s1, *s2, min_len[toks_matched], 0))
198 goto done;
199
200 toks_matched++;
201
202 s1++;
203 s2++;
204
205 if (! *s2)
206 {
207 status = (toks_matched >= min_toks_to_match);
208 goto done;
209 }
210
211 if (! *s1)
212 goto done;
213 }
214
215 done:
216
217 delete [] kw;
218 delete [] to_match;
219
220 return status;
221}
222
223// Return non-zero if either NR or NC is zero. Return -1 if this
224// should be considered fatal; return 1 if this is ok.
225
226int
227empty_arg (const char * /* name */, octave_idx_type nr, octave_idx_type nc)
228{
229 return (nr == 0 || nc == 0);
230}
231
232// See if the given file is in the path.
233
234std::string
235search_path_for_file (const std::string& path, const string_vector& names)
236{
237 dir_path p (path);
238
239 return octave_env::make_absolute (p.find_first_of (names));
240}
241
242// Find all locations of the given file in the path.
243
244string_vector
245search_path_for_all_files (const std::string& path, const string_vector& names)
246{
247 dir_path p (path);
248
249 string_vector sv = p.find_all_first_of (names);
250
251 octave_idx_type len = sv.length ();
252
253 for (octave_idx_type i = 0; i < len; i++)
254 sv[i] = octave_env::make_absolute (sv[i]);
255
256 return sv;
257}
258
259static string_vector
260make_absolute (const string_vector& sv)
261{
262 octave_idx_type len = sv.length ();
263
264 string_vector retval (len);
265
266 for (octave_idx_type i = 0; i < len; i++)
267 retval[i] = octave_env::make_absolute (sv[i]);
268
269 return retval;
270}
271
272DEFUN (file_in_loadpath, args, ,
273 "-*- texinfo -*-\n\
274@deftypefn {Built-in Function} {} file_in_loadpath (@var{file})\n\
275@deftypefnx {Built-in Function} {} file_in_loadpath (@var{file}, \"all\")\n\
276\n\
277Return the absolute name of @var{file} if it can be found in\n\
278the list of directories specified by @code{path}.\n\
279If no file is found, return an empty matrix.\n\
280\n\
281If the first argument is a cell array of strings, search each\n\
282directory of the loadpath for element of the cell array and return\n\
283the first that matches.\n\
284\n\
285If the second optional argument @code{\"all\"} is supplied, return\n\
286a cell array containing the list of all files that have the same\n\
287name in the path. If no files are found, return an empty cell array.\n\
288@seealso{file_in_path, path}\n\
289@end deftypefn")
290{
291 octave_value retval;
292
293 int nargin = args.length ();
294
295 if (nargin == 1 || nargin == 2)
296 {
297 string_vector names = args(0).all_strings ();
298
299 if (! error_state && names.length () > 0)
300 {
301 if (nargin == 1)
302 {
303 std::string fname
304 = octave_env::make_absolute (load_path::find_first_of (names));
305
306 if (fname.empty ())
307 retval = Matrix ();
308 else
309 retval = fname;
310 }
311 else if (nargin == 2)
312 {
313 std::string opt = args(1).string_value ();
314
315 if (! error_state && opt == "all")
316 retval = Cell (make_absolute
317 (load_path::find_all_first_of (names)));
318 else
319 error ("file_in_loadpath: invalid option");
320 }
321 }
322 else
323 error ("file_in_loadpath: expecting string as first argument");
324 }
325 else
326 print_usage ();
327
328 return retval;
329}
330
331DEFUN (file_in_path, args, ,
332 "-*- texinfo -*-\n\
333@deftypefn {Built-in Function} {} file_in_path (@var{path}, @var{file})\n\
334@deftypefnx {Built-in Function} {} file_in_path (@var{path}, @var{file}, \"all\")\n\
335Return the absolute name of @var{file} if it can be found in\n\
336@var{path}. The value of @var{path} should be a colon-separated list of\n\
337directories in the format described for @code{path}. If no file\n\
338is found, return an empty matrix. For example,\n\
339\n\
340@example\n\
341@group\n\
342file_in_path (EXEC_PATH, \"sh\")\n\
343 @result{} \"/bin/sh\"\n\
344@end group\n\
345@end example\n\
346\n\
347If the second argument is a cell array of strings, search each\n\
348directory of the path for element of the cell array and return\n\
349the first that matches.\n\
350\n\
351If the third optional argument @code{\"all\"} is supplied, return\n\
352a cell array containing the list of all files that have the same\n\
353name in the path. If no files are found, return an empty cell array.\n\
354@seealso{file_in_loadpath}\n\
355@end deftypefn")
356{
357 octave_value retval;
358
359 int nargin = args.length ();
360
361 if (nargin == 2 || nargin == 3)
362 {
363 std::string path = args(0).string_value ();
364
365 if (! error_state)
366 {
367 string_vector names = args(1).all_strings ();
368
369 if (! error_state && names.length () > 0)
370 {
371 if (nargin == 2)
372 {
373 std::string fname = search_path_for_file (path, names);
374
375 if (fname.empty ())
376 retval = Matrix ();
377 else
378 retval = fname;
379 }
380 else if (nargin == 3)
381 {
382 std::string opt = args(2).string_value ();
383
384 if (! error_state && opt == "all")
385 retval = Cell (make_absolute
386 (search_path_for_all_files (path, names)));
387 else
388 error ("file_in_path: invalid option");
389 }
390 }
391 else
392 error ("file_in_path: expecting string as second argument");
393 }
394 else
395 error ("file_in_path: expecting string as first argument");
396 }
397 else
398 print_usage ();
399
400 return retval;
401}
402
403std::string
404file_in_path (const std::string& name, const std::string& suffix)
405{
406 std::string nm = name;
407
408 if (! suffix.empty ())
409 nm.append (suffix);
410
411 return octave_env::make_absolute (load_path::find_file (nm));
412}
413
414// See if there is an function file in the path. If so, return the
415// full path to the file.
416
417std::string
418fcn_file_in_path (const std::string& name)
419{
420 std::string retval;
421
422 int len = name.length ();
423
424 if (len > 0)
425 {
426 if (octave_env::absolute_pathname (name))
427 {
428 file_stat fs (name);
429
430 if (fs.exists ())
431 retval = name;
432 }
433 else if (len > 2 && name [len - 2] == '.' && name [len - 1] == 'm')
434 retval = load_path::find_fcn_file (name.substr (0, len-2));
435 else
436 {
437 std::string fname = name;
438 size_t pos = name.find_first_of (Vfilemarker);
439 if (pos != std::string::npos)
440 fname = name.substr (0, pos);
441
442 retval = load_path::find_fcn_file (fname);
443 }
444 }
445
446 return retval;
447}
448
449// See if there is a directory called "name" in the path and if it
450// contains a Contents.m file return the full path to this file.
451
452std::string
453contents_file_in_path (const std::string& dir)
454{
455 std::string retval;
456
457 if (dir.length () > 0)
458 {
459 std::string tcontents = file_ops::concat (load_path::find_dir (dir),
460 std::string ("Contents.m"));
461
462 file_stat fs (tcontents);
463
464 if (fs.exists ())
465 retval = octave_env::make_absolute (tcontents);
466 }
467
468 return retval;
469}
470
471// See if there is a .oct file in the path. If so, return the
472// full path to the file.
473
474std::string
475oct_file_in_path (const std::string& name)
476{
477 std::string retval;
478
479 int len = name.length ();
480
481 if (len > 0)
482 {
483 if (octave_env::absolute_pathname (name))
484 {
485 file_stat fs (name);
486
487 if (fs.exists ())
488 retval = name;
489 }
490 else if (len > 4 && name [len - 4] == '.' && name [len - 3] == 'o'
491 && name [len - 2] == 'c' && name [len - 1] == 't')
492 retval = load_path::find_oct_file (name.substr (0, len-4));
493 else
494 retval = load_path::find_oct_file (name);
495 }
496
497 return retval;
498}
499
500// See if there is a .mex file in the path. If so, return the
501// full path to the file.
502
503std::string
504mex_file_in_path (const std::string& name)
505{
506 std::string retval;
507
508 int len = name.length ();
509
510 if (len > 0)
511 {
512 if (octave_env::absolute_pathname (name))
513 {
514 file_stat fs (name);
515
516 if (fs.exists ())
517 retval = name;
518 }
519 else if (len > 4 && name [len - 4] == '.' && name [len - 3] == 'm'
520 && name [len - 2] == 'e' && name [len - 1] == 'x')
521 retval = load_path::find_mex_file (name.substr (0, len-4));
522 else
523 retval = load_path::find_mex_file (name);
524 }
525
526 return retval;
527}
528
529// Replace backslash escapes in a string with the real values.
530
531std::string
532do_string_escapes (const std::string& s)
533{
534 std::string retval;
535
536 size_t i = 0;
537 size_t j = 0;
538 size_t len = s.length ();
539
540 retval.resize (len);
541
542 while (j < len)
543 {
544 if (s[j] == '\\' && j+1 < len)
545 {
546 switch (s[++j])
547 {
548 case '0':
549 retval[i] = '\0';
550 break;
551
552 case 'a':
553 retval[i] = '\a';
554 break;
555
556 case 'b': // backspace
557 retval[i] = '\b';
558 break;
559
560 case 'f': // formfeed
561 retval[i] = '\f';
562 break;
563
564 case 'n': // newline
565 retval[i] = '\n';
566 break;
567
568 case 'r': // carriage return
569 retval[i] = '\r';
570 break;
571
572 case 't': // horizontal tab
573 retval[i] = '\t';
574 break;
575
576 case 'v': // vertical tab
577 retval[i] = '\v';
578 break;
579
580 case '\\': // backslash
581 retval[i] = '\\';
582 break;
583
584 case '\'': // quote
585 retval[i] = '\'';
586 break;
587
588 case '"': // double quote
589 retval[i] = '"';
590 break;
591
592 default:
593 warning ("unrecognized escape sequence `\\%c' --\
594 converting to `%c'", s[j], s[j]);
595 retval[i] = s[j];
596 break;
597 }
598 }
599 else
600 {
601 retval[i] = s[j];
602 }
603
604 i++;
605 j++;
606 }
607
608 retval.resize (i);
609
610 return retval;
611}
612
613DEFUN (do_string_escapes, args, ,
614 "-*- texinfo -*-\n\
615@deftypefn {Built-in Function} {} do_string_escapes (@var{string})\n\
616Convert special characters in @var{string} to their escaped forms.\n\
617@end deftypefn")
618{
619 octave_value retval;
620
621 int nargin = args.length ();
622
623 if (nargin == 1)
624 {
625 if (args(0).is_string ())
626 retval = do_string_escapes (args(0).string_value ());
627 else
628 error ("do_string_escapes: argument must be a string");
629 }
630 else
631 print_usage ();
632
633 return retval;
634}
635
636const char *
637undo_string_escape (char c)
638{
639 if (! c)
640 return "";
641
642 switch (c)
643 {
644 case '\0':
645 return "\\0";
646
647 case '\a':
648 return "\\a";
649
650 case '\b': // backspace
651 return "\\b";
652
653 case '\f': // formfeed
654 return "\\f";
655
656 case '\n': // newline
657 return "\\n";
658
659 case '\r': // carriage return
660 return "\\r";
661
662 case '\t': // horizontal tab
663 return "\\t";
664
665 case '\v': // vertical tab
666 return "\\v";
667
668 case '\\': // backslash
669 return "\\\\";
670
671 case '"': // double quote
672 return "\\\"";
673
674 default:
675 {
676 static char retval[2];
677 retval[0] = c;
678 retval[1] = '\0';
679 return retval;
680 }
681 }
682}
683
684std::string
685undo_string_escapes (const std::string& s)
686{
687 std::string retval;
688
689 for (size_t i = 0; i < s.length (); i++)
690 retval.append (undo_string_escape (s[i]));
691
692 return retval;
693}
694
695DEFUN (undo_string_escapes, args, ,
696 "-*- texinfo -*-\n\
697@deftypefn {Built-in Function} {} undo_string_escapes (@var{s})\n\
698Converts special characters in strings back to their escaped forms. For\n\
699example, the expression\n\
700\n\
701@example\n\
702bell = \"\\a\";\n\
703@end example\n\
704\n\
705@noindent\n\
706assigns the value of the alert character (control-g, ASCII code 7) to\n\
707the string variable @code{bell}. If this string is printed, the\n\
708system will ring the terminal bell (if it is possible). This is\n\
709normally the desired outcome. However, sometimes it is useful to be\n\
710able to print the original representation of the string, with the\n\
711special characters replaced by their escape sequences. For example,\n\
712\n\
713@example\n\
714@group\n\
715octave:13> undo_string_escapes (bell)\n\
716ans = \\a\n\
717@end group\n\
718@end example\n\
719\n\
720@noindent\n\
721replaces the unprintable alert character with its printable\n\
722representation.\n\
723@end deftypefn")
724{
725 octave_value retval;
726
727 int nargin = args.length ();
728
729 if (nargin == 1)
730 {
731 if (args(0).is_string ())
732 retval = undo_string_escapes (args(0).string_value ());
733 else
734 error ("undo_string_escapes: argument must be a string");
735 }
736 else
737 print_usage ();
738
739 return retval;
740}
741
742DEFUN (is_absolute_filename, args, ,
743 "-*- texinfo -*-\n\
744@deftypefn {Built-in Function} {} is_absolute_filename (@var{file})\n\
745Return true if @var{file} is an absolute filename.\n\
746@end deftypefn")
747{
748 octave_value retval = false;
749
750 if (args.length () == 1)
751 retval = (args(0).is_string ()
752 && octave_env::absolute_pathname (args(0).string_value ()));
753 else
754 print_usage ();
755
756 return retval;
757}
758
759DEFUN (is_rooted_relative_filename, args, ,
760 "-*- texinfo -*-\n\
761@deftypefn {Built-in Function} {} is_rooted_relative_filename (@var{file})\n\
762Return true if @var{file} is a rooted-relative filename.\n\
763@end deftypefn")
764{
765 octave_value retval = false;
766
767 if (args.length () == 1)
768 retval = (args(0).is_string ()
769 && octave_env::rooted_relative_pathname (args(0).string_value ()));
770 else
771 print_usage ();
772
773 return retval;
774}
775
776DEFUN (make_absolute_filename, args, ,
777 "-*- texinfo -*-\n\
778@deftypefn {Built-in Function} {} make_absolute_filename (@var{file})\n\
779Return the full name of @var{file}, relative to the current directory.\n\
780@end deftypefn")
781{
782 octave_value retval = std::string ();
783
784 if (args.length () == 1)
785 {
786 std::string nm = args(0).string_value ();
787
788 if (! error_state)
789 retval = octave_env::make_absolute (nm);
790 else
791 error ("make_absolute_filename: expecting argument to be a file name");
792 }
793 else
794 print_usage ();
795
796 return retval;
797}
798
799DEFUN (find_dir_in_path, args, ,
800 "-*- texinfo -*-\n\
801@deftypefn {Built-in Function} {} find_dir_in_path (@var{dir}, \"all\")\n\
802Return the full name of the path element matching @var{dir}. The\n\
803match is performed at the end of each path element. For example, if\n\
804@var{dir} is @code{\"foo/bar\"}, it matches the path element\n\
805@code{\"/some/dir/foo/bar\"}, but not @code{\"/some/dir/foo/bar/baz\"}\n\
806or @code{\"/some/dir/allfoo/bar\"}.\n\
807\n\
808The second argument is optional. If it is supplied, return a cell array\n\
809containing all the directory names that match.\n\
810@end deftypefn")
811{
812 octave_value retval = std::string ();
813
814 int nargin = args.length ();
815
816 std::string dir;
817
818 if (nargin == 1 || nargin == 2)
819 {
820 dir = args(0).string_value ();
821
822 if (! error_state)
823 {
824 if (nargin == 1)
825 retval = load_path::find_dir (dir);
826 else if (nargin == 2)
827 retval = Cell (load_path::find_matching_dirs (dir));
828 }
829 else
830 error ("find_dir_in_path: expecting argument to be a directory name");
831 }
832 else
833 print_usage ();
834
835 return retval;
836}
837
838DEFUNX ("errno", Ferrno, args, ,
839 "-*- texinfo -*-\n\
840@deftypefn {Built-in Function} {@var{err} =} errno ()\n\
841@deftypefnx {Built-in Function} {@var{err} =} errno (@var{val})\n\
842@deftypefnx {Built-in Function} {@var{err} =} errno (@var{name})\n\
843Return the current value of the system-dependent variable errno,\n\
844set its value to @var{val} and return the previous value, or return\n\
845the named error code given @var{name} as a character string, or -1\n\
846if @var{name} is not found.\n\
847@end deftypefn")
848{
849 octave_value retval;
850
851 int nargin = args.length ();
852
853 if (nargin == 1)
854 {
855 if (args(0).is_string ())
856 {
857 std::string nm = args(0).string_value ();
858
859 if (! error_state)
860 retval = octave_errno::lookup (nm);
861 else
862 error ("errno: expecting character string argument");
863 }
864 else
865 {
866 int val = args(0).int_value ();
867
868 if (! error_state)
869 retval = octave_errno::set (val);
870 else
871 error ("errno: expecting integer argument");
872 }
873 }
874 else if (nargin == 0)
875 retval = octave_errno::get ();
876 else
877 print_usage ();
878
879 return retval;
880}
881
882DEFUN (errno_list, args, ,
883 "-*- texinfo -*-\n\
884@deftypefn {Built-in Function} {} errno_list ()\n\
885Return a structure containing the system-dependent errno values.\n\
886@end deftypefn")
887{
888 octave_value retval;
889
890 if (args.length () == 0)
891 retval = octave_errno::list ();
892 else
893 print_usage ();
894
895 return retval;
896}
897
898static void
899check_dimensions (octave_idx_type& nr, octave_idx_type& nc, const char *warnfor)
900{
901 if (nr < 0 || nc < 0)
902 {
903 warning_with_id ("Octave:neg-dim-as-zero",
904 "%s: converting negative dimension to zero", warnfor);
905
906 nr = (nr < 0) ? 0 : nr;
907 nc = (nc < 0) ? 0 : nc;
908 }
909}
910
911void
912check_dimensions (dim_vector& dim, const char *warnfor)
913{
914 bool neg = false;
915
916 for (int i = 0; i < dim.length (); i++)
917 {
918 if (dim(i) < 0)
919 {
920 dim(i) = 0;
921 neg = true;
922 }
923 }
924
925 if (neg)
926 warning_with_id ("Octave:neg-dim-as-zero",
927 "%s: converting negative dimension to zero", warnfor);
928}
929
930
931void
932get_dimensions (const octave_value& a, const char *warn_for,
933 dim_vector& dim)
934{
935 if (a.is_scalar_type ())
936 {
937 dim.resize (2);
938 dim(0) = a.int_value ();
939 dim(1) = dim(0);
940 }
941 else
942 {
943 octave_idx_type nr = a.rows ();
944 octave_idx_type nc = a.columns ();
945
946 if (nr == 1 || nc == 1)
947 {
948 Array<double> v = a.vector_value ();
949
950 if (error_state)
951 return;
952
953 octave_idx_type n = v.length ();
954 dim.resize (n);
955 for (octave_idx_type i = 0; i < n; i++)
956 dim(i) = static_cast<int> (fix (v(i)));
957 }
958 else
959 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
960 }
961
962 if (! error_state)
963 check_dimensions (dim, warn_for); // May set error_state.
964}
965
966
967void
968get_dimensions (const octave_value& a, const char *warn_for,
969 octave_idx_type& nr, octave_idx_type& nc)
970{
971 if (a.is_scalar_type ())
972 {
973 nr = nc = a.int_value ();
974 }
975 else
976 {
977 nr = a.rows ();
978 nc = a.columns ();
979
980 if ((nr == 1 && nc == 2) || (nr == 2 && nc == 1))
981 {
982 Array<double> v = a.vector_value ();
983
984 if (error_state)
985 return;
986
987 nr = static_cast<octave_idx_type> (fix (v (0)));
988 nc = static_cast<octave_idx_type> (fix (v (1)));
989 }
990 else
991 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
992 }
993
994 if (! error_state)
995 check_dimensions (nr, nc, warn_for); // May set error_state.
996}
997
998void
999get_dimensions (const octave_value& a, const octave_value& b,
1000 const char *warn_for, octave_idx_type& nr, octave_idx_type& nc)
1001{
1002 nr = a.is_empty () ? 0 : a.int_value ();
1003 nc = b.is_empty () ? 0 : b.int_value ();
1004
1005 if (error_state)
1006 error ("%s: expecting two scalar arguments", warn_for);
1007 else
1008 check_dimensions (nr, nc, warn_for); // May set error_state.
1009}
1010
1011octave_idx_type
1012dims_to_numel (const dim_vector& dims, const octave_value_list& idx)
1013{
1014 octave_idx_type retval;
1015
1016 octave_idx_type len = idx.length ();
1017
1018 if (len == 0)
1019 retval = dims.numel ();
1020 else
1021 {
1022 const dim_vector dv = dims.redim (len);
1023 retval = 1;
1024 for (octave_idx_type i = 0; i < len; i++)
1025 {
1026 octave_value idxi = idx(i);
1027 if (idxi.is_magic_colon ())
1028 retval *= dv(i);
1029 else if (idxi.is_numeric_type ())
1030 retval *= idxi.numel ();
1031 else
1032 {
1033 idx_vector jdx = idxi.index_vector ();
1034 if (error_state)
1035 break;
1036 retval *= jdx.length (dv(i));
1037 }
1038 }
1039 }
1040
1041 return retval;
1042}
1043
1044void
1045decode_subscripts (const char* name, const octave_value& arg,
1046 std::string& type_string,
1047 std::list<octave_value_list>& idx)
1048{
1049 Octave_map m = arg.map_value ();
1050
1051 if (! error_state
1052 && m.nfields () == 2 && m.contains ("type") && m.contains ("subs"))
1053 {
1054 Cell& type = m.contents ("type");
1055 Cell& subs = m.contents ("subs");
1056
1057 type_string = std::string (type.length(), '\0');
1058
1059 for (int k = 0; k < type.length (); k++)
1060 {
1061 std::string item = type(k).string_value ();
1062
1063 if (! error_state)
1064 {
1065 if (item == "{}")
1066 type_string[k] = '{';
1067 else if (item == "()")
1068 type_string[k] = '(';
1069 else if (item == ".")
1070 type_string[k] = '.';
1071 else
1072 {
1073 error("%s: invalid indexing type `%s'", name, item.c_str ());
1074 return;
1075 }
1076 }
1077 else
1078 {
1079 error ("%s: expecting type(%d) to be a character string",
1080 name, k+1);
1081 return;
1082 }
1083
1084 octave_value_list idx_item;
1085
1086 if (subs(k).is_string ())
1087 idx_item(0) = subs(k);
1088 else if (subs(k).is_cell ())
1089 {
1090 Cell subs_cell = subs(k).cell_value ();
1091
1092 for (int n = 0; n < subs_cell.length (); n++)
1093 {
1094 if (subs_cell(n).is_string ()
1095 && subs_cell(n).string_value () == ":")
1096 idx_item(n) = octave_value(octave_value::magic_colon_t);
1097 else
1098 idx_item(n) = subs_cell(n);
1099 }
1100 }
1101 else
1102 {
1103 error ("%s: expecting subs(%d) to be a character string or cell array",
1104 name, k+1);
1105 return;
1106 }
1107
1108 idx.push_back (idx_item);
1109 }
1110 }
1111 else
1112 error ("%s: second argument must be a structure with fields `type' and `subs'", name);
1113}
1114
1115Matrix
1116identity_matrix (octave_idx_type nr, octave_idx_type nc)
1117{
1118 Matrix m (nr, nc, 0.0);
1119
1120 if (nr > 0 && nc > 0)
1121 {
1122 octave_idx_type n = std::min (nr, nc);
1123
1124 for (octave_idx_type i = 0; i < n; i++)
1125 m (i, i) = 1.0;
1126 }
1127
1128 return m;
1129}
1130
1131FloatMatrix
1132float_identity_matrix (octave_idx_type nr, octave_idx_type nc)
1133{
1134 FloatMatrix m (nr, nc, 0.0);
1135
1136 if (nr > 0 && nc > 0)
1137 {
1138 octave_idx_type n = std::min (nr, nc);
1139
1140 for (octave_idx_type i = 0; i < n; i++)
1141 m (i, i) = 1.0;
1142 }
1143
1144 return m;
1145}
1146
1147int
1148octave_format (std::ostream& os, const char *fmt, ...)
1149{
1150 int retval = -1;
1151
1152 va_list args;
1153 va_start (args, fmt);
1154
1155 retval = octave_vformat (os, fmt, args);
1156
1157 va_end (args);
1158
1159 return retval;
1160}
1161
1162int
1163octave_vformat (std::ostream& os, const char *fmt, va_list args)
1164{
1165 int retval = -1;
1166
1167#if defined (__GNUG__) && !CXX_ISO_COMPLIANT_LIBRARY
1168
1169 std::streambuf *sb = os.rdbuf ();
1170
1171 if (sb)
1172 {
1173 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1174
1175 retval = sb->vform (fmt, args);
1176
1177 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1178 }
1179
1180#else
1181
1182 char *s = octave_vsnprintf (fmt, args);
1183
1184 if (s)
1185 {
1186 os << s;
1187
1188 retval = strlen (s);
1189 }
1190
1191#endif
1192
1193 return retval;
1194}
1195
1196// We manage storage. User should not free it, and its contents are
1197// only valid until next call to vsnprintf.
1198
1199// Interrupts might happen if someone makes a call with something that
1200// will require a very large buffer. If we are interrupted in that
1201// case, we should make the buffer size smaller for the next call.
1202
1203#define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF \
1204 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_1; \
1205 delete [] buf; \
1206 buf = 0; \
1207 size = initial_size; \
1208 octave_rethrow_exception (); \
1209 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_2
1210
1211#if defined __GNUC__ && defined __va_copy
1212#define SAVE_ARGS(saved_args, args) __va_copy (saved_args, args)
1213#elif defined va_copy
1214#define SAVE_ARGS(saved_args, args) va_copy (saved_args, args)
1215#else
1216#define SAVE_ARGS(saved_args, args) saved_args = args
1217#endif
1218
1219char *
1220octave_vsnprintf (const char *fmt, va_list args)
1221{
1222 static const size_t initial_size = 100;
1223
1224 static size_t size = initial_size;
1225
1226 static char *buf = 0;
1227
1228 int nchars = 0;
1229
1230 if (! buf)
1231 buf = new char [size];
1232
1233 if (! buf)
1234 return 0;
1235
1236 while (1)
1237 {
1238 va_list saved_args;
1239
1240 SAVE_ARGS (saved_args, args);
1241
1242 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF;
1243
1244 nchars = octave_raw_vsnprintf (buf, size, fmt, saved_args);
1245
1246 va_end (saved_args);
1247
1248 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1249
1250 if (nchars > -1 && nchars < size)
1251 break;
1252 else
1253 {
1254 delete [] buf;
1255
1256 size = nchars + 1;;
1257
1258 buf = new char [size];
1259
1260 if (! buf)
1261 return 0;
1262 }
1263 }
1264
1265 return buf;
1266}
1267
1268char *
1269octave_snprintf (const char *fmt, ...)
1270{
1271 char *retval = 0;
1272
1273 va_list args;
1274 va_start (args, fmt);
1275
1276 retval = octave_vsnprintf (fmt, args);
1277
1278 va_end (args);
1279
1280 return retval;
1281}
1282
1283void
1284octave_sleep (double seconds)
1285{
1286 if (seconds > 0)
1287 {
1288 double t;
1289
1290 unsigned int usec
1291 = static_cast<unsigned int> (modf (seconds, &t) * 1000000);
1292
1293 unsigned int sec
1294 = (t > UINT_MAX) ? UINT_MAX : static_cast<unsigned int> (t);
1295
1296 // Versions of these functions that accept unsigned int args are
1297 // defined in cutils.c.
1298 octave_sleep (sec);
1299 octave_usleep (usec);
1300
1301 octave_quit ();
1302 }
1303}
1304
1305DEFUN (isindex, args, ,
1306 "-*- texinfo -*-\n\
1307@deftypefn {Built-in Function} {} isindex (@var{ind}, @var{n})\n\
1308Returns true if @var{ind} is a valid index. Valid indices can be\n\
1309either positive integers (though possibly real data), or logical arrays.\n\
1310If present, @var{n} specifies the extent of the dimension to be indexed.\n\
1311Note that, if possible, the internal conversion result is cached so that\n\
1312subsequent indexing will not perform the checking again.\n\
1313@end deftypefn")
1314{
1315 octave_value retval;
1316 int nargin = args.length ();
1317 octave_idx_type n = 0;
1318
1319 if (nargin == 2)
1320 n = args(1).idx_type_value ();
1321 else if (nargin != 1)
1322 print_usage ();
1323
1324 if (! error_state)
1325 {
1326 unwind_protect frame;
1327 frame.protect_var (error_state);
1328 frame.protect_var (discard_error_messages);
1329 discard_error_messages = true;
1330
1331 try
1332 {
1333 idx_vector idx = args(0).index_vector ();
1334 if (! error_state)
1335 {
1336 if (nargin == 2)
1337 retval = idx.extent (n) <= n;
1338 else
1339 retval = true;
1340 }
1341 else
1342 retval = false;
1343 }
1344 catch (octave_execution_exception)
1345 {
1346 retval = false;
1347 }
1348 }
1349
1350 return retval;
1351}
1352
1353octave_value_list
1354do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
1355 const char *fun_name, const octave_value_list& args,
1356 int nargout)
1357{
1358 octave_value_list new_args = args, retval;
1359 int nargin = args.length ();
1360 OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
1361 OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
1362 OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
1363
1364 const Cell *ccells = cells;
1365
1366 octave_idx_type numel = 1;
1367 dim_vector dims (1, 1);
1368
1369 for (int i = 0; i < nargin; i++)
1370 {
1371 octave_value arg = new_args(i);
1372 iscell[i] = arg.is_cell ();
1373 if (iscell[i])
1374 {
1375 cells[i] = arg.cell_value ();
1376 octave_idx_type n = ccells[i].numel ();
1377 if (n == 1)
1378 {
1379 iscell[i] = false;
1380 new_args(i) = ccells[i](0);
1381 }
1382 else if (numel == 1)
1383 {
1384 numel = n;
1385 dims = ccells[i].dims ();
1386 }
1387 else if (dims != ccells[i].dims ())
1388 {
1389 error ("%s: cell arguments must have matching sizes", fun_name);
1390 break;
1391 }
1392 }
1393 }
1394
1395 if (! error_state)
1396 {
1397 for (int i = 0; i < nargout; i++)
1398 rcells[i].clear (dims);
1399
1400 for (octave_idx_type j = 0; j < numel; j++)
1401 {
1402 for (int i = 0; i < nargin; i++)
1403 if (iscell[i])
1404 new_args(i) = ccells[i](j);
1405
1406 octave_quit ();
1407
1408 const octave_value_list tmp = fun (new_args, nargout);
1409
1410 if (tmp.length () < nargout)
1411 {
1412 error ("%s: do_simple_cellfun: internal error", fun_name);
1413 break;
1414 }
1415 else
1416 {
1417 for (int i = 0; i < nargout; i++)
1418 rcells[i](j) = tmp(i);
1419 }
1420 }
1421 }
1422
1423 if (! error_state)
1424 {
1425 retval.resize (nargout);
1426 for (int i = 0; i < nargout; i++)
1427 retval(i) = rcells[i];
1428 }
1429
1430 return retval;
1431}
1432
1433octave_value
1434do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
1435 const char *fun_name, const octave_value_list& args)
1436{
1437 octave_value retval;
1438 const octave_value_list tmp = do_simple_cellfun (fun, fun_name, args, 1);
1439 if (tmp.length () > 0)
1440 retval = tmp(0);
1441
1442 return retval;
1443}