utils.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <cerrno>
00029 #include <climits>
00030 #include <cstring>
00031 
00032 #include <fstream>
00033 #include <iostream>
00034 #include <string>
00035 
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038 
00039 #include "vasnprintf.h"
00040 
00041 #include "quit.h"
00042 
00043 #include "dir-ops.h"
00044 #include "file-ops.h"
00045 #include "file-stat.h"
00046 #include "lo-mappers.h"
00047 #include "lo-utils.h"
00048 #include "oct-cmplx.h"
00049 #include "oct-env.h"
00050 #include "pathsearch.h"
00051 #include "str-vec.h"
00052 
00053 #include "Cell.h"
00054 #include <defaults.h>
00055 #include "defun.h"
00056 #include "dirfns.h"
00057 #include "error.h"
00058 #include "gripes.h"
00059 #include "input.h"
00060 #include "lex.h"
00061 #include "load-path.h"
00062 #include "oct-errno.h"
00063 #include "oct-hist.h"
00064 #include "oct-obj.h"
00065 #include "ov-range.h"
00066 #include "pager.h"
00067 #include "parse.h"
00068 #include "sysdep.h"
00069 #include "toplev.h"
00070 #include "unwind-prot.h"
00071 #include "utils.h"
00072 #include "variables.h"
00073 
00074 // Return TRUE if S is a valid identifier.
00075 
00076 bool
00077 valid_identifier (const char *s)
00078 {
00079   if (! s || ! (isalpha (*s) || *s == '_' || *s == '$'))
00080      return false;
00081 
00082   while (*++s != '\0')
00083     if (! (isalnum (*s) || *s == '_' || *s == '$'))
00084       return false;
00085 
00086   return true;
00087 }
00088 
00089 bool
00090 valid_identifier (const std::string& s)
00091 {
00092   return valid_identifier (s.c_str ());
00093 }
00094 
00095 DEFUN (isvarname, args, ,
00096   "-*- texinfo -*-\n\
00097 @deftypefn {Built-in Function} {} isvarname (@var{name})\n\
00098 Return true if @var{name} is a valid variable name.\n\
00099 @seealso{iskeyword, exist, who}\n\
00100 @end deftypefn")
00101 {
00102   octave_value retval;
00103 
00104   int argc = args.length () + 1;
00105 
00106   string_vector argv = args.make_argv ("isvarname");
00107 
00108   if (error_state)
00109     return retval;
00110 
00111   if (argc == 2)
00112     retval = valid_identifier (argv[1]) && ! is_keyword (argv[1]);
00113   else
00114     print_usage ();
00115 
00116   return retval;
00117 }
00118 
00119 /*
00120 %!error isvarname ();
00121 %!error isvarname ("foo", "bar");
00122 
00123 %!assert (isvarname ("foo"), true);
00124 %!assert (isvarname ("_foo"), true);
00125 %!assert (isvarname ("_1"), true);
00126 %!assert (isvarname ("1foo"), false);
00127 %!assert (isvarname (""), false);
00128 */
00129 
00130 // Return TRUE if F and G are both names for the same file.
00131 
00132 bool
00133 same_file (const std::string& f, const std::string& g)
00134 {
00135   return same_file_internal (f, g);
00136 }
00137 
00138 int
00139 almost_match (const std::string& std, const std::string& s, int min_match_len,
00140               int case_sens)
00141 {
00142   int stdlen = std.length ();
00143   int slen = s.length ();
00144 
00145   return (slen <= stdlen
00146           && slen >= min_match_len
00147           && (case_sens
00148               ? (strncmp (std.c_str (), s.c_str (), slen) == 0)
00149               : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0)));
00150 }
00151 
00152 // Ugh.
00153 
00154 int
00155 keyword_almost_match (const char * const *std, int *min_len, const std::string& s,
00156                       int min_toks_to_match, int max_toks)
00157 {
00158   int status = 0;
00159   int tok_count = 0;
00160   int toks_matched = 0;
00161 
00162   if (s.empty () || max_toks < 1)
00163     return status;
00164 
00165   char *kw = strsave (s.c_str ());
00166 
00167   char *t = kw;
00168   while (*t != '\0')
00169     {
00170       if (*t == '\t')
00171         *t = ' ';
00172       t++;
00173     }
00174 
00175   char *beg = kw;
00176   while (*beg == ' ')
00177     beg++;
00178 
00179   if (*beg == '\0')
00180     return status;
00181 
00182 
00183   const char **to_match = new const char * [max_toks + 1];
00184   const char * const *s1 = std;
00185   const char **s2 = to_match;
00186 
00187   if (! s1 || ! s2)
00188     goto done;
00189 
00190   s2[tok_count] = beg;
00191   char *end;
00192   while ((end = strchr (beg, ' ')) != 0)
00193     {
00194       *end = '\0';
00195       beg = end + 1;
00196 
00197       while (*beg == ' ')
00198         beg++;
00199 
00200       if (*beg == '\0')
00201         break;
00202 
00203       tok_count++;
00204       if (tok_count >= max_toks)
00205         goto done;
00206 
00207       s2[tok_count] = beg;
00208     }
00209   s2[tok_count+1] = 0;
00210 
00211   s2 = to_match;
00212 
00213   for (;;)
00214     {
00215       if (! almost_match (*s1, *s2, min_len[toks_matched], 0))
00216         goto done;
00217 
00218       toks_matched++;
00219 
00220       s1++;
00221       s2++;
00222 
00223       if (! *s2)
00224         {
00225           status = (toks_matched >= min_toks_to_match);
00226           goto done;
00227         }
00228 
00229       if (! *s1)
00230         goto done;
00231     }
00232 
00233  done:
00234 
00235   delete [] kw;
00236   delete [] to_match;
00237 
00238   return status;
00239 }
00240 
00241 // Return non-zero if either NR or NC is zero.  Return -1 if this
00242 // should be considered fatal; return 1 if this is ok.
00243 
00244 int
00245 empty_arg (const char * /* name */, octave_idx_type nr, octave_idx_type nc)
00246 {
00247   return (nr == 0 || nc == 0);
00248 }
00249 
00250 // See if the given file is in the path.
00251 
00252 std::string
00253 search_path_for_file (const std::string& path, const string_vector& names)
00254 {
00255   dir_path p (path);
00256 
00257   return octave_env::make_absolute (p.find_first_of (names));
00258 }
00259 
00260 // Find all locations of the given file in the path.
00261 
00262 string_vector
00263 search_path_for_all_files (const std::string& path, const string_vector& names)
00264 {
00265   dir_path p (path);
00266 
00267   string_vector sv = p.find_all_first_of (names);
00268 
00269   octave_idx_type len = sv.length ();
00270 
00271   for (octave_idx_type i = 0; i < len; i++)
00272     sv[i] = octave_env::make_absolute (sv[i]);
00273 
00274   return sv;
00275 }
00276 
00277 static string_vector
00278 make_absolute (const string_vector& sv)
00279 {
00280   octave_idx_type len = sv.length ();
00281 
00282   string_vector retval (len);
00283 
00284   for (octave_idx_type i = 0; i < len; i++)
00285     retval[i] = octave_env::make_absolute (sv[i]);
00286 
00287   return retval;
00288 }
00289 
00290 DEFUN (file_in_loadpath, args, ,
00291   "-*- texinfo -*-\n\
00292 @deftypefn  {Built-in Function} {} file_in_loadpath (@var{file})\n\
00293 @deftypefnx {Built-in Function} {} file_in_loadpath (@var{file}, \"all\")\n\
00294 \n\
00295 Return the absolute name of @var{file} if it can be found in\n\
00296 the list of directories specified by @code{path}.\n\
00297 If no file is found, return an empty character string.\n\
00298 \n\
00299 If the first argument is a cell array of strings, search each\n\
00300 directory of the loadpath for element of the cell array and return\n\
00301 the first that matches.\n\
00302 \n\
00303 If the second optional argument @code{\"all\"} is supplied, return\n\
00304 a cell array containing the list of all files that have the same\n\
00305 name in the path.  If no files are found, return an empty cell array.\n\
00306 @seealso{file_in_path, path}\n\
00307 @end deftypefn")
00308 {
00309   octave_value retval;
00310 
00311   int nargin = args.length ();
00312 
00313   if (nargin == 1 || nargin == 2)
00314     {
00315       string_vector names = args(0).all_strings ();
00316 
00317       if (! error_state && names.length () > 0)
00318         {
00319           if (nargin == 1)
00320             retval = octave_env::make_absolute (load_path::find_first_of (names));
00321           else if (nargin == 2)
00322             {
00323               std::string opt = args(1).string_value ();
00324 
00325               if (! error_state && opt == "all")
00326                 retval = Cell (make_absolute
00327                                (load_path::find_all_first_of (names)));
00328               else
00329                 error ("file_in_loadpath: invalid option");
00330             }
00331         }
00332       else
00333         error ("file_in_loadpath: FILE argument must be a string");
00334     }
00335   else
00336     print_usage ();
00337 
00338   return retval;
00339 }
00340 
00341 /*
00342 %!error file_in_loadpath ();
00343 %!error file_in_loadpath ("foo", "bar", 1);
00344 
00345 %!test
00346 %! f = file_in_loadpath ("plot.m");
00347 %! assert (ischar (f));
00348 %! assert (! isempty (f));
00349 
00350 %!test
00351 %! f = file_in_loadpath ("$$probably_!!_not_&&_a_!!_file$$");
00352 %! assert (f, "");
00353 
00354 %!test
00355 %! lst = file_in_loadpath ("$$probably_!!_not_&&_a_!!_file$$", "all");
00356 %! assert (lst, {});
00357 */
00358 
00359 DEFUN (file_in_path, args, ,
00360   "-*- texinfo -*-\n\
00361 @deftypefn  {Built-in Function} {} file_in_path (@var{path}, @var{file})\n\
00362 @deftypefnx {Built-in Function} {} file_in_path (@var{path}, @var{file}, \"all\")\n\
00363 Return the absolute name of @var{file} if it can be found in\n\
00364 @var{path}.  The value of @var{path} should be a colon-separated list of\n\
00365 directories in the format described for @code{path}.  If no file\n\
00366 is found, return an empty character string.  For example:\n\
00367 \n\
00368 @example\n\
00369 @group\n\
00370 file_in_path (EXEC_PATH, \"sh\")\n\
00371      @result{} \"/bin/sh\"\n\
00372 @end group\n\
00373 @end example\n\
00374 \n\
00375 If the second argument is a cell array of strings, search each\n\
00376 directory of the path for element of the cell array and return\n\
00377 the first that matches.\n\
00378 \n\
00379 If the third optional argument @code{\"all\"} is supplied, return\n\
00380 a cell array containing the list of all files that have the same\n\
00381 name in the path.  If no files are found, return an empty cell array.\n\
00382 @seealso{file_in_loadpath}\n\
00383 @end deftypefn")
00384 {
00385   octave_value retval;
00386 
00387   int nargin = args.length ();
00388 
00389   if (nargin == 2 || nargin == 3)
00390     {
00391       std::string path = args(0).string_value ();
00392 
00393       if (! error_state)
00394         {
00395           string_vector names = args(1).all_strings ();
00396 
00397           if (! error_state && names.length () > 0)
00398             {
00399               if (nargin == 2)
00400                 retval = search_path_for_file (path, names);
00401               else if (nargin == 3)
00402                 {
00403                   std::string opt = args(2).string_value ();
00404 
00405                   if (! error_state && opt == "all")
00406                     retval = Cell (make_absolute
00407                                    (search_path_for_all_files (path, names)));
00408                   else
00409                     error ("file_in_path: invalid option");
00410                 }
00411             }
00412           else
00413             error ("file_in_path: all arguments must be strings");
00414         }
00415       else
00416         error ("file_in_path: PATH must be a string");
00417     }
00418   else
00419     print_usage ();
00420 
00421   return retval;
00422 }
00423 
00424 /*
00425 %!error file_in_path ();
00426 %!error file_in_path ("foo");
00427 %!error file_in_path ("foo", "bar", "baz", 1);
00428 
00429 %!test
00430 %! f = file_in_path (path (), "plot.m");
00431 %! assert (ischar (f));
00432 %! assert (! isempty (f));
00433 
00434 %!test
00435 %! f = file_in_path (path (), "$$probably_!!_not_&&_a_!!_file$$");
00436 %! assert (f, "");
00437 
00438 %!test
00439 %! lst = file_in_path (path (), "$$probably_!!_not_&&_a_!!_file$$", "all");
00440 %! assert (lst, {});
00441 */
00442 
00443 std::string
00444 file_in_path (const std::string& name, const std::string& suffix)
00445 {
00446   std::string nm = name;
00447 
00448   if (! suffix.empty ())
00449     nm.append (suffix);
00450 
00451   return octave_env::make_absolute (load_path::find_file (nm));
00452 }
00453 
00454 // See if there is an function file in the path.  If so, return the
00455 // full path to the file.
00456 
00457 std::string
00458 fcn_file_in_path (const std::string& name)
00459 {
00460   std::string retval;
00461 
00462   int len = name.length ();
00463 
00464   if (len > 0)
00465     {
00466       if (octave_env::absolute_pathname (name))
00467         {
00468           file_stat fs (name);
00469 
00470           if (fs.exists ())
00471             retval = name;
00472         }
00473       else if (len > 2 && name [len - 2] == '.' && name [len - 1] == 'm')
00474         retval = load_path::find_fcn_file (name.substr (0, len-2));
00475       else
00476         {
00477           std::string fname = name;
00478           size_t pos = name.find_first_of (Vfilemarker);
00479           if (pos != std::string::npos)
00480             fname = name.substr (0, pos);
00481 
00482           retval = load_path::find_fcn_file (fname);
00483         }
00484     }
00485 
00486   return retval;
00487 }
00488 
00489 // See if there is a directory called "name" in the path and if it
00490 // contains a Contents.m file return the full path to this file.
00491 
00492 std::string
00493 contents_file_in_path (const std::string& dir)
00494 {
00495   std::string retval;
00496 
00497   if (dir.length () > 0)
00498     {
00499       std::string tcontents = file_ops::concat (load_path::find_dir (dir),
00500                                                 std::string ("Contents.m"));
00501 
00502       file_stat fs (tcontents);
00503 
00504       if (fs.exists ())
00505         retval = octave_env::make_absolute (tcontents);
00506     }
00507 
00508   return retval;
00509 }
00510 
00511 // See if there is a .oct file in the path.  If so, return the
00512 // full path to the file.
00513 
00514 std::string
00515 oct_file_in_path (const std::string& name)
00516 {
00517   std::string retval;
00518 
00519   int len = name.length ();
00520 
00521   if (len > 0)
00522     {
00523       if (octave_env::absolute_pathname (name))
00524         {
00525           file_stat fs (name);
00526 
00527           if (fs.exists ())
00528             retval = name;
00529         }
00530       else if (len > 4 && name [len - 4] == '.' && name [len - 3] == 'o'
00531                && name [len - 2] == 'c' && name [len - 1] == 't')
00532         retval = load_path::find_oct_file (name.substr (0, len-4));
00533       else
00534         retval = load_path::find_oct_file (name);
00535     }
00536 
00537   return retval;
00538 }
00539 
00540 // See if there is a .mex file in the path.  If so, return the
00541 // full path to the file.
00542 
00543 std::string
00544 mex_file_in_path (const std::string& name)
00545 {
00546   std::string retval;
00547 
00548   int len = name.length ();
00549 
00550   if (len > 0)
00551     {
00552       if (octave_env::absolute_pathname (name))
00553         {
00554           file_stat fs (name);
00555 
00556           if (fs.exists ())
00557             retval = name;
00558         }
00559       else if (len > 4 && name [len - 4] == '.' && name [len - 3] == 'm'
00560                && name [len - 2] == 'e' && name [len - 1] == 'x')
00561         retval = load_path::find_mex_file (name.substr (0, len-4));
00562       else
00563         retval = load_path::find_mex_file (name);
00564     }
00565 
00566   return retval;
00567 }
00568 
00569 // Replace backslash escapes in a string with the real values.
00570 
00571 std::string
00572 do_string_escapes (const std::string& s)
00573 {
00574   std::string retval;
00575 
00576   size_t i = 0;
00577   size_t j = 0;
00578   size_t len = s.length ();
00579 
00580   retval.resize (len);
00581 
00582   while (j < len)
00583     {
00584       if (s[j] == '\\' && j+1 < len)
00585         {
00586           switch (s[++j])
00587             {
00588             case '0':
00589               retval[i] = '\0';
00590               break;
00591 
00592             case 'a':
00593               retval[i] = '\a';
00594               break;
00595 
00596             case 'b': // backspace
00597               retval[i] = '\b';
00598               break;
00599 
00600             case 'f': // formfeed
00601               retval[i] = '\f';
00602               break;
00603 
00604             case 'n': // newline
00605               retval[i] = '\n';
00606               break;
00607 
00608             case 'r': // carriage return
00609               retval[i] = '\r';
00610               break;
00611 
00612             case 't': // horizontal tab
00613               retval[i] = '\t';
00614               break;
00615 
00616             case 'v': // vertical tab
00617               retval[i] = '\v';
00618               break;
00619 
00620             case '\\': // backslash
00621               retval[i] = '\\';
00622               break;
00623 
00624             case '\'': // quote
00625               retval[i] = '\'';
00626               break;
00627 
00628             case '"': // double quote
00629               retval[i] = '"';
00630               break;
00631 
00632             default:
00633               warning ("unrecognized escape sequence '\\%c' --\
00634  converting to '%c'", s[j], s[j]);
00635               retval[i] = s[j];
00636               break;
00637             }
00638         }
00639       else
00640         {
00641           retval[i] = s[j];
00642         }
00643 
00644       i++;
00645       j++;
00646     }
00647 
00648   retval.resize (i);
00649 
00650   return retval;
00651 }
00652 
00653 DEFUN (do_string_escapes, args, ,
00654   "-*- texinfo -*-\n\
00655 @deftypefn {Built-in Function} {} do_string_escapes (@var{string})\n\
00656 Convert special characters in @var{string} to their escaped forms.\n\
00657 @end deftypefn")
00658 {
00659   octave_value retval;
00660 
00661   int nargin = args.length ();
00662 
00663   if (nargin == 1)
00664     {
00665       if (args(0).is_string ())
00666         retval = do_string_escapes (args(0).string_value ());
00667       else
00668         error ("do_string_escapes: STRING argument must be of type string");
00669     }
00670   else
00671     print_usage ();
00672 
00673   return retval;
00674 }
00675 
00676 /*
00677 %!error do_string_escapes ();
00678 %!error do_string_escapes ("foo", "bar");
00679 
00680 %!assert (do_string_escapes ('foo\nbar'), "foo\nbar");
00681 %!assert (do_string_escapes ("foo\\nbar"), "foo\nbar");
00682 %!assert (do_string_escapes ("foo\\nbar"), ["foo", char(10), "bar"]);
00683 %!assert ("foo\nbar", ["foo", char(10), "bar"]);
00684 
00685 %!assert (do_string_escapes ('\a\b\f\n\r\t\v'), "\a\b\f\n\r\t\v");
00686 %!assert (do_string_escapes ("\\a\\b\\f\\n\\r\\t\\v"), "\a\b\f\n\r\t\v");
00687 %!assert (do_string_escapes ("\\a\\b\\f\\n\\r\\t\\v"),
00688 %!        char ([7, 8, 12, 10, 13, 9, 11]));
00689 %!assert ("\a\b\f\n\r\t\v", char ([7, 8, 12, 10, 13, 9, 11]));
00690 */
00691 
00692 const char *
00693 undo_string_escape (char c)
00694 {
00695   if (! c)
00696     return "";
00697 
00698   switch (c)
00699     {
00700     case '\0':
00701       return "\\0";
00702 
00703     case '\a':
00704       return "\\a";
00705 
00706     case '\b': // backspace
00707       return "\\b";
00708 
00709     case '\f': // formfeed
00710       return "\\f";
00711 
00712     case '\n': // newline
00713       return "\\n";
00714 
00715     case '\r': // carriage return
00716       return "\\r";
00717 
00718     case '\t': // horizontal tab
00719       return "\\t";
00720 
00721     case '\v': // vertical tab
00722       return "\\v";
00723 
00724     case '\\': // backslash
00725       return "\\\\";
00726 
00727     case '"': // double quote
00728       return "\\\"";
00729 
00730     default:
00731       {
00732         static char retval[2];
00733         retval[0] = c;
00734         retval[1] = '\0';
00735         return retval;
00736       }
00737     }
00738 }
00739 
00740 std::string
00741 undo_string_escapes (const std::string& s)
00742 {
00743   std::string retval;
00744 
00745   for (size_t i = 0; i < s.length (); i++)
00746     retval.append (undo_string_escape (s[i]));
00747 
00748   return retval;
00749 }
00750 
00751 DEFUN (undo_string_escapes, args, ,
00752   "-*- texinfo -*-\n\
00753 @deftypefn {Built-in Function} {} undo_string_escapes (@var{s})\n\
00754 Convert special characters in strings back to their escaped forms.  For\n\
00755 example, the expression\n\
00756 \n\
00757 @example\n\
00758 bell = \"\\a\";\n\
00759 @end example\n\
00760 \n\
00761 @noindent\n\
00762 assigns the value of the alert character (control-g, ASCII code 7) to\n\
00763 the string variable @code{bell}.  If this string is printed, the\n\
00764 system will ring the terminal bell (if it is possible).  This is\n\
00765 normally the desired outcome.  However, sometimes it is useful to be\n\
00766 able to print the original representation of the string, with the\n\
00767 special characters replaced by their escape sequences.  For example,\n\
00768 \n\
00769 @example\n\
00770 @group\n\
00771 octave:13> undo_string_escapes (bell)\n\
00772 ans = \\a\n\
00773 @end group\n\
00774 @end example\n\
00775 \n\
00776 @noindent\n\
00777 replaces the unprintable alert character with its printable\n\
00778 representation.\n\
00779 @end deftypefn")
00780 {
00781   octave_value retval;
00782 
00783   int nargin = args.length ();
00784 
00785   if (nargin == 1)
00786     {
00787       if (args(0).is_string ())
00788         retval = undo_string_escapes (args(0).string_value ());
00789       else
00790         error ("undo_string_escapes: S argument must be a string");
00791     }
00792   else
00793     print_usage ();
00794 
00795   return retval;
00796 }
00797 
00798 /*
00799 %!error undo_string_escapes ();
00800 %!error undo_string_escapes ("foo", "bar");
00801 
00802 %!assert (undo_string_escapes ("foo\nbar"), 'foo\nbar');
00803 %!assert (undo_string_escapes ("foo\nbar"), "foo\\nbar");
00804 %!assert (undo_string_escapes (["foo", char(10), "bar"]), "foo\\nbar");
00805 
00806 %!assert (undo_string_escapes ("\a\b\f\n\r\t\v"), '\a\b\f\n\r\t\v');
00807 %!assert (undo_string_escapes ("\a\b\f\n\r\t\v"), "\\a\\b\\f\\n\\r\\t\\v");
00808 %!assert (undo_string_escapes (char ([7, 8, 12, 10, 13, 9, 11])),
00809 %!        "\\a\\b\\f\\n\\r\\t\\v");
00810 */
00811 
00812 DEFUN (is_absolute_filename, args, ,
00813   "-*- texinfo -*-\n\
00814 @deftypefn {Built-in Function} {} is_absolute_filename (@var{file})\n\
00815 Return true if @var{file} is an absolute filename.\n\
00816 @seealso{is_rooted_relative_filename, make_absolute_filename, isdir}\n\
00817 @end deftypefn")
00818 {
00819   octave_value retval = false;
00820 
00821   if (args.length () == 1)
00822     retval = (args(0).is_string ()
00823               && octave_env::absolute_pathname (args(0).string_value ()));
00824   else
00825     print_usage ();
00826 
00827   return retval;
00828 }
00829 
00830 /*
00831 %!error is_absolute_filename ();
00832 %!error is_absolute_filename ("foo", "bar");
00833 
00834 FIXME -- we need system-dependent tests here.
00835 */
00836 
00837 DEFUN (is_rooted_relative_filename, args, ,
00838   "-*- texinfo -*-\n\
00839 @deftypefn {Built-in Function} {} is_rooted_relative_filename (@var{file})\n\
00840 Return true if @var{file} is a rooted-relative filename.\n\
00841 @seealso{is_absolute_filename, make_absolute_filename, isdir}\n\
00842 @end deftypefn")
00843 {
00844   octave_value retval = false;
00845 
00846   if (args.length () == 1)
00847     retval = (args(0).is_string ()
00848               && octave_env::rooted_relative_pathname (args(0).string_value ()));
00849   else
00850     print_usage ();
00851 
00852   return retval;
00853 }
00854 
00855 /*
00856 %!error is_rooted_relative_filename ();
00857 %!error is_rooted_relative_filename ("foo", "bar");
00858 
00859 FIXME -- we need system-dependent tests here.
00860 */
00861 
00862 DEFUN (make_absolute_filename, args, ,
00863   "-*- texinfo -*-\n\
00864 @deftypefn {Built-in Function} {} make_absolute_filename (@var{file})\n\
00865 Return the full name of @var{file}, relative to the current directory.\n\
00866 @seealso{is_absolute_filename, is_rooted_relative_filename, isdir}\n\
00867 @end deftypefn")
00868 {
00869   octave_value retval = std::string ();
00870 
00871   if (args.length () == 1)
00872     {
00873       std::string nm = args(0).string_value ();
00874 
00875       if (! error_state)
00876         retval = octave_env::make_absolute (nm);
00877       else
00878         error ("make_absolute_filename: FILE argument must be a file name");
00879     }
00880   else
00881     print_usage ();
00882 
00883   return retval;
00884 }
00885 
00886 /*
00887 %!error make_absolute_filename ();
00888 %!error make_absolute_filename ("foo", "bar");
00889 
00890 FIXME -- we need system-dependent tests here.
00891 */
00892 
00893 DEFUN (find_dir_in_path, args, ,
00894   "-*- texinfo -*-\n\
00895 @deftypefn  {Built-in Function} {} find_dir_in_path (@var{dir})\n\
00896 @deftypefnx {Built-in Function} {} find_dir_in_path (@var{dir}, \"all\")\n\
00897 Return the full name of the path element matching @var{dir}.  The\n\
00898 match is performed at the end of each path element.  For example, if\n\
00899 @var{dir} is @code{\"foo/bar\"}, it matches the path element\n\
00900 @code{\"/some/dir/foo/bar\"}, but not @code{\"/some/dir/foo/bar/baz\"}\n\
00901 or @code{\"/some/dir/allfoo/bar\"}.\n\
00902 \n\
00903 The second argument is optional.  If it is supplied, return a cell array\n\
00904 containing all name matches rather than just the first.\n\
00905 @end deftypefn")
00906 {
00907   octave_value retval = std::string ();
00908 
00909   int nargin = args.length ();
00910 
00911   std::string dir;
00912 
00913   if (nargin == 1 || nargin == 2)
00914     {
00915       dir = args(0).string_value ();
00916 
00917       if (! error_state)
00918         {
00919           if (nargin == 1)
00920             retval = load_path::find_dir (dir);
00921           else if (nargin == 2)
00922             retval = Cell (load_path::find_matching_dirs (dir));
00923         }
00924       else
00925         error ("find_dir_in_path: DIR must be a directory name");
00926     }
00927   else
00928     print_usage ();
00929 
00930   return retval;
00931 }
00932 
00933 /*
00934 %!error find_dir_in_path ();
00935 %!error find_dir_in_path ("foo", "bar", 1);
00936 
00937 FIXME -- need to create tests using current path, pathsep, and dirsep.
00938 */
00939 
00940 DEFUNX ("errno", Ferrno, args, ,
00941   "-*- texinfo -*-\n\
00942 @deftypefn  {Built-in Function} {@var{err} =} errno ()\n\
00943 @deftypefnx {Built-in Function} {@var{err} =} errno (@var{val})\n\
00944 @deftypefnx {Built-in Function} {@var{err} =} errno (@var{name})\n\
00945 Return the current value of the system-dependent variable errno,\n\
00946 set its value to @var{val} and return the previous value, or return\n\
00947 the named error code given @var{name} as a character string, or -1\n\
00948 if @var{name} is not found.\n\
00949 @end deftypefn")
00950 {
00951   octave_value retval;
00952 
00953   int nargin = args.length ();
00954 
00955   if (nargin == 1)
00956     {
00957       if (args(0).is_string ())
00958         {
00959           std::string nm = args(0).string_value ();
00960 
00961           if (! error_state)
00962             retval = octave_errno::lookup (nm);
00963           else
00964             error ("errno: expecting character string argument");
00965         }
00966       else
00967         {
00968           int val = args(0).int_value ();
00969 
00970           if (! error_state)
00971             retval = octave_errno::set (val);
00972           else
00973             error ("errno: expecting integer argument");
00974         }
00975     }
00976   else if (nargin == 0)
00977     retval = octave_errno::get ();
00978   else
00979     print_usage ();
00980 
00981   return retval;
00982 }
00983 
00984 /*
00985 %!error errno ("foo", 1);
00986 
00987 %!assert (isnumeric (errno ()));
00988 
00989 %!test
00990 %! lst = errno_list ();
00991 %! fns = fieldnames (lst);
00992 %! oldval = errno (fns{1});
00993 %! assert (isnumeric (oldval));
00994 %! errno (oldval);
00995 %! newval = errno ();
00996 %! assert (oldval, newval);
00997 */
00998 
00999 DEFUN (errno_list, args, ,
01000   "-*- texinfo -*-\n\
01001 @deftypefn {Built-in Function} {} errno_list ()\n\
01002 Return a structure containing the system-dependent errno values.\n\
01003 @end deftypefn")
01004 {
01005   octave_value retval;
01006 
01007   if (args.length () == 0)
01008     retval = octave_errno::list ();
01009   else
01010     print_usage ();
01011 
01012   return retval;
01013 }
01014 
01015 /*
01016 %!error errno_list ("foo");
01017 
01018 %!assert (isstruct (errno_list ()));
01019 */
01020 
01021 static void
01022 check_dimensions (octave_idx_type& nr, octave_idx_type& nc, const char *warnfor)
01023 {
01024   if (nr < 0 || nc < 0)
01025     {
01026       warning_with_id ("Octave:neg-dim-as-zero",
01027                        "%s: converting negative dimension to zero", warnfor);
01028 
01029       nr = (nr < 0) ? 0 : nr;
01030       nc = (nc < 0) ? 0 : nc;
01031     }
01032 }
01033 
01034 void
01035 check_dimensions (dim_vector& dim, const char *warnfor)
01036 {
01037   bool neg = false;
01038 
01039   for (int i = 0; i < dim.length (); i++)
01040     {
01041       if (dim(i) < 0)
01042         {
01043           dim(i) = 0;
01044           neg = true;
01045         }
01046     }
01047 
01048   if (neg)
01049     warning_with_id ("Octave:neg-dim-as-zero",
01050                      "%s: converting negative dimension to zero", warnfor);
01051 }
01052 
01053 
01054 void
01055 get_dimensions (const octave_value& a, const char *warn_for,
01056                 dim_vector& dim)
01057 {
01058   if (a.is_scalar_type ())
01059     {
01060       dim.resize (2);
01061       dim(0) = a.int_value ();
01062       dim(1) = dim(0);
01063     }
01064   else
01065     {
01066       octave_idx_type nr = a.rows ();
01067       octave_idx_type nc = a.columns ();
01068 
01069       if (nr == 1 || nc == 1)
01070         {
01071           Array<double> v = a.vector_value ();
01072 
01073           if (error_state)
01074             return;
01075 
01076           octave_idx_type n = v.length ();
01077           dim.resize (n);
01078           for (octave_idx_type i = 0; i < n; i++)
01079             dim(i) = static_cast<int> (fix (v(i)));
01080         }
01081       else
01082         error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
01083     }
01084 
01085   if (! error_state)
01086     check_dimensions (dim, warn_for); // May set error_state.
01087 }
01088 
01089 
01090 void
01091 get_dimensions (const octave_value& a, const char *warn_for,
01092                 octave_idx_type& nr, octave_idx_type& nc)
01093 {
01094   if (a.is_scalar_type ())
01095     {
01096       nr = nc = a.int_value ();
01097     }
01098   else
01099     {
01100       nr = a.rows ();
01101       nc = a.columns ();
01102 
01103       if ((nr == 1 && nc == 2) || (nr == 2 && nc == 1))
01104         {
01105           Array<double> v = a.vector_value ();
01106 
01107           if (error_state)
01108             return;
01109 
01110           nr = static_cast<octave_idx_type> (fix (v (0)));
01111           nc = static_cast<octave_idx_type> (fix (v (1)));
01112         }
01113       else
01114         error ("%s (A): use %s (size (A)) instead", warn_for, warn_for);
01115     }
01116 
01117   if (! error_state)
01118     check_dimensions (nr, nc, warn_for); // May set error_state.
01119 }
01120 
01121 void
01122 get_dimensions (const octave_value& a, const octave_value& b,
01123                 const char *warn_for, octave_idx_type& nr, octave_idx_type& nc)
01124 {
01125   nr = a.is_empty () ? 0 : a.int_value ();
01126   nc = b.is_empty () ? 0 : b.int_value ();
01127 
01128   if (error_state)
01129     error ("%s: expecting two scalar arguments", warn_for);
01130   else
01131     check_dimensions (nr, nc, warn_for); // May set error_state.
01132 }
01133 
01134 octave_idx_type
01135 dims_to_numel (const dim_vector& dims, const octave_value_list& idx)
01136 {
01137   octave_idx_type retval;
01138 
01139   octave_idx_type len = idx.length ();
01140 
01141   if (len == 0)
01142     retval = dims.numel ();
01143   else
01144     {
01145       const dim_vector dv = dims.redim (len);
01146       retval = 1;
01147       for (octave_idx_type i = 0; i < len; i++)
01148         {
01149           octave_value idxi = idx(i);
01150           if (idxi.is_magic_colon ())
01151             retval *= dv(i);
01152           else if (idxi.is_numeric_type ())
01153             retval *= idxi.numel ();
01154           else
01155             {
01156               idx_vector jdx = idxi.index_vector ();
01157               if (error_state)
01158                 break;
01159               retval *= jdx.length (dv(i));
01160             }
01161         }
01162     }
01163 
01164   return retval;
01165 }
01166 
01167 Matrix
01168 identity_matrix (octave_idx_type nr, octave_idx_type nc)
01169 {
01170   Matrix m (nr, nc, 0.0);
01171 
01172   if (nr > 0 && nc > 0)
01173     {
01174       octave_idx_type n = std::min (nr, nc);
01175 
01176       for (octave_idx_type i = 0; i < n; i++)
01177         m (i, i) = 1.0;
01178     }
01179 
01180   return m;
01181 }
01182 
01183 FloatMatrix
01184 float_identity_matrix (octave_idx_type nr, octave_idx_type nc)
01185 {
01186   FloatMatrix m (nr, nc, 0.0);
01187 
01188   if (nr > 0 && nc > 0)
01189     {
01190       octave_idx_type n = std::min (nr, nc);
01191 
01192       for (octave_idx_type i = 0; i < n; i++)
01193         m (i, i) = 1.0;
01194     }
01195 
01196   return m;
01197 }
01198 
01199 size_t
01200 octave_format (std::ostream& os, const char *fmt, ...)
01201 {
01202   size_t retval;
01203 
01204   va_list args;
01205   va_start (args, fmt);
01206 
01207   retval = octave_vformat (os, fmt, args);
01208 
01209   va_end (args);
01210 
01211   return retval;
01212 }
01213 
01214 size_t
01215 octave_vformat (std::ostream& os, const char *fmt, va_list args)
01216 {
01217   std::string s = octave_vasprintf (fmt, args);
01218 
01219   os << s;
01220 
01221   return s.length ();
01222 }
01223 
01224 std::string
01225 octave_vasprintf (const char *fmt, va_list args)
01226 {
01227   std::string retval;
01228 
01229   char *result;
01230 
01231   int status = gnulib::vasprintf (&result, fmt, args);
01232 
01233   if (status >= 0)
01234     {
01235       retval = result;
01236       ::free (result);
01237     }
01238 
01239   return retval;
01240 }
01241 
01242 std::string
01243 octave_asprintf (const char *fmt, ...)
01244 {
01245   std::string retval;
01246 
01247   va_list args;
01248   va_start (args, fmt);
01249 
01250   retval = octave_vasprintf (fmt, args);
01251 
01252   va_end (args);
01253 
01254   return retval;
01255 }
01256 
01257 void
01258 octave_sleep (double seconds)
01259 {
01260   if (seconds > 0)
01261     {
01262       double t;
01263 
01264       unsigned int usec
01265         = static_cast<unsigned int> (modf (seconds, &t) * 1000000);
01266 
01267       unsigned int sec
01268         = (t > UINT_MAX) ? UINT_MAX : static_cast<unsigned int> (t);
01269 
01270       // Versions of these functions that accept unsigned int args are
01271       // defined in cutils.c.
01272       octave_sleep (sec);
01273       octave_usleep (usec);
01274 
01275       octave_quit ();
01276     }
01277 }
01278 
01279 DEFUN (isindex, args, ,
01280   "-*- texinfo -*-\n\
01281 @deftypefn  {Built-in Function} {} isindex (@var{ind})\n\
01282 @deftypefnx {Built-in Function} {} isindex (@var{ind}, @var{n})\n\
01283 Return true if @var{ind} is a valid index.  Valid indices are\n\
01284 either positive integers (although possibly of real data type), or logical\n\
01285 arrays.  If present, @var{n} specifies the maximum extent of the dimension\n\
01286 to be indexed.  When possible the internal result is cached so that\n\
01287 subsequent indexing using @var{ind} will not perform the check again.\n\
01288 @end deftypefn")
01289 {
01290   octave_value retval;
01291   int nargin = args.length ();
01292   octave_idx_type n = 0;
01293 
01294   if (nargin == 2)
01295     n = args(1).idx_type_value ();
01296   else if (nargin != 1)
01297     print_usage ();
01298 
01299   if (! error_state)
01300     {
01301       unwind_protect frame;
01302 
01303       frame.protect_var (Vallow_noninteger_range_as_index);
01304       Vallow_noninteger_range_as_index = false;
01305 
01306       frame.protect_var (error_state);
01307 
01308       frame.protect_var (discard_error_messages);
01309       discard_error_messages = true;
01310 
01311       try
01312         {
01313           idx_vector idx = args(0).index_vector ();
01314           if (! error_state)
01315             {
01316               if (nargin == 2)
01317                 retval = idx.extent (n) <= n;
01318               else
01319                 retval = true;
01320             }
01321           else
01322             retval = false;
01323         }
01324       catch (octave_execution_exception)
01325         {
01326           retval = false;
01327         }
01328     }
01329 
01330   return retval;
01331 }
01332 
01333 /*
01334 %!error isindex ();
01335 
01336 %!assert (isindex ([1, 2, 3]));
01337 %!assert (isindex (1:3));
01338 %!assert (isindex ([1, 2, -3]), false);
01339 */
01340 
01341 octave_value_list
01342 do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
01343                    const char *fun_name, const octave_value_list& args,
01344                    int nargout)
01345 {
01346   octave_value_list new_args = args, retval;
01347   int nargin = args.length ();
01348   OCTAVE_LOCAL_BUFFER (bool, iscell, nargin);
01349   OCTAVE_LOCAL_BUFFER (Cell, cells, nargin);
01350   OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout);
01351 
01352   const Cell *ccells = cells;
01353 
01354   octave_idx_type numel = 1;
01355   dim_vector dims (1, 1);
01356 
01357   for (int i = 0; i < nargin; i++)
01358     {
01359       octave_value arg = new_args(i);
01360       iscell[i] = arg.is_cell ();
01361       if (iscell[i])
01362         {
01363           cells[i] = arg.cell_value ();
01364           octave_idx_type n = ccells[i].numel ();
01365           if (n == 1)
01366             {
01367               iscell[i] = false;
01368               new_args(i) = ccells[i](0);
01369             }
01370           else if (numel == 1)
01371             {
01372               numel = n;
01373               dims = ccells[i].dims ();
01374             }
01375           else if (dims != ccells[i].dims ())
01376             {
01377               error ("%s: cell arguments must have matching sizes", fun_name);
01378               break;
01379             }
01380         }
01381     }
01382 
01383   if (! error_state)
01384     {
01385       for (int i = 0; i < nargout; i++)
01386         rcells[i].clear (dims);
01387 
01388       for (octave_idx_type j = 0; j < numel; j++)
01389         {
01390           for (int i = 0; i < nargin; i++)
01391             if (iscell[i])
01392               new_args(i) = ccells[i](j);
01393 
01394           octave_quit ();
01395 
01396           const octave_value_list tmp = fun (new_args, nargout);
01397 
01398           if (tmp.length () < nargout)
01399             {
01400               error ("%s: do_simple_cellfun: internal error", fun_name);
01401               break;
01402             }
01403           else
01404             {
01405               for (int i = 0; i < nargout; i++)
01406                 rcells[i](j) = tmp(i);
01407             }
01408         }
01409     }
01410 
01411   if (! error_state)
01412     {
01413       retval.resize (nargout);
01414       for (int i = 0; i < nargout; i++)
01415         retval(i) = rcells[i];
01416     }
01417 
01418   return retval;
01419 }
01420 
01421 octave_value
01422 do_simple_cellfun (octave_value_list (*fun) (const octave_value_list&, int),
01423                    const char *fun_name, const octave_value_list& args)
01424 {
01425   octave_value retval;
01426   const octave_value_list tmp = do_simple_cellfun (fun, fun_name, args, 1);
01427   if (tmp.length () > 0)
01428     retval = tmp(0);
01429 
01430   return retval;
01431 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines