3Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003,
4 2004, 2005, 2006, 2007, 2008, 2009 John W. Eaton
6This file is part of Octave.
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.
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
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/>.
42#include "glob-match.h"
44#include "pathsearch.h"
57#include "procstream.h"
60#include "unwind-prot.h"
64// TRUE means we ask for confirmation before recursively removing a
66static bool Vconfirm_recursive_rmdir = true;
68// The time we last time we changed directories.
69octave_time Vlast_chdir_time = 0.0;
72octave_change_to_directory (const std::string& newdir)
74 int cd_ok = octave_env::chdir (file_ops::tilde_expand (newdir));
78 Vlast_chdir_time.stamp ();
80 // FIXME -- should this be handled as a list of functions
81 // to call so users can add their own chdir handlers?
89 error ("%s: %s", newdir.c_str (), strerror (errno));
97@deffn {Command} cd dir\n\
98@deffnx {Command} chdir dir\n\
99Change the current working directory to @var{dir}. If @var{dir} is\n\
100omitted, the current directory is changed to the user's home\n\
101directory. For example,\n\
108Changes the current working directory to @file{~/octave}. If the\n\
109directory does not exist, an error message is printed and the working\n\
110directory is not changed.\n\
111@seealso{mkdir, rmdir, dir}\n\
114 octave_value_list retval;
116 int argc = args.length () + 1;
118 string_vector argv = args.make_argv ("cd");
125 std::string dirname = argv[1];
127 if (dirname.length () > 0
128 && ! octave_change_to_directory (dirname))
135 std::string home_dir = octave_env::get_home_directory ();
137 if (home_dir.empty () || ! octave_change_to_directory (home_dir))
148@deftypefn {Built-in Function} {} pwd ()\n\
149Return the current working directory.\n\
153 return octave_value (octave_env::get_current_directory ());
156DEFUN (readdir, args, ,
158@deftypefn {Built-in Function} {[@var{files}, @var{err}, @var{msg}] =} readdir (@var{dir})\n\
159Return names of the files in the directory @var{dir} as a cell array of\n\
160strings. If an error occurs, return an empty cell array in @var{files}.\n\
162If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
163Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
164system-dependent error message.\n\
165@seealso{dir, glob}\n\
168 octave_value_list retval;
170 retval(2) = std::string ();
174 if (args.length () == 1)
176 std::string dirname = args(0).string_value ();
179 gripe_wrong_type_arg ("readdir", args(0));
182 dir_entry dir (dirname);
186 string_vector dirlist = dir.read ();
187 retval(0) = Cell (dirlist.sort ());
192 retval(2) = dir.error ();
202// FIXME -- should maybe also allow second arg to specify
203// mode? OTOH, that might cause trouble with compatibility later...
205DEFUNX ("mkdir", Fmkdir, args, ,
207@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{dir})\n\
208@deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{parent}, @var{dir})\n\
209Create a directory named @var{dir} in the directory @var{parent}.\n\
211If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
212character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
213system-dependent error message, and @var{msgid} contains a unique\n\
214message identifier.\n\
218 octave_value_list retval;
220 retval(2) = std::string ();
221 retval(1) = std::string ();
224 int nargin = args.length ();
230 std::string parent = args(0).string_value ();
231 std::string dir = args(1).string_value ();
235 gripe_wrong_type_arg ("mkdir", args(0));
239 dirname = file_ops::concat (parent, dir);
241 else if (nargin == 1)
243 dirname = args(0).string_value ();
247 gripe_wrong_type_arg ("mkdir", args(0));
252 if (nargin == 1 || nargin == 2)
256 dirname = file_ops::tilde_expand (dirname);
258 file_stat fs (dirname);
260 if (fs && fs.is_dir ())
262 // For compatibility with Matlab, we return true when the
263 // directory already exists.
266 retval(1) = "directory exists";
271 int status = octave_mkdir (dirname, 0777, msg);
288DEFUNX ("rmdir", Frmdir, args, ,
290@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir})\n\
291@deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir}, @code{\"s\"})\n\
292Remove the directory named @var{dir}.\n\
294If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
295character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
296system-dependent error message, and @var{msgid} contains a unique\n\
297message identifier.\n\
299If the optional second parameter is supplied with value @code{\"s\"},\n\
300recursively remove all subdirectories as well.\n\
301@seealso{mkdir, confirm_recursive_rmdir}\n\
304 octave_value_list retval;
306 retval(2) = std::string ();
307 retval(1) = std::string ();
310 int nargin = args.length ();
312 if (nargin == 1 || nargin == 2)
314 std::string dirname = args(0).string_value ();
317 gripe_wrong_type_arg ("rmdir", args(0));
320 std::string fulldir = file_ops::tilde_expand (dirname);
326 if (args(1).string_value () == "s")
330 if (interactive && Vconfirm_recursive_rmdir)
333 = "remove entire contents of " + fulldir + "? ";
335 doit = octave_yes_or_no (prompt);
339 status = octave_recursive_rmdir (fulldir, msg);
342 error ("rmdir: expecting second argument to be \"s\"");
345 status = octave_rmdir (fulldir, msg);
362DEFUNX ("link", Flink, args, ,
364@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})\n\
365Create a new link (also known as a hard link) to an existing file.\n\
367If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
368Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
369system-dependent error message.\n\
373 octave_value_list retval;
375 retval(1) = std::string ();
378 if (args.length () == 2)
380 std::string from = args(0).string_value ();
383 gripe_wrong_type_arg ("link", args(0));
386 std::string to = args(1).string_value ();
389 gripe_wrong_type_arg ("link", args(1));
394 int status = octave_link (from, to, msg);
409DEFUNX ("symlink", Fsymlink, args, ,
411@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})\n\
412Create a symbolic link @var{new} which contains the string @var{old}.\n\
414If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
415Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
416system-dependent error message.\n\
417@seealso{link, readlink}\n\
420 octave_value_list retval;
422 retval(1) = std::string ();
425 if (args.length () == 2)
427 std::string from = args(0).string_value ();
430 gripe_wrong_type_arg ("symlink", args(0));
433 std::string to = args(1).string_value ();
436 gripe_wrong_type_arg ("symlink", args(1));
441 int status = octave_symlink (from, to, msg);
456DEFUNX ("readlink", Freadlink, args, ,
458@deftypefn {Built-in Function} {[@var{result}, @var{err}, @var{msg}] =} readlink (@var{symlink})\n\
459Read the value of the symbolic link @var{symlink}.\n\
461If successful, @var{result} contains the contents of the symbolic link\n\
462@var{symlink}, @var{err} is 0 and @var{msg} is an empty string.\n\
463Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
464system-dependent error message.\n\
465@seealso{link, symlink}\n\
468 octave_value_list retval;
470 retval(2) = std::string ();
472 retval(0) = std::string ();
474 if (args.length () == 1)
476 std::string symlink = args(0).string_value ();
479 gripe_wrong_type_arg ("readlink", args(0));
485 int status = octave_readlink (symlink, result, msg);
501DEFUNX ("rename", Frename, args, ,
503@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})\n\
504Change the name of file @var{old} to @var{new}.\n\
506If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
507Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
508system-dependent error message.\n\
512 octave_value_list retval;
514 retval(1) = std::string ();
517 if (args.length () == 2)
519 std::string from = args(0).string_value ();
522 gripe_wrong_type_arg ("rename", args(0));
525 std::string to = args(1).string_value ();
528 gripe_wrong_type_arg ("rename", args(1));
533 int status = octave_rename (from, to, msg);
550@deftypefn {Built-in Function} {} glob (@var{pattern})\n\
551Given an array of strings (as a char array or a cell array) in\n\
552@var{pattern}, return a cell array of file names that match any of\n\
553them, or an empty cell array if no patterns match. Tilde expansion\n\
554is performed on each of the patterns before looking for matching file\n\
555names. For example,\n\
560 @result{} \"/vmlinuz\"\n\
563@seealso{dir, ls, stat, readdir}\n\
568 if (args.length () == 1)
570 string_vector pat = args(0).all_strings ();
573 gripe_wrong_type_arg ("glob", args(0));
576 glob_match pattern (file_ops::tilde_expand (pat));
578 retval = Cell (pattern.glob ());
587DEFUN (fnmatch, args, ,
589@deftypefn {Built-in Function} {} fnmatch (@var{pattern}, @var{string})\n\
590Return 1 or zero for each element of @var{string} that matches any of\n\
591the elements of the string array @var{pattern}, using the rules of\n\
592filename pattern matching. For example,\n\
596fnmatch (\"a*b\", @{\"ab\"; \"axyzb\"; \"xyzab\"@})\n\
597 @result{} [ 1; 1; 0 ]\n\
604 if (args.length () == 2)
606 string_vector pat = args(0).all_strings ();
607 string_vector str = args(1).all_strings ();
610 gripe_wrong_type_arg ("fnmatch", args(0));
613 glob_match pattern (file_ops::tilde_expand (pat));
615 retval = pattern.match (str);
624DEFUN (filesep, args, ,
626@deftypefn {Built-in Function} {} filesep ()\n\
627@deftypefnx {Built-in Function} {} filesep ('all')\n\
628Return the system-dependent character used to separate directory names.\n\
630If 'all' is given, the function return all valid file separators in\n\
631the form of a string. The list of file separators is system-dependent.\n\
632It is / (forward slash) under UNIX or Mac OS X, / and \\ (forward and\n\
633backward slashes) under Windows.\n\
634@seealso{pathsep, dir, ls}\n\
639 if (args.length () == 0)
640 retval = file_ops::dir_sep_str ();
641 else if (args.length () == 1)
643 std::string s = args(0).string_value ();
648 retval = file_ops::dir_sep_chars ();
650 gripe_wrong_type_arg ("filesep", args(0));
653 gripe_wrong_type_arg ("filesep", args(0));
661DEFUN (pathsep, args, nargout,
663@deftypefn {Built-in Function} {@var{val} =} pathsep ()\n\
664@deftypefnx {Built-in Function} {@var{old_val} =} pathsep (@var{new_val})\n\
665Query or set the character used to separate directories in\n\
667@seealso{filesep, dir, ls}\n\
672 int nargin = args.length ();
674 if (nargout > 0 || nargin == 0)
675 retval = dir_path::path_sep_str ();
679 std::string sval = args(0).string_value ();
683 switch (sval.length ())
686 dir_path::path_sep_char (sval[0]);
690 dir_path::path_sep_char ('\0');
694 error ("pathsep: argument must be a single character");
699 error ("pathsep: argument must be a single character");
707DEFUN (confirm_recursive_rmdir, args, nargout,
709@deftypefn {Built-in Function} {@var{val} =} confirm_recursive_rmdir ()\n\
710@deftypefnx {Built-in Function} {@var{old_val} =} confirm_recursive_rmdir (@var{new_val})\n\
711Query or set the internal variable that controls whether Octave\n\
712will ask for confirmation before recursively removing a directory tree.\n\
715 return SET_INTERNAL_VARIABLE (confirm_recursive_rmdir);