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/>.
38#ifdef HAVE_SYS_TYPES_H
46#include "glob-match.h"
48#include "pathsearch.h"
61#include "procstream.h"
64#include "unwind-prot.h"
68// TRUE means we ask for confirmation before recursively removing a
70static bool Vconfirm_recursive_rmdir = true;
72// The time we last time we changed directories.
73octave_time Vlast_chdir_time = 0.0;
76octave_change_to_directory (const std::string& newdir)
78 int cd_ok = octave_env::chdir (file_ops::tilde_expand (newdir));
82 Vlast_chdir_time.stamp ();
84 // FIXME -- should this be handled as a list of functions
85 // to call so users can add their own chdir handlers?
93 error ("%s: %s", newdir.c_str (), strerror (errno));
101@deffn {Command} cd dir\n\
102@deffnx {Command} chdir dir\n\
103Change the current working directory to @var{dir}. If @var{dir} is\n\
104omitted, the current directory is changed to the user's home\n\
105directory. For example,\n\
112Changes the current working directory to @file{~/octave}. If the\n\
113directory does not exist, an error message is printed and the working\n\
114directory is not changed.\n\
115@seealso{mkdir, rmdir, dir}\n\
118 octave_value_list retval;
120 int argc = args.length () + 1;
122 string_vector argv = args.make_argv ("cd");
129 std::string dirname = argv[1];
131 if (dirname.length () > 0
132 && ! octave_change_to_directory (dirname))
139 std::string home_dir = octave_env::get_home_directory ();
141 if (home_dir.empty () || ! octave_change_to_directory (home_dir))
152@deftypefn {Built-in Function} {} pwd ()\n\
153Return the current working directory.\n\
157 return octave_value (octave_env::getcwd ());
160DEFUN (readdir, args, ,
162@deftypefn {Built-in Function} {[@var{files}, @var{err}, @var{msg}] =} readdir (@var{dir})\n\
163Return names of the files in the directory @var{dir} as a cell array of\n\
164strings. If an error occurs, return an empty cell array in @var{files}.\n\
166If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
167Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
168system-dependent error message.\n\
169@seealso{dir, glob}\n\
172 octave_value_list retval;
174 retval(2) = std::string ();
178 if (args.length () == 1)
180 std::string dirname = args(0).string_value ();
183 gripe_wrong_type_arg ("readdir", args(0));
186 dir_entry dir (dirname);
190 string_vector dirlist = dir.read ();
191 retval(0) = Cell (dirlist.sort ());
196 retval(2) = dir.error ();
206// FIXME -- should maybe also allow second arg to specify
207// mode? OTOH, that might cause trouble with compatibility later...
211@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{dir})\n\
212@deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{parent}, @var{dir})\n\
213Create a directory named @var{dir} in the directory @var{parent}.\n\
215If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
216character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
217system-dependent error message, and @var{msgid} contains a unique\n\
218message identifier.\n\
222 octave_value_list retval;
224 retval(2) = std::string ();
225 retval(1) = std::string ();
228 int nargin = args.length ();
234 std::string parent = args(0).string_value ();
235 std::string dir = args(1).string_value ();
239 gripe_wrong_type_arg ("mkdir", args(0));
243 dirname = file_ops::concat (parent, dir);
245 else if (nargin == 1)
247 dirname = args(0).string_value ();
251 gripe_wrong_type_arg ("mkdir", args(0));
256 if (nargin == 1 || nargin == 2)
260 dirname = file_ops::tilde_expand (dirname);
262 file_stat fs (dirname);
264 if (fs && fs.is_dir ())
266 // For compatibility with Matlab, we return true when the
267 // directory already exists.
270 retval(1) = "directory exists";
275 int status = file_ops::mkdir (dirname, 0777, msg);
294@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir})\n\
295@deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir}, @code{\"s\"})\n\
296Remove the directory named @var{dir}.\n\
298If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
299character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
300system-dependent error message, and @var{msgid} contains a unique\n\
301message identifier.\n\
303If the optional second parameter is supplied with value @code{\"s\"},\n\
304recursively remove all subdirectories as well.\n\
305@seealso{mkdir, confirm_recursive_rmdir}\n\
308 octave_value_list retval;
310 retval(2) = std::string ();
311 retval(1) = std::string ();
314 int nargin = args.length ();
316 if (nargin == 1 || nargin == 2)
318 std::string dirname = args(0).string_value ();
321 gripe_wrong_type_arg ("rmdir", args(0));
324 std::string fulldir = file_ops::tilde_expand (dirname);
330 if (args(1).string_value () == "s")
334 if (interactive && Vconfirm_recursive_rmdir)
337 = "remove entire contents of " + fulldir + "? ";
339 doit = octave_yes_or_no (prompt);
343 status = file_ops::recursive_rmdir (fulldir, msg);
346 error ("rmdir: expecting second argument to be \"s\"");
349 status = file_ops::rmdir (fulldir, msg);
368@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})\n\
369Create a new link (also known as a hard link) to an existing file.\n\
371If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
372Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
373system-dependent error message.\n\
377 octave_value_list retval;
379 retval(1) = std::string ();
382 if (args.length () == 2)
384 std::string from = args(0).string_value ();
387 gripe_wrong_type_arg ("link", args(0));
390 std::string to = args(1).string_value ();
393 gripe_wrong_type_arg ("link", args(1));
398 int status = file_ops::link (from, to, msg);
413DEFUN (symlink, args, ,
415@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})\n\
416Create a symbolic link @var{new} which contains the string @var{old}.\n\
418If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
419Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
420system-dependent error message.\n\
421@seealso{link, readlink}\n\
424 octave_value_list retval;
426 retval(1) = std::string ();
429 if (args.length () == 2)
431 std::string from = args(0).string_value ();
434 gripe_wrong_type_arg ("symlink", args(0));
437 std::string to = args(1).string_value ();
440 gripe_wrong_type_arg ("symlink", args(1));
445 int status = file_ops::symlink (from, to, msg);
460DEFUN (readlink, args, ,
462@deftypefn {Built-in Function} {[@var{result}, @var{err}, @var{msg}] =} readlink (@var{symlink})\n\
463Read the value of the symbolic link @var{symlink}.\n\
465If successful, @var{result} contains the contents of the symbolic link\n\
466@var{symlink}, @var{err} is 0 and @var{msg} is an empty string.\n\
467Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
468system-dependent error message.\n\
469@seealso{link, symlink}\n\
472 octave_value_list retval;
474 retval(2) = std::string ();
476 retval(0) = std::string ();
478 if (args.length () == 1)
480 std::string symlink = args(0).string_value ();
483 gripe_wrong_type_arg ("readlink", args(0));
489 int status = file_ops::readlink (symlink, result, msg);
505DEFUN (rename, args, ,
507@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})\n\
508Change the name of file @var{old} to @var{new}.\n\
510If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
511Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
512system-dependent error message.\n\
516 octave_value_list retval;
518 retval(1) = std::string ();
521 if (args.length () == 2)
523 std::string from = args(0).string_value ();
526 gripe_wrong_type_arg ("rename", args(0));
529 std::string to = args(1).string_value ();
532 gripe_wrong_type_arg ("rename", args(1));
537 int status = file_ops::rename (from, to, msg);
554@deftypefn {Built-in Function} {} glob (@var{pattern})\n\
555Given an array of strings (as a char array or a cell array) in\n\
556@var{pattern}, return a cell array of file names that match any of\n\
557them, or an empty cell array if no patterns match. Tilde expansion\n\
558is performed on each of the patterns before looking for matching file\n\
559names. For example,\n\
564 @result{} \"/vmlinuz\"\n\
567@seealso{dir, ls, stat, readdir}\n\
572 if (args.length () == 1)
574 string_vector pat = args(0).all_strings ();
577 gripe_wrong_type_arg ("glob", args(0));
580 glob_match pattern (file_ops::tilde_expand (pat));
582 retval = Cell (pattern.glob ());
591DEFUN (fnmatch, args, ,
593@deftypefn {Built-in Function} {} fnmatch (@var{pattern}, @var{string})\n\
594Return 1 or zero for each element of @var{string} that matches any of\n\
595the elements of the string array @var{pattern}, using the rules of\n\
596filename pattern matching. For example,\n\
600fnmatch (\"a*b\", @{\"ab\"; \"axyzb\"; \"xyzab\"@})\n\
601 @result{} [ 1; 1; 0 ]\n\
608 if (args.length () == 2)
610 string_vector pat = args(0).all_strings ();
611 string_vector str = args(1).all_strings ();
614 gripe_wrong_type_arg ("fnmatch", args(0));
617 glob_match pattern (file_ops::tilde_expand (pat));
619 Array<bool> tmp = pattern.match (str);
621 octave_idx_type n = tmp.length ();
623 ColumnVector result (n);
625 for (octave_idx_type i = 0; i < n; i++)
637DEFUN (filesep, args, ,
639@deftypefn {Built-in Function} {} filesep ()\n\
640@deftypefnx {Built-in Function} {} filesep ('all')\n\
641Return the system-dependent character used to separate directory names.\n\
643If 'all' is given, the function return all valid file separators in\n\
644the form of a string. The list of file separators is system-dependent.\n\
645It is / (forward slash) under UNIX or Mac OS X, / and \\ (forward and\n\
646backward slashes) under Windows.\n\
647@seealso{pathsep, dir, ls}\n\
652 if (args.length () == 0)
653 retval = file_ops::dir_sep_str ();
654 else if (args.length () == 1)
656 std::string s = args(0).string_value ();
661 retval = file_ops::dir_sep_chars ();
663 gripe_wrong_type_arg ("filesep", args(0));
666 gripe_wrong_type_arg ("filesep", args(0));
674DEFUN (pathsep, args, nargout,
676@deftypefn {Built-in Function} {@var{val} =} pathsep ()\n\
677@deftypefnx {Built-in Function} {@var{old_val} =} pathsep (@var{new_val})\n\
678Query or set the character used to separate directories in\n\
680@seealso{filesep, dir, ls}\n\
685 int nargin = args.length ();
687 if (nargout > 0 || nargin == 0)
688 retval = dir_path::path_sep_str ();
692 std::string sval = args(0).string_value ();
696 switch (sval.length ())
699 dir_path::path_sep_char (sval[0]);
703 dir_path::path_sep_char ('\0');
707 error ("pathsep: argument must be a single character");
712 error ("pathsep: argument must be a single character");
720DEFUN (confirm_recursive_rmdir, args, nargout,
722@deftypefn {Built-in Function} {@var{val} =} confirm_recursive_rmdir ()\n\
723@deftypefnx {Built-in Function} {@var{old_val} =} confirm_recursive_rmdir (@var{new_val})\n\
724Query or set the internal variable that controls whether Octave\n\
725will ask for confirmation before recursively removing a directory tree.\n\
728 return SET_INTERNAL_VARIABLE (confirm_recursive_rmdir);
732;;; Local Variables: ***