GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
file-ops.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 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 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cerrno>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cstring>
31 
32 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
33 # include <algorithm>
34 #endif
35 
36 #include <iostream>
37 #include <vector>
38 
39 #include "areadlink-wrapper.h"
41 #include "dir-ops.h"
42 #include "file-ops.h"
43 #include "file-stat.h"
44 #include "gen-tempname-wrapper.h"
45 #include "oct-env.h"
46 #include "oct-locbuf.h"
47 #include "oct-passwd.h"
48 #include "quit.h"
49 #include "singleton-cleanup.h"
50 #include "stat-wrappers.h"
51 #include "str-vec.h"
52 #include "unistd-wrappers.h"
53 
54 namespace octave
55 {
56  namespace sys
57  {
58  file_ops *octave::sys::file_ops::instance = 0;
59 
60  bool
62  {
63  bool retval = true;
64 
65  if (! instance)
66  {
67 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
68  char system_dev_sep_char = ':';
69  char system_dir_sep_char = '\\';
70  std::string system_dir_sep_str = "\\";
71 #else
72  char system_dev_sep_char = 0;
73  char system_dir_sep_char = '/';
74  std::string system_dir_sep_str = "/";
75 #endif
76 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
77  std::string system_dir_sep_chars = "/\\";
78 #else
79  std::string system_dir_sep_chars = system_dir_sep_str;
80 #endif
81 
82  instance = new file_ops (system_dev_sep_char, system_dir_sep_char,
83  system_dir_sep_str, system_dir_sep_chars);
84 
85  if (instance)
86  singleton_cleanup_list::add (cleanup_instance);
87  }
88 
89  if (! instance)
90  (*current_liboctave_error_handler)
91  ("unable to create file_ops object!");
92 
93  return retval;
94  }
95 
96  // The following tilde-expansion code was stolen and adapted from
97  // readline.
98 
99  // The default value of tilde_additional_prefixes. This is set to
100  // whitespace preceding a tilde so that simple programs which do not
101  // perform any word separation get desired behavior.
102  static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 };
103 
104  // The default value of tilde_additional_suffixes. This is set to
105  // whitespace or newline so that simple programs which do not perform
106  // any word separation get desired behavior.
107  static const char *default_suffixes[] = { " ", "\n", ":", 0 };
108 
109  // If non-null, this contains the address of a function that the
110  // application wants called before trying the standard tilde
111  // expansions. The function is called with the text sans tilde, and
112  // returns a malloc()'ed string which is the expansion, or a NULL
113  // pointer if the expansion fails.
116 
117  // If non-null, this contains the address of a function to call if the
118  // standard meaning for expanding a tilde fails. The function is
119  // called with the text (sans tilde, as in "foo"), and returns a
120  // malloc()'ed string which is the expansion, or a NULL pointer if
121  // there is no expansion.
124 
125  // When non-null, this is a NULL terminated array of strings which are
126  // duplicates for a tilde prefix. Bash uses this to expand '=~' and
127  // ':~'.
130 
131  // When non-null, this is a NULL terminated array of strings which
132  // match the end of a username, instead of just "/". Bash sets this
133  // to ':' and '=~'.
136 
137  // Find the start of a tilde expansion in S, and return the index
138  // of the tilde which starts the expansion. Place the length of the
139  // text which identified this tilde starter in LEN, excluding the
140  // tilde itself.
141 
142  static size_t
143  tilde_find_prefix (const std::string& s, size_t& len)
144  {
145  len = 0;
146 
147  size_t s_len = s.length ();
148 
149  if (s_len == 0 || s[0] == '~')
150  return 0;
151 
153 
154  if (! prefixes.empty ())
155  {
156  for (size_t i = 0; i < s_len; i++)
157  {
158  for (int j = 0; j < prefixes.numel (); j++)
159  {
160  size_t pfx_len = prefixes[j].length ();
161 
162  if (prefixes[j] == s.substr (i, pfx_len))
163  {
164  len = pfx_len - 1;
165  return i + len;
166  }
167  }
168  }
169  }
170 
171  return s_len;
172  }
173 
174  // Find the end of a tilde expansion in S, and return the index
175  // of the character which ends the tilde definition.
176 
177  static size_t
179  {
180  size_t s_len = s.length ();
181 
183 
184  size_t i = 0;
185 
186  for ( ; i < s_len; i++)
187  {
189  break;
190 
191  if (! suffixes.empty ())
192  {
193  for (int j = 0; j < suffixes.numel (); j++)
194  {
195  size_t sfx_len = suffixes[j].length ();
196 
197  if (suffixes[j] == s.substr (i, sfx_len))
198  return i;
199  }
200  }
201  }
202 
203  return i;
204  }
205 
206  // Take FNAME and return the tilde prefix we want expanded.
207 
208  static std::string
210  {
211  size_t f_len = fname.length ();
212 
213  size_t len = 1;
214 
215  while (len < f_len && ! octave::sys::file_ops::is_dir_sep (fname[len]))
216  len++;
217 
218  return fname.substr (1, len);
219  }
220 
221  // Do the work of tilde expansion on FILENAME. FILENAME starts with a
222  // tilde.
223 
224  static std::string
226  {
227  size_t f_len = filename.length ();
228 
229  if (f_len == 0 || filename[0] != '~')
230  return std::string (filename);
231 
232  // A leading '~/' or a bare '~' is *always* translated to the value
233  // of $HOME or the home directory of the current user, regardless of
234  // any preexpansion hook.
235 
236  if (f_len == 1 || octave::sys::file_ops::is_dir_sep (filename[1]))
237  return octave::sys::env::get_home_directory () + filename.substr (1);
238 
239  std::string username = isolate_tilde_prefix (filename);
240 
241  size_t user_len = username.length ();
242 
243  std::string dirname;
244 
245  if (octave::sys::file_ops::tilde_expansion_preexpansion_hook)
246  {
247  std::string expansion
249 
250  if (! expansion.empty ())
251  return expansion + filename.substr (user_len+1);
252  }
253 
254  // No preexpansion hook, or the preexpansion hook failed. Look in the
255  // password database.
256 
258 
259  if (! pw)
260  {
261  // If the calling program has a special syntax for expanding tildes,
262  // and we couldn't find a standard expansion, then let them try.
263 
264  if (octave::sys::file_ops::tilde_expansion_failure_hook)
265  {
266  std::string expansion
268 
269  if (! expansion.empty ())
270  dirname = expansion + filename.substr (user_len+1);
271  }
272 
273  // If we don't have a failure hook, or if the failure hook did not
274  // expand the tilde, return a copy of what we were passed.
275 
276  if (dirname.empty ())
277  dirname = filename;
278  }
279  else
280  dirname = pw.dir () + filename.substr (user_len+1);
281 
282  return dirname;
283  }
284 
285  bool
287  {
288 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
289  return c == dev_sep_char ();
290 #else
291  octave_unused_parameter (c);
292 
293  return false;
294 #endif
295  }
296 
297  // If NAME has a leading ~ or ~user, Unix-style, expand it to the
298  // user's home directory. If no ~, or no <pwd.h>, just return NAME.
299 
302  {
303  if (name.find ('~') == std::string::npos)
304  return std::string (name);
305  else
306  {
308 
309  size_t name_len = name.length ();
310 
311  // Scan through S expanding tildes as we come to them.
312 
313  size_t pos = 0;
314 
315  while (1)
316  {
317  if (pos > name_len)
318  break;
319 
320  size_t len;
321 
322  // Make START point to the tilde which starts the expansion.
323 
324  size_t start = tilde_find_prefix (name.substr (pos), len);
325 
326  result.append (name.substr (pos, start));
327 
328  // Advance STRING to the starting tilde.
329 
330  pos += start;
331 
332  // Make FINI be the index of one after the last character of the
333  // username.
334 
335  size_t fini = tilde_find_suffix (name.substr (pos));
336 
337  // If both START and FINI are zero, we are all done.
338 
339  if (! (start || fini))
340  break;
341 
342  // Expand the entire tilde word, and copy it into RESULT.
343 
344  std::string tilde_word = name.substr (pos, fini);
345 
346  pos += fini;
347 
348  std::string expansion = tilde_expand_word (tilde_word);
349 
350  result.append (expansion);
351  }
352 
353  return result;
354  }
355  }
356 
357  // A vector version of the above.
358 
361  {
363 
364  int n = names.numel ();
365 
366  retval.resize (n);
367 
368  for (int i = 0; i < n; i++)
369  retval[i] = tilde_expand (names[i]);
370 
371  return retval;
372  }
373 
376  {
377  return dir.empty ()
378  ? file
379  : (is_dir_sep (dir[dir.length ()-1])
380  ? dir + file
381  : dir + dir_sep_char () + file);
382  }
383 
386  {
388 
389  if (dir_sep_char () == '/')
390  retval = path;
391  else
392  {
393  size_t n = path.length ();
394  for (size_t i = 0; i < n; i++)
395  {
396  if (path[i] == '/')
397  retval += dir_sep_char();
398  else
399  retval += path[i];
400  }
401  }
402 
403  return retval;
404  }
405 
406  int
407  mkdir (const std::string& nm, mode_t md)
408  {
409  std::string msg;
410  return octave::sys::mkdir (nm, md, msg);
411  }
412 
413  int
414  mkdir (const std::string& name, mode_t mode, std::string& msg)
415  {
416  msg = "";
417 
418  int status = octave_mkdir_wrapper (name.c_str (), mode);
419 
420  if (status < 0)
421  msg = std::strerror (errno);
422 
423  return status;
424  }
425 
426  int
427  mkfifo (const std::string& nm, mode_t md)
428  {
429  std::string msg;
430  return mkfifo (nm, md, msg);
431  }
432 
433  int
434  mkfifo (const std::string& name, mode_t mode, std::string& msg)
435  {
436  msg = "";
437 
438  int status = octave_mkfifo_wrapper (name.c_str (), mode);
439 
440  if (status < 0)
441  msg = std::strerror (errno);
442 
443  return status;
444  }
445 
446  int
447  link (const std::string& old_name, const std::string& new_name)
448  {
449  std::string msg;
450  return link (old_name, new_name, msg);
451  }
452 
453  int
454  link (const std::string& old_name, const std::string& new_name,
455  std::string& msg)
456  {
457  msg = "";
458 
459  int status = -1;
460 
461  status = octave_link_wrapper (old_name.c_str (), new_name.c_str ());
462 
463  if (status < 0)
464  msg = std::strerror (errno);
465 
466  return status;
467  }
468 
469  int
470  symlink (const std::string& old_name, const std::string& new_name)
471  {
472  std::string msg;
473  return symlink (old_name, new_name, msg);
474  }
475 
476  int
477  symlink (const std::string& old_name,
478  const std::string& new_name, std::string& msg)
479  {
480  msg = "";
481 
482  int status = -1;
483 
484  status = octave_symlink_wrapper (old_name.c_str (), new_name.c_str ());
485 
486  if (status < 0)
487  msg = std::strerror (errno);
488 
489  return status;
490  }
491 
492  int
494  {
495  std::string msg;
496  return readlink (path, result, msg);
497  }
498 
499  int
501  {
502  int status = -1;
503 
504  msg = "";
505 
506  char *buf = octave_areadlink_wrapper (path.c_str ());
507 
508  if (! buf)
509  msg = std::strerror (errno);
510  else
511  {
512  result = buf;
513  ::free (buf);
514  status = 0;
515  }
516 
517  return status;
518  }
519 
520  int
521  rename (const std::string& from, const std::string& to)
522  {
523  std::string msg;
524  return rename (from, to, msg);
525  }
526 
527  int
528  rename (const std::string& from, const std::string& to, std::string& msg)
529  {
530  int status = -1;
531 
532  msg = "";
533 
534  status = std::rename (from.c_str (), to.c_str ());
535 
536  if (status < 0)
537  msg = std::strerror (errno);
538 
539  return status;
540  }
541 
542  int
544  {
545  std::string msg;
546  return rmdir (name, msg);
547  }
548 
549  int
551  {
552  msg = "";
553 
554  int status = -1;
555 
556  status = octave_rmdir_wrapper (name.c_str ());
557 
558  if (status < 0)
559  msg = std::strerror (errno);
560 
561  return status;
562  }
563 
564  // And a version that works recursively.
565 
566  int
568  {
569  std::string msg;
570  return recursive_rmdir (name, msg);
571  }
572 
573  int
575  {
576  msg = "";
577 
578  int status = 0;
579 
580  octave::sys::dir_entry dir (name);
581 
582  if (dir)
583  {
584  string_vector dirlist = dir.read ();
585 
586  for (octave_idx_type i = 0; i < dirlist.numel (); i++)
587  {
588  octave_quit ();
589 
590  std::string nm = dirlist[i];
591 
592  // Skip current directory and parent.
593  if (nm == "." || nm == "..")
594  continue;
595 
597 
598  // Get info about the file. Don't follow links.
599  octave::sys::file_stat fs (fullnm, false);
600 
601  if (fs)
602  {
603  if (fs.is_dir ())
604  {
605  status = recursive_rmdir (fullnm, msg);
606 
607  if (status < 0)
608  break;
609  }
610  else
611  {
612  status = unlink (fullnm, msg);
613 
614  if (status < 0)
615  break;
616  }
617  }
618  else
619  {
620  msg = fs.error ();
621  break;
622  }
623  }
624 
625  if (status >= 0)
626  {
627  dir.close ();
628  status = rmdir (name, msg);
629  }
630  }
631  else
632  {
633  status = -1;
634 
635  msg = dir.error ();
636  }
637 
638  return status;
639  }
640 
641  int
642  umask (mode_t mode)
643  {
644  return octave_umask_wrapper (mode);
645  }
646 
647  int
649  {
650  std::string msg;
651  return unlink (name, msg);
652  }
653 
654  int
656  {
657  msg = "";
658 
659  int status = -1;
660 
661  status = octave_unlink_wrapper (name.c_str ());
662 
663  if (status < 0)
664  msg = std::strerror (errno);
665 
666  return status;
667  }
668 
670  tempnam (const std::string& dir, const std::string& pfx)
671  {
672  std::string msg;
673  return tempnam (dir, pfx, msg);
674  }
675 
677  tempnam (const std::string& dir, const std::string& pfx,
678  std::string& msg)
679  {
680  msg = "";
681 
683 
684  // get dir path to use for template
685  std::string templatename;
686  if (dir.empty ())
687  templatename = octave::sys::env::get_temp_directory ();
688  else if (! octave::sys::file_stat (dir, false).is_dir ())
689  templatename = octave::sys::env::get_temp_directory ();
690  else
691  templatename = dir;
692 
693  // add dir sep char if it is not there
694  if (*templatename.rbegin () != octave::sys::file_ops::dir_sep_char ())
695  templatename += octave::sys::file_ops::dir_sep_char ();
696 
697  if (pfx.empty ())
698  templatename += "file";
699  else
700  templatename += pfx;
701 
702  // add the required XXXXXX for the template
703  templatename += "XXXXXX";
704 
705  // create and copy template to char array for call to gen_tempname
706  char tname [templatename.length () + 1];
707 
708  strcpy (tname, templatename.c_str ());
709 
710  if (octave_gen_tempname_wrapper (tname) == -1)
711  msg = std::strerror (errno);
712  else
713  retval = tname;
714 
715  return retval;
716  }
717 
720  {
721  std::string msg;
722  return canonicalize_file_name (name, msg);
723  }
724 
727  {
728  msg = "";
729 
731 
732  char *tmp = octave_canonicalize_file_name_wrapper (name.c_str ());
733 
734  if (tmp)
735  {
736  retval = tmp;
737  free (tmp);
738  }
739 
740 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
741  // Canonical Windows file separator is backslash.
742  std::replace (retval.begin (), retval.end (), '/', '\\');
743 #endif
744 
745  if (retval.empty ())
746  msg = std::strerror (errno);
747 
748  return retval;
749  }
750  }
751 }
static std::string dir_sep_str(void)
Definition: file-ops.h:80
static password getpwnam(const std::string &nm)
Definition: oct-passwd.cc:152
static const char * default_prefixes[]
Definition: file-ops.cc:102
Octave interface to the compression and uncompression libraries.
Definition: aepbalance.cc:47
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:120
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:719
fname
Definition: load-save.cc:754
int octave_link_wrapper(const char *nm1, const char *nm2)
int unlink(const std::string &name)
Definition: file-ops.cc:648
static bool instance_ok(void)
Definition: file-ops.cc:61
int octave_rmdir_wrapper(const char *nm)
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
int symlink(const std::string &old_name, const std::string &new_name)
Definition: file-ops.cc:470
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6386
static bool is_dev_sep(char c)
Definition: file-ops.cc:286
std::string tempnam(const std::string &dir, const std::string &pfx)
Definition: file-ops.cc:670
bool empty(void) const
Definition: str-vec.h:79
std::string filename
Definition: urlwrite.cc:340
static string_vector tilde_additional_prefixes
Definition: file-ops.h:64
static tilde_expansion_hook tilde_expansion_preexpansion_hook
Definition: file-ops.h:60
Definition: dir-ops.h:36
s
Definition: file-io.cc:2682
static std::string tilde_expand(const std::string &)
Definition: file-ops.cc:301
void resize(octave_idx_type n, const std::string &rfv="")
Definition: str-vec.h:97
static size_t tilde_find_suffix(const std::string &s)
Definition: file-ops.cc:178
int octave_gen_tempname_wrapper(char *tmpl)
static file_ops * instance
Definition: file-ops.h:130
int recursive_rmdir(const std::string &name)
Definition: file-ops.cc:567
int rename(const std::string &from, const std::string &to)
Definition: file-ops.cc:521
static std::string isolate_tilde_prefix(const std::string &fname)
Definition: file-ops.cc:209
static const char * default_suffixes[]
Definition: file-ops.cc:107
string_vector read(void)
Definition: dir-ops.cc:70
int octave_symlink_wrapper(const char *nm1, const char *nm2)
bool is_dir(void) const
Definition: file-stat.cc:57
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:941
std::string dir(void) const
Definition: oct-passwd.cc:96
static void replace(QString &text, const QRegExp &re, const QString &after)
Definition: parser.cc:561
static std::string get_home_directory(void)
Definition: oct-env.cc:143
static std::string get_temp_directory(void)
Definition: oct-env.cc:150
static void add(fptr f)
int octave_unlink_wrapper(const char *nm)
int link(const std::string &old_name, const std::string &new_name)
Definition: file-ops.cc:447
char * octave_canonicalize_file_name_wrapper(const char *name)
static char dir_sep_char(void)
Definition: file-ops.h:75
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
static const char dir_sep_char
Definition: shared-fcns.h:75
static tilde_expansion_hook tilde_expansion_failure_hook
Definition: file-ops.h:62
octave_idx_type length(void) const
Definition: ov.cc:1623
static size_t tilde_find_prefix(const std::string &s, size_t &len)
Definition: file-ops.cc:143
int octave_umask_wrapper(mode_t mode)
Definition: stat-wrappers.c:52
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
may be zero for pure relative error test tem the relative tolerance must be greater than or equal to
Definition: Quad-opts.cc:233
With real return the complex result
Definition: data.cc:3375
int umask(mode_t mode)
Definition: file-ops.cc:642
static std::string concat(const std::string &, const std::string &)
Definition: file-ops.cc:375
std::string(* tilde_expansion_hook)(const std::string &)
Definition: file-ops.h:58
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:354
int mkdir(const std::string &nm, mode_t md)
Definition: file-ops.cc:407
int rmdir(const std::string &name)
Definition: file-ops.cc:543
octave::sys::time start
Definition: graphics.cc:11731
int octave_mkfifo_wrapper(const char *name, mode_t mode)
Definition: stat-wrappers.c:46
void free(void *)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
static std::string native_separator_path(const std::string &path)
Definition: file-ops.cc:385
static std::string tilde_expand_word(const std::string &filename)
Definition: file-ops.cc:225
int readlink(const std::string &path, std::string &result)
Definition: file-ops.cc:493
octave::sys::file_stat fs(filename)
static string_vector tilde_additional_suffixes
Definition: file-ops.h:66
std::string error(void) const
Definition: file-stat.h:146
int octave_mkdir_wrapper(const char *name, mode_t mode)
Definition: stat-wrappers.c:40
int rename(const std::string &from, const std::string &to, std::string &msg)
Definition: file-ops.cc:528
std::string error(void) const
Definition: dir-ops.h:77
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
static bool is_dir_sep(char c)
Definition: file-ops.h:90
int mkfifo(const std::string &nm, mode_t md)
Definition: file-ops.cc:427
bool close(void)
Definition: dir-ops.cc:90