comparison src/interpfcn/dirfns.cc @ 15088:60ff2cef569d

maint: Move core interpreter files with DEFUNS to interpfcn/ directory * src/Makefile.am: Adjust build system for new location of files. * interpfcn/module.mk: Add files and rules to build system. * data.cc, data.h, debug.cc, debug.h, defaults.cc, defaults.in.h, defun.cc, defun.h, dirfns.cc, dirfns.h, error.cc, error.h, file-io.cc, file-io.h, graphics.cc, graphics.in.h, help.cc, help.h, input.cc, input.h, load-path.cc, load-path.h, load-save.cc, load-save.h, ls-oct-ascii.cc, ls-oct-ascii.h, oct-hist.cc, oct-hist.h, pager.cc, pager.h, pr-output.cc, pr-output.h, profiler.cc, profiler.h, sighandlers.cc, sighandlers.h, symtab.cc, symtab.h, sysdep.cc, sysdep.h, toplev.cc, toplev.h, utils.cc, utils.h, variables.cc, variables.h: Move files to interpfcn/ directory
author Rik <rik@octave.org>
date Fri, 03 Aug 2012 09:31:37 -0700
parents src/dirfns.cc@0ab3dd0fad18
children
comparison
equal deleted inserted replaced
15087:20b33f227599 15088:60ff2cef569d
1 /*
2
3 Copyright (C) 1994-2012 John W. Eaton
4
5 This file is part of Octave.
6
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <cerrno>
28 #include <cstdio>
29 #include <cstddef>
30 #include <cstdlib>
31 #include <cstring>
32
33 #include <sstream>
34 #include <string>
35
36 #include <sys/types.h>
37 #include <unistd.h>
38
39 #include "file-ops.h"
40 #include "file-stat.h"
41 #include "glob-match.h"
42 #include "oct-env.h"
43 #include "pathsearch.h"
44 #include "str-vec.h"
45
46 #include "Cell.h"
47 #include "defun.h"
48 #include "dir-ops.h"
49 #include "dirfns.h"
50 #include "error.h"
51 #include "gripes.h"
52 #include "input.h"
53 #include "load-path.h"
54 #include "oct-obj.h"
55 #include "pager.h"
56 #include "procstream.h"
57 #include "sysdep.h"
58 #include "toplev.h"
59 #include "unwind-prot.h"
60 #include "utils.h"
61 #include "variables.h"
62
63 // TRUE means we ask for confirmation before recursively removing a
64 // directory tree.
65 static bool Vconfirm_recursive_rmdir = true;
66
67 // The time we last time we changed directories.
68 octave_time Vlast_chdir_time = 0.0;
69
70 static int
71 octave_change_to_directory (const std::string& newdir)
72 {
73 int cd_ok = octave_env::chdir (file_ops::tilde_expand (newdir));
74
75 if (cd_ok)
76 {
77 Vlast_chdir_time.stamp ();
78
79 // FIXME -- should this be handled as a list of functions
80 // to call so users can add their own chdir handlers?
81
82 load_path::update ();
83 }
84 else
85 error ("%s: %s", newdir.c_str (), gnulib::strerror (errno));
86
87 return cd_ok;
88 }
89
90 DEFUN (cd, args, nargout,
91 "-*- texinfo -*-\n\
92 @deftypefn {Command} {} cd dir\n\
93 @deftypefnx {Command} {} chdir dir\n\
94 Change the current working directory to @var{dir}. If @var{dir} is\n\
95 omitted, the current directory is changed to the user's home\n\
96 directory. For example,\n\
97 \n\
98 @example\n\
99 cd ~/octave\n\
100 @end example\n\
101 \n\
102 @noindent\n\
103 changes the current working directory to @file{~/octave}. If the\n\
104 directory does not exist, an error message is printed and the working\n\
105 directory is not changed.\n\
106 @seealso{mkdir, rmdir, dir}\n\
107 @end deftypefn")
108 {
109 octave_value_list retval;
110
111 int argc = args.length () + 1;
112
113 string_vector argv = args.make_argv ("cd");
114
115 if (error_state)
116 return retval;
117
118 if (argc > 1)
119 {
120 std::string dirname = argv[1];
121
122 if (dirname.length () > 0
123 && ! octave_change_to_directory (dirname))
124 {
125 return retval;
126 }
127 }
128 else
129 {
130 // Behave like Unixy shells for "cd" by itself, but be Matlab
131 // compatible if doing "current_dir = cd".
132
133 if (nargout == 0)
134 {
135 std::string home_dir = octave_env::get_home_directory ();
136
137 if (home_dir.empty () || ! octave_change_to_directory (home_dir))
138 return retval;
139 }
140 else
141 retval = octave_value (octave_env::get_current_directory ());
142 }
143
144 return retval;
145 }
146
147 DEFALIAS (chdir, cd);
148
149 DEFUN (pwd, , ,
150 "-*- texinfo -*-\n\
151 @deftypefn {Built-in Function} {} pwd ()\n\
152 Return the current working directory.\n\
153 @seealso{dir, ls}\n\
154 @end deftypefn")
155 {
156 return octave_value (octave_env::get_current_directory ());
157 }
158
159 DEFUN (readdir, args, ,
160 "-*- texinfo -*-\n\
161 @deftypefn {Built-in Function} {[@var{files}, @var{err}, @var{msg}] =} readdir (@var{dir})\n\
162 Return names of the files in the directory @var{dir} as a cell array of\n\
163 strings. If an error occurs, return an empty cell array in @var{files}.\n\
164 \n\
165 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
166 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
167 system-dependent error message.\n\
168 @seealso{ls, dir, glob}\n\
169 @end deftypefn")
170 {
171 octave_value_list retval;
172
173 retval(2) = std::string ();
174 retval(1) = -1.0;
175 retval(0) = Cell ();
176
177 if (args.length () == 1)
178 {
179 std::string dirname = args(0).string_value ();
180
181 if (error_state)
182 gripe_wrong_type_arg ("readdir", args(0));
183 else
184 {
185 dir_entry dir (dirname);
186
187 if (dir)
188 {
189 string_vector dirlist = dir.read ();
190 retval(1) = 0.0;
191 retval(0) = Cell (dirlist.sort ());
192 }
193 else
194 {
195 retval(2) = dir.error ();
196 }
197 }
198 }
199 else
200 print_usage ();
201
202 return retval;
203 }
204
205 // FIXME -- should maybe also allow second arg to specify
206 // mode? OTOH, that might cause trouble with compatibility later...
207
208 DEFUNX ("mkdir", Fmkdir, args, ,
209 "-*- texinfo -*-\n\
210 @deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{dir})\n\
211 @deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{parent}, @var{dir})\n\
212 Create a directory named @var{dir} in the directory @var{parent}.\n\
213 \n\
214 If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
215 character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
216 system-dependent error message, and @var{msgid} contains a unique\n\
217 message identifier.\n\
218 @seealso{rmdir}\n\
219 @end deftypefn")
220 {
221 octave_value_list retval;
222
223 retval(2) = std::string ();
224 retval(1) = std::string ();
225 retval(0) = false;
226
227 int nargin = args.length ();
228
229 std::string dirname;
230
231 if (nargin == 2)
232 {
233 std::string parent = args(0).string_value ();
234 std::string dir = args(1).string_value ();
235
236 if (error_state)
237 {
238 gripe_wrong_type_arg ("mkdir", args(0));
239 return retval;
240 }
241 else
242 dirname = file_ops::concat (parent, dir);
243 }
244 else if (nargin == 1)
245 {
246 dirname = args(0).string_value ();
247
248 if (error_state)
249 {
250 gripe_wrong_type_arg ("mkdir", args(0));
251 return retval;
252 }
253 }
254
255 if (nargin == 1 || nargin == 2)
256 {
257 std::string msg;
258
259 dirname = file_ops::tilde_expand (dirname);
260
261 file_stat fs (dirname);
262
263 if (fs && fs.is_dir ())
264 {
265 // For compatibility with Matlab, we return true when the
266 // directory already exists.
267
268 retval(2) = "mkdir";
269 retval(1) = "directory exists";
270 retval(0) = true;
271 }
272 else
273 {
274 int status = octave_mkdir (dirname, 0777, msg);
275
276 if (status < 0)
277 {
278 retval(2) = "mkdir";
279 retval(1) = msg;
280 }
281 else
282 retval(0) = true;
283 }
284 }
285 else
286 print_usage ();
287
288 return retval;
289 }
290
291 DEFUNX ("rmdir", Frmdir, args, ,
292 "-*- texinfo -*-\n\
293 @deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir})\n\
294 @deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir}, \"s\")\n\
295 Remove the directory named @var{dir}.\n\
296 \n\
297 If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
298 character strings. Otherwise, @var{status} is 0, @var{msg} contains a\n\
299 system-dependent error message, and @var{msgid} contains a unique\n\
300 message identifier.\n\
301 \n\
302 If the optional second parameter is supplied with value @code{\"s\"},\n\
303 recursively remove all subdirectories as well.\n\
304 @seealso{mkdir, confirm_recursive_rmdir}\n\
305 @end deftypefn")
306 {
307 octave_value_list retval;
308
309 retval(2) = std::string ();
310 retval(1) = std::string ();
311 retval(0) = false;
312
313 int nargin = args.length ();
314
315 if (nargin == 1 || nargin == 2)
316 {
317 std::string dirname = args(0).string_value ();
318
319 if (error_state)
320 gripe_wrong_type_arg ("rmdir", args(0));
321 else
322 {
323 std::string fulldir = file_ops::tilde_expand (dirname);
324 int status = -1;
325 std::string msg;
326
327 if (nargin == 2)
328 {
329 if (args(1).string_value () == "s")
330 {
331 bool doit = true;
332
333 if (interactive && Vconfirm_recursive_rmdir)
334 {
335 std::string prompt
336 = "remove entire contents of " + fulldir + "? ";
337
338 doit = octave_yes_or_no (prompt);
339 }
340
341 if (doit)
342 status = octave_recursive_rmdir (fulldir, msg);
343 }
344 else
345 error ("rmdir: expecting second argument to be \"s\"");
346 }
347 else
348 status = octave_rmdir (fulldir, msg);
349
350 if (status < 0)
351 {
352 retval(2) = "rmdir";
353 retval(1) = msg;
354 }
355 else
356 retval(0) = true;
357 }
358 }
359 else
360 print_usage ();
361
362 return retval;
363 }
364
365 DEFUNX ("link", Flink, args, ,
366 "-*- texinfo -*-\n\
367 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})\n\
368 Create a new link (also known as a hard link) to an existing file.\n\
369 \n\
370 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
371 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
372 system-dependent error message.\n\
373 @seealso{symlink}\n\
374 @end deftypefn")
375 {
376 octave_value_list retval;
377
378 retval(1) = std::string ();
379 retval(0) = -1.0;
380
381 if (args.length () == 2)
382 {
383 std::string from = args(0).string_value ();
384
385 if (error_state)
386 gripe_wrong_type_arg ("link", args(0));
387 else
388 {
389 std::string to = args(1).string_value ();
390
391 if (error_state)
392 gripe_wrong_type_arg ("link", args(1));
393 else
394 {
395 std::string msg;
396
397 int status = octave_link (from, to, msg);
398
399 retval(0) = status;
400
401 if (status < 0)
402 retval(1) = msg;
403 }
404 }
405 }
406 else
407 print_usage ();
408
409 return retval;
410 }
411
412 DEFUNX ("symlink", Fsymlink, args, ,
413 "-*- texinfo -*-\n\
414 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})\n\
415 Create a symbolic link @var{new} which contains the string @var{old}.\n\
416 \n\
417 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
418 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
419 system-dependent error message.\n\
420 @seealso{link, readlink}\n\
421 @end deftypefn")
422 {
423 octave_value_list retval;
424
425 retval(1) = std::string ();
426 retval(0) = -1.0;
427
428 if (args.length () == 2)
429 {
430 std::string from = args(0).string_value ();
431
432 if (error_state)
433 gripe_wrong_type_arg ("symlink", args(0));
434 else
435 {
436 std::string to = args(1).string_value ();
437
438 if (error_state)
439 gripe_wrong_type_arg ("symlink", args(1));
440 else
441 {
442 std::string msg;
443
444 int status = octave_symlink (from, to, msg);
445
446 retval(0) = status;
447
448 if (status < 0)
449 retval(1) = msg;
450 }
451 }
452 }
453 else
454 print_usage ();
455
456 return retval;
457 }
458
459 DEFUNX ("readlink", Freadlink, args, ,
460 "-*- texinfo -*-\n\
461 @deftypefn {Built-in Function} {[@var{result}, @var{err}, @var{msg}] =} readlink (@var{symlink})\n\
462 Read the value of the symbolic link @var{symlink}.\n\
463 \n\
464 If successful, @var{result} contains the contents of the symbolic link\n\
465 @var{symlink}, @var{err} is 0 and @var{msg} is an empty string.\n\
466 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
467 system-dependent error message.\n\
468 @seealso{link, symlink}\n\
469 @end deftypefn")
470 {
471 octave_value_list retval;
472
473 retval(2) = std::string ();
474 retval(1) = -1.0;
475 retval(0) = std::string ();
476
477 if (args.length () == 1)
478 {
479 std::string symlink = args(0).string_value ();
480
481 if (error_state)
482 gripe_wrong_type_arg ("readlink", args(0));
483 else
484 {
485 std::string result;
486 std::string msg;
487
488 int status = octave_readlink (symlink, result, msg);
489
490 if (status < 0)
491 retval(2) = msg;
492 retval(1) = status;
493 retval(0) = result;
494 }
495 }
496 else
497 print_usage ();
498
499 return retval;
500 }
501
502 DEFUNX ("rename", Frename, args, ,
503 "-*- texinfo -*-\n\
504 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})\n\
505 Change the name of file @var{old} to @var{new}.\n\
506 \n\
507 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
508 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
509 system-dependent error message.\n\
510 @seealso{ls, dir}\n\
511 @end deftypefn")
512 {
513 octave_value_list retval;
514
515 retval(1) = std::string ();
516 retval(0) = -1.0;
517
518 if (args.length () == 2)
519 {
520 std::string from = args(0).string_value ();
521
522 if (error_state)
523 gripe_wrong_type_arg ("rename", args(0));
524 else
525 {
526 std::string to = args(1).string_value ();
527
528 if (error_state)
529 gripe_wrong_type_arg ("rename", args(1));
530 else
531 {
532 std::string msg;
533
534 int status = octave_rename (from, to, msg);
535
536 retval(0) = status;
537
538 if (status < 0)
539 retval(1) = msg;
540 }
541 }
542 }
543 else
544 print_usage ();
545
546 return retval;
547 }
548
549 DEFUN (glob, args, ,
550 "-*- texinfo -*-\n\
551 @deftypefn {Built-in Function} {} glob (@var{pattern})\n\
552 Given an array of pattern strings (as a char array or a cell array) in\n\
553 @var{pattern}, return a cell array of file names that match any of\n\
554 them, or an empty cell array if no patterns match. The pattern strings are\n\
555 interpreted as filename globbing patterns (as they are used by Unix shells).\n\
556 Within a pattern\n\
557 \n\
558 @table @code\n\
559 @itemx *\n\
560 matches any string, including the null string,\n\
561 @itemx ?\n\
562 matches any single character, and\n\
563 \n\
564 @item [@dots{}]\n\
565 matches any of the enclosed characters.\n\
566 @end table\n\
567 \n\
568 Tilde expansion\n\
569 is performed on each of the patterns before looking for matching file\n\
570 names. For example:\n\
571 \n\
572 @example\n\
573 ls\n\
574 @result{}\n\
575 file1 file2 file3 myfile1 myfile1b\n\
576 glob (\"*file1\")\n\
577 @result{}\n\
578 @{\n\
579 [1,1] = file1\n\
580 [2,1] = myfile1\n\
581 @}\n\
582 glob (\"myfile?\")\n\
583 @result{}\n\
584 @{\n\
585 [1,1] = myfile1\n\
586 @}\n\
587 glob (\"file[12]\")\n\
588 @result{}\n\
589 @{\n\
590 [1,1] = file1\n\
591 [2,1] = file2\n\
592 @}\n\
593 @end example\n\
594 @seealso{ls, dir, readdir}\n\
595 @end deftypefn")
596 {
597 octave_value retval;
598
599 if (args.length () == 1)
600 {
601 string_vector pat = args(0).all_strings ();
602
603 if (error_state)
604 gripe_wrong_type_arg ("glob", args(0));
605 else
606 {
607 glob_match pattern (file_ops::tilde_expand (pat));
608
609 retval = Cell (pattern.glob ());
610 }
611 }
612 else
613 print_usage ();
614
615 return retval;
616 }
617
618 /*
619 %!test
620 %! tmpdir = tmpnam;
621 %! filename = {"file1", "file2", "file3", "myfile1", "myfile1b"};
622 %! if (mkdir (tmpdir))
623 %! cwd = pwd;
624 %! cd (tmpdir);
625 %! if strcmp (canonicalize_file_name (pwd), canonicalize_file_name (tmpdir))
626 %! a = 0;
627 %! for n = 1:5
628 %! save (filename{n}, "a");
629 %! endfor
630 %! else
631 %! rmdir (tmpdir);
632 %! error ("Couldn't change to temporary dir");
633 %! endif
634 %! else
635 %! error ("Couldn't create temporary directory");
636 %! endif
637 %! result1 = glob ("*file1");
638 %! result2 = glob ("myfile?");
639 %! result3 = glob ("file[12]");
640 %! for n = 1:5
641 %! delete (filename{n});
642 %! endfor
643 %! cd (cwd);
644 %! rmdir (tmpdir);
645 %! assert (result1, {"file1"; "myfile1"});
646 %! assert (result2, {"myfile1"});
647 %! assert (result3, {"file1"; "file2"});
648 */
649
650 DEFUNX ("fnmatch", Ffnmatch, args, ,
651 "-*- texinfo -*-\n\
652 @deftypefn {Built-in Function} {} fnmatch (@var{pattern}, @var{string})\n\
653 Return 1 or zero for each element of @var{string} that matches any of\n\
654 the elements of the string array @var{pattern}, using the rules of\n\
655 filename pattern matching. For example:\n\
656 \n\
657 @example\n\
658 @group\n\
659 fnmatch (\"a*b\", @{\"ab\"; \"axyzb\"; \"xyzab\"@})\n\
660 @result{} [ 1; 1; 0 ]\n\
661 @end group\n\
662 @end example\n\
663 @end deftypefn")
664 {
665 octave_value retval;
666
667 if (args.length () == 2)
668 {
669 string_vector pat = args(0).all_strings ();
670 string_vector str = args(1).all_strings ();
671
672 if (error_state)
673 gripe_wrong_type_arg ("fnmatch", args(0));
674 else
675 {
676 glob_match pattern (file_ops::tilde_expand (pat));
677
678 retval = pattern.match (str);
679 }
680 }
681 else
682 print_usage ();
683
684 return retval;
685 }
686
687 DEFUN (filesep, args, ,
688 "-*- texinfo -*-\n\
689 @deftypefn {Built-in Function} {} filesep ()\n\
690 @deftypefnx {Built-in Function} {} filesep (\"all\")\n\
691 Return the system-dependent character used to separate directory names.\n\
692 \n\
693 If \"all\" is given, the function returns all valid file separators in\n\
694 the form of a string. The list of file separators is system-dependent.\n\
695 It is @samp{/} (forward slash) under UNIX or @w{Mac OS X}, @samp{/} and\n\
696 @samp{\\} (forward and backward slashes) under Windows.\n\
697 @seealso{pathsep}\n\
698 @end deftypefn")
699 {
700 octave_value retval;
701
702 if (args.length () == 0)
703 retval = file_ops::dir_sep_str ();
704 else if (args.length () == 1)
705 {
706 std::string s = args(0).string_value ();
707
708 if (! error_state)
709 {
710 if (s == "all")
711 retval = file_ops::dir_sep_chars ();
712 else
713 gripe_wrong_type_arg ("filesep", args(0));
714 }
715 else
716 gripe_wrong_type_arg ("filesep", args(0));
717 }
718 else
719 print_usage ();
720
721 return retval;
722 }
723
724 DEFUN (pathsep, args, nargout,
725 "-*- texinfo -*-\n\
726 @deftypefn {Built-in Function} {@var{val} =} pathsep ()\n\
727 @deftypefnx {Built-in Function} {@var{old_val} =} pathsep (@var{new_val})\n\
728 Query or set the character used to separate directories in a path.\n\
729 @seealso{filesep}\n\
730 @end deftypefn")
731 {
732 octave_value retval;
733
734 int nargin = args.length ();
735
736 if (nargout > 0 || nargin == 0)
737 retval = dir_path::path_sep_str ();
738
739 if (nargin == 1)
740 {
741 std::string sval = args(0).string_value ();
742
743 if (! error_state)
744 {
745 switch (sval.length ())
746 {
747 case 1:
748 dir_path::path_sep_char (sval[0]);
749 break;
750
751 case 0:
752 dir_path::path_sep_char ('\0');
753 break;
754
755 default:
756 error ("pathsep: argument must be a single character");
757 break;
758 }
759 }
760 else
761 error ("pathsep: argument must be a single character");
762 }
763 else if (nargin > 1)
764 print_usage ();
765
766 return retval;
767 }
768
769 DEFUN (confirm_recursive_rmdir, args, nargout,
770 "-*- texinfo -*-\n\
771 @deftypefn {Built-in Function} {@var{val} =} confirm_recursive_rmdir ()\n\
772 @deftypefnx {Built-in Function} {@var{old_val} =} confirm_recursive_rmdir (@var{new_val})\n\
773 @deftypefnx {Built-in Function} {} confirm_recursive_rmdir (@var{new_val}, \"local\")\n\
774 Query or set the internal variable that controls whether Octave\n\
775 will ask for confirmation before recursively removing a directory tree.\n\
776 \n\
777 When called from inside a function with the \"local\" option, the variable is\n\
778 changed locally for the function and any subroutines it calls. The original\n\
779 variable value is restored when exiting the function.\n\
780 @end deftypefn")
781 {
782 return SET_INTERNAL_VARIABLE (confirm_recursive_rmdir);
783 }