00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #include <cerrno>
00028 #include <cstdio>
00029 #include <cstddef>
00030 #include <cstdlib>
00031 #include <cstring>
00032
00033 #include <sstream>
00034 #include <string>
00035
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038
00039 #include "file-ops.h"
00040 #include "file-stat.h"
00041 #include "glob-match.h"
00042 #include "oct-env.h"
00043 #include "pathsearch.h"
00044 #include "str-vec.h"
00045
00046 #include "Cell.h"
00047 #include "defun.h"
00048 #include "dir-ops.h"
00049 #include "dirfns.h"
00050 #include "error.h"
00051 #include "gripes.h"
00052 #include "input.h"
00053 #include "load-path.h"
00054 #include "oct-obj.h"
00055 #include "pager.h"
00056 #include "procstream.h"
00057 #include "sysdep.h"
00058 #include "toplev.h"
00059 #include "unwind-prot.h"
00060 #include "utils.h"
00061 #include "variables.h"
00062
00063
00064
00065 static bool Vconfirm_recursive_rmdir = true;
00066
00067
00068 octave_time Vlast_chdir_time = 0.0;
00069
00070 static int
00071 octave_change_to_directory (const std::string& newdir)
00072 {
00073 int cd_ok = octave_env::chdir (file_ops::tilde_expand (newdir));
00074
00075 if (cd_ok)
00076 {
00077 Vlast_chdir_time.stamp ();
00078
00079
00080
00081
00082 load_path::update ();
00083 }
00084 else
00085 error ("%s: %s", newdir.c_str (), gnulib::strerror (errno));
00086
00087 return cd_ok;
00088 }
00089
00090 DEFUN (cd, args, nargout,
00091 "-*- texinfo -*-\n\
00092 @deftypefn {Command} {} cd dir\n\
00093 @deftypefnx {Command} {} chdir dir\n\
00094 Change the current working directory to @var{dir}. If @var{dir} is\n\
00095 omitted, the current directory is changed to the user's home\n\
00096 directory. For example,\n\
00097 \n\
00098 @example\n\
00099 cd ~/octave\n\
00100 @end example\n\
00101 \n\
00102 @noindent\n\
00103 changes the current working directory to @file{~/octave}. If the\n\
00104 directory does not exist, an error message is printed and the working\n\
00105 directory is not changed.\n\
00106 @seealso{mkdir, rmdir, dir}\n\
00107 @end deftypefn")
00108 {
00109 octave_value_list retval;
00110
00111 int argc = args.length () + 1;
00112
00113 string_vector argv = args.make_argv ("cd");
00114
00115 if (error_state)
00116 return retval;
00117
00118 if (argc > 1)
00119 {
00120 std::string dirname = argv[1];
00121
00122 if (dirname.length () > 0
00123 && ! octave_change_to_directory (dirname))
00124 {
00125 return retval;
00126 }
00127 }
00128 else
00129 {
00130
00131
00132
00133 if (nargout == 0)
00134 {
00135 std::string home_dir = octave_env::get_home_directory ();
00136
00137 if (home_dir.empty () || ! octave_change_to_directory (home_dir))
00138 return retval;
00139 }
00140 else
00141 retval = octave_value (octave_env::get_current_directory ());
00142 }
00143
00144 return retval;
00145 }
00146
00147 DEFALIAS (chdir, cd);
00148
00149 DEFUN (pwd, , ,
00150 "-*- texinfo -*-\n\
00151 @deftypefn {Built-in Function} {} pwd ()\n\
00152 Return the current working directory.\n\
00153 @seealso{dir, ls}\n\
00154 @end deftypefn")
00155 {
00156 return octave_value (octave_env::get_current_directory ());
00157 }
00158
00159 DEFUN (readdir, args, ,
00160 "-*- texinfo -*-\n\
00161 @deftypefn {Built-in Function} {[@var{files}, @var{err}, @var{msg}] =} readdir (@var{dir})\n\
00162 Return names of the files in the directory @var{dir} as a cell array of\n\
00163 strings. If an error occurs, return an empty cell array in @var{files}.\n\
00164 \n\
00165 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
00166 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
00167 system-dependent error message.\n\
00168 @seealso{ls, dir, glob}\n\
00169 @end deftypefn")
00170 {
00171 octave_value_list retval;
00172
00173 retval(2) = std::string ();
00174 retval(1) = -1.0;
00175 retval(0) = Cell ();
00176
00177 if (args.length () == 1)
00178 {
00179 std::string dirname = args(0).string_value ();
00180
00181 if (error_state)
00182 gripe_wrong_type_arg ("readdir", args(0));
00183 else
00184 {
00185 dir_entry dir (dirname);
00186
00187 if (dir)
00188 {
00189 string_vector dirlist = dir.read ();
00190 retval(1) = 0.0;
00191 retval(0) = Cell (dirlist.sort ());
00192 }
00193 else
00194 {
00195 retval(2) = dir.error ();
00196 }
00197 }
00198 }
00199 else
00200 print_usage ();
00201
00202 return retval;
00203 }
00204
00205
00206
00207
00208 DEFUNX ("mkdir", Fmkdir, args, ,
00209 "-*- texinfo -*-\n\
00210 @deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{dir})\n\
00211 @deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{parent}, @var{dir})\n\
00212 Create a directory named @var{dir} in the directory @var{parent}.\n\
00213 \n\
00214 If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
00215 character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
00216 system-dependent error message, and @var{msgid} contains a unique\n\
00217 message identifier.\n\
00218 @seealso{rmdir}\n\
00219 @end deftypefn")
00220 {
00221 octave_value_list retval;
00222
00223 retval(2) = std::string ();
00224 retval(1) = std::string ();
00225 retval(0) = false;
00226
00227 int nargin = args.length ();
00228
00229 std::string dirname;
00230
00231 if (nargin == 2)
00232 {
00233 std::string parent = args(0).string_value ();
00234 std::string dir = args(1).string_value ();
00235
00236 if (error_state)
00237 {
00238 gripe_wrong_type_arg ("mkdir", args(0));
00239 return retval;
00240 }
00241 else
00242 dirname = file_ops::concat (parent, dir);
00243 }
00244 else if (nargin == 1)
00245 {
00246 dirname = args(0).string_value ();
00247
00248 if (error_state)
00249 {
00250 gripe_wrong_type_arg ("mkdir", args(0));
00251 return retval;
00252 }
00253 }
00254
00255 if (nargin == 1 || nargin == 2)
00256 {
00257 std::string msg;
00258
00259 dirname = file_ops::tilde_expand (dirname);
00260
00261 file_stat fs (dirname);
00262
00263 if (fs && fs.is_dir ())
00264 {
00265
00266
00267
00268 retval(2) = "mkdir";
00269 retval(1) = "directory exists";
00270 retval(0) = true;
00271 }
00272 else
00273 {
00274 int status = octave_mkdir (dirname, 0777, msg);
00275
00276 if (status < 0)
00277 {
00278 retval(2) = "mkdir";
00279 retval(1) = msg;
00280 }
00281 else
00282 retval(0) = true;
00283 }
00284 }
00285 else
00286 print_usage ();
00287
00288 return retval;
00289 }
00290
00291 DEFUNX ("rmdir", Frmdir, args, ,
00292 "-*- texinfo -*-\n\
00293 @deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir})\n\
00294 @deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir}, \"s\")\n\
00295 Remove the directory named @var{dir}.\n\
00296 \n\
00297 If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
00298 character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
00299 system-dependent error message, and @var{msgid} contains a unique\n\
00300 message identifier.\n\
00301 \n\
00302 If the optional second parameter is supplied with value @code{\"s\"},\n\
00303 recursively remove all subdirectories as well.\n\
00304 @seealso{mkdir, confirm_recursive_rmdir}\n\
00305 @end deftypefn")
00306 {
00307 octave_value_list retval;
00308
00309 retval(2) = std::string ();
00310 retval(1) = std::string ();
00311 retval(0) = false;
00312
00313 int nargin = args.length ();
00314
00315 if (nargin == 1 || nargin == 2)
00316 {
00317 std::string dirname = args(0).string_value ();
00318
00319 if (error_state)
00320 gripe_wrong_type_arg ("rmdir", args(0));
00321 else
00322 {
00323 std::string fulldir = file_ops::tilde_expand (dirname);
00324 int status = -1;
00325 std::string msg;
00326
00327 if (nargin == 2)
00328 {
00329 if (args(1).string_value () == "s")
00330 {
00331 bool doit = true;
00332
00333 if (interactive && Vconfirm_recursive_rmdir)
00334 {
00335 std::string prompt
00336 = "remove entire contents of " + fulldir + "? ";
00337
00338 doit = octave_yes_or_no (prompt);
00339 }
00340
00341 if (doit)
00342 status = octave_recursive_rmdir (fulldir, msg);
00343 }
00344 else
00345 error ("rmdir: expecting second argument to be \"s\"");
00346 }
00347 else
00348 status = octave_rmdir (fulldir, msg);
00349
00350 if (status < 0)
00351 {
00352 retval(2) = "rmdir";
00353 retval(1) = msg;
00354 }
00355 else
00356 retval(0) = true;
00357 }
00358 }
00359 else
00360 print_usage ();
00361
00362 return retval;
00363 }
00364
00365 DEFUNX ("link", Flink, args, ,
00366 "-*- texinfo -*-\n\
00367 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})\n\
00368 Create a new link (also known as a hard link) to an existing file.\n\
00369 \n\
00370 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
00371 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
00372 system-dependent error message.\n\
00373 @seealso{symlink}\n\
00374 @end deftypefn")
00375 {
00376 octave_value_list retval;
00377
00378 retval(1) = std::string ();
00379 retval(0) = -1.0;
00380
00381 if (args.length () == 2)
00382 {
00383 std::string from = args(0).string_value ();
00384
00385 if (error_state)
00386 gripe_wrong_type_arg ("link", args(0));
00387 else
00388 {
00389 std::string to = args(1).string_value ();
00390
00391 if (error_state)
00392 gripe_wrong_type_arg ("link", args(1));
00393 else
00394 {
00395 std::string msg;
00396
00397 int status = octave_link (from, to, msg);
00398
00399 retval(0) = status;
00400
00401 if (status < 0)
00402 retval(1) = msg;
00403 }
00404 }
00405 }
00406 else
00407 print_usage ();
00408
00409 return retval;
00410 }
00411
00412 DEFUNX ("symlink", Fsymlink, args, ,
00413 "-*- texinfo -*-\n\
00414 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})\n\
00415 Create a symbolic link @var{new} which contains the string @var{old}.\n\
00416 \n\
00417 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
00418 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
00419 system-dependent error message.\n\
00420 @seealso{link, readlink}\n\
00421 @end deftypefn")
00422 {
00423 octave_value_list retval;
00424
00425 retval(1) = std::string ();
00426 retval(0) = -1.0;
00427
00428 if (args.length () == 2)
00429 {
00430 std::string from = args(0).string_value ();
00431
00432 if (error_state)
00433 gripe_wrong_type_arg ("symlink", args(0));
00434 else
00435 {
00436 std::string to = args(1).string_value ();
00437
00438 if (error_state)
00439 gripe_wrong_type_arg ("symlink", args(1));
00440 else
00441 {
00442 std::string msg;
00443
00444 int status = octave_symlink (from, to, msg);
00445
00446 retval(0) = status;
00447
00448 if (status < 0)
00449 retval(1) = msg;
00450 }
00451 }
00452 }
00453 else
00454 print_usage ();
00455
00456 return retval;
00457 }
00458
00459 DEFUNX ("readlink", Freadlink, args, ,
00460 "-*- texinfo -*-\n\
00461 @deftypefn {Built-in Function} {[@var{result}, @var{err}, @var{msg}] =} readlink (@var{symlink})\n\
00462 Read the value of the symbolic link @var{symlink}.\n\
00463 \n\
00464 If successful, @var{result} contains the contents of the symbolic link\n\
00465 @var{symlink}, @var{err} is 0 and @var{msg} is an empty string.\n\
00466 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
00467 system-dependent error message.\n\
00468 @seealso{link, symlink}\n\
00469 @end deftypefn")
00470 {
00471 octave_value_list retval;
00472
00473 retval(2) = std::string ();
00474 retval(1) = -1.0;
00475 retval(0) = std::string ();
00476
00477 if (args.length () == 1)
00478 {
00479 std::string symlink = args(0).string_value ();
00480
00481 if (error_state)
00482 gripe_wrong_type_arg ("readlink", args(0));
00483 else
00484 {
00485 std::string result;
00486 std::string msg;
00487
00488 int status = octave_readlink (symlink, result, msg);
00489
00490 if (status < 0)
00491 retval(2) = msg;
00492 retval(1) = status;
00493 retval(0) = result;
00494 }
00495 }
00496 else
00497 print_usage ();
00498
00499 return retval;
00500 }
00501
00502 DEFUNX ("rename", Frename, args, ,
00503 "-*- texinfo -*-\n\
00504 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})\n\
00505 Change the name of file @var{old} to @var{new}.\n\
00506 \n\
00507 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
00508 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
00509 system-dependent error message.\n\
00510 @seealso{ls, dir}\n\
00511 @end deftypefn")
00512 {
00513 octave_value_list retval;
00514
00515 retval(1) = std::string ();
00516 retval(0) = -1.0;
00517
00518 if (args.length () == 2)
00519 {
00520 std::string from = args(0).string_value ();
00521
00522 if (error_state)
00523 gripe_wrong_type_arg ("rename", args(0));
00524 else
00525 {
00526 std::string to = args(1).string_value ();
00527
00528 if (error_state)
00529 gripe_wrong_type_arg ("rename", args(1));
00530 else
00531 {
00532 std::string msg;
00533
00534 int status = octave_rename (from, to, msg);
00535
00536 retval(0) = status;
00537
00538 if (status < 0)
00539 retval(1) = msg;
00540 }
00541 }
00542 }
00543 else
00544 print_usage ();
00545
00546 return retval;
00547 }
00548
00549 DEFUN (glob, args, ,
00550 "-*- texinfo -*-\n\
00551 @deftypefn {Built-in Function} {} glob (@var{pattern})\n\
00552 Given an array of pattern strings (as a char array or a cell array) in\n\
00553 @var{pattern}, return a cell array of file names that match any of\n\
00554 them, or an empty cell array if no patterns match. The pattern strings are\n\
00555 interpreted as filename globbing patterns (as they are used by Unix shells).\n\
00556 Within a pattern\n\
00557 @table @code\n\
00558 @itemx *\n\
00559 matches any string, including the null string,\n\
00560 @itemx ?\n\
00561 matches any single character, and\n\
00562 \n\
00563 @item [@dots{}]\n\
00564 matches any of the enclosed characters.\n\
00565 @end table\n\
00566 \n\
00567 Tilde expansion\n\
00568 is performed on each of the patterns before looking for matching file\n\
00569 names. For example:\n\
00570 \n\
00571 @example\n\
00572 ls\n\
00573 @result{}\n\
00574 file1 file2 file3 myfile1 myfile1b\n\
00575 glob (\"*file1\")\n\
00576 @result{}\n\
00577 @{\n\
00578 [1,1] = file1\n\
00579 [2,1] = myfile1\n\
00580 @}\n\
00581 glob (\"myfile?\")\n\
00582 @result{}\n\
00583 @{\n\
00584 [1,1] = myfile1\n\
00585 @}\n\
00586 glob (\"file[12]\")\n\
00587 @result{}\n\
00588 @{\n\
00589 [1,1] = file1\n\
00590 [2,1] = file2\n\
00591 @}\n\
00592 @end example\n\
00593 @seealso{ls, dir, readdir}\n\
00594 @end deftypefn")
00595 {
00596 octave_value retval;
00597
00598 if (args.length () == 1)
00599 {
00600 string_vector pat = args(0).all_strings ();
00601
00602 if (error_state)
00603 gripe_wrong_type_arg ("glob", args(0));
00604 else
00605 {
00606 glob_match pattern (file_ops::tilde_expand (pat));
00607
00608 retval = Cell (pattern.glob ());
00609 }
00610 }
00611 else
00612 print_usage ();
00613
00614 return retval;
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 DEFUNX ("fnmatch", Ffnmatch, args, ,
00651 "-*- texinfo -*-\n\
00652 @deftypefn {Built-in Function} {} fnmatch (@var{pattern}, @var{string})\n\
00653 Return 1 or zero for each element of @var{string} that matches any of\n\
00654 the elements of the string array @var{pattern}, using the rules of\n\
00655 filename pattern matching. For example:\n\
00656 \n\
00657 @example\n\
00658 @group\n\
00659 fnmatch (\"a*b\", @{\"ab\"; \"axyzb\"; \"xyzab\"@})\n\
00660 @result{} [ 1; 1; 0 ]\n\
00661 @end group\n\
00662 @end example\n\
00663 @end deftypefn")
00664 {
00665 octave_value retval;
00666
00667 if (args.length () == 2)
00668 {
00669 string_vector pat = args(0).all_strings ();
00670 string_vector str = args(1).all_strings ();
00671
00672 if (error_state)
00673 gripe_wrong_type_arg ("fnmatch", args(0));
00674 else
00675 {
00676 glob_match pattern (file_ops::tilde_expand (pat));
00677
00678 retval = pattern.match (str);
00679 }
00680 }
00681 else
00682 print_usage ();
00683
00684 return retval;
00685 }
00686
00687 DEFUN (filesep, args, ,
00688 "-*- texinfo -*-\n\
00689 @deftypefn {Built-in Function} {} filesep ()\n\
00690 @deftypefnx {Built-in Function} {} filesep ('all')\n\
00691 Return the system-dependent character used to separate directory names.\n\
00692 \n\
00693 If 'all' is given, the function returns all valid file separators in\n\
00694 the form of a string. The list of file separators is system-dependent.\n\
00695 It is @samp{/} (forward slash) under UNIX or @w{Mac OS X}, @samp{/} and\n\
00696 @samp{\\} (forward and backward slashes) under Windows.\n\
00697 @seealso{pathsep}\n\
00698 @end deftypefn")
00699 {
00700 octave_value retval;
00701
00702 if (args.length () == 0)
00703 retval = file_ops::dir_sep_str ();
00704 else if (args.length () == 1)
00705 {
00706 std::string s = args(0).string_value ();
00707
00708 if (! error_state)
00709 {
00710 if (s == "all")
00711 retval = file_ops::dir_sep_chars ();
00712 else
00713 gripe_wrong_type_arg ("filesep", args(0));
00714 }
00715 else
00716 gripe_wrong_type_arg ("filesep", args(0));
00717 }
00718 else
00719 print_usage ();
00720
00721 return retval;
00722 }
00723
00724 DEFUN (pathsep, args, nargout,
00725 "-*- texinfo -*-\n\
00726 @deftypefn {Built-in Function} {@var{val} =} pathsep ()\n\
00727 @deftypefnx {Built-in Function} {@var{old_val} =} pathsep (@var{new_val})\n\
00728 Query or set the character used to separate directories in a path.\n\
00729 @seealso{filesep}\n\
00730 @end deftypefn")
00731 {
00732 octave_value retval;
00733
00734 int nargin = args.length ();
00735
00736 if (nargout > 0 || nargin == 0)
00737 retval = dir_path::path_sep_str ();
00738
00739 if (nargin == 1)
00740 {
00741 std::string sval = args(0).string_value ();
00742
00743 if (! error_state)
00744 {
00745 switch (sval.length ())
00746 {
00747 case 1:
00748 dir_path::path_sep_char (sval[0]);
00749 break;
00750
00751 case 0:
00752 dir_path::path_sep_char ('\0');
00753 break;
00754
00755 default:
00756 error ("pathsep: argument must be a single character");
00757 break;
00758 }
00759 }
00760 else
00761 error ("pathsep: argument must be a single character");
00762 }
00763 else if (nargin > 1)
00764 print_usage ();
00765
00766 return retval;
00767 }
00768
00769 DEFUN (confirm_recursive_rmdir, args, nargout,
00770 "-*- texinfo -*-\n\
00771 @deftypefn {Built-in Function} {@var{val} =} confirm_recursive_rmdir ()\n\
00772 @deftypefnx {Built-in Function} {@var{old_val} =} confirm_recursive_rmdir (@var{new_val})\n\
00773 @deftypefnx {Built-in Function} {} confirm_recursive_rmdir (@var{new_val}, \"local\")\n\
00774 Query or set the internal variable that controls whether Octave\n\
00775 will ask for confirmation before recursively removing a directory tree.\n\
00776 \n\
00777 When called from inside a function with the \"local\" option, the variable is\n\
00778 changed locally for the function and any subroutines it calls. The original\n\
00779 variable value is restored when exiting the function.\n\
00780 @end deftypefn")
00781 {
00782 return SET_INTERNAL_VARIABLE (confirm_recursive_rmdir);
00783 }