GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-env.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 /*
24 
25 The functions listed below were adapted from a similar functions
26 from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
27 Free Software Foundation, Inc.
28 
29  octave::sys::env::do_absolute_pathname
30  octave::sys:env::do_base_pathname
31  octave::sys:env::do_chdir
32  octave::sys:env::do_getcwd
33  octave::sys:env::do_make_absolute
34  octave::sys:env::do_polite_directory_format
35  octave::sys:env::pathname_backup
36 
37 */
38 
39 #if defined (HAVE_CONFIG_H)
40 # include "config.h"
41 #endif
42 
43 #include <cctype>
44 #include <cstdlib>
45 #include <cstring>
46 
47 #include <string>
48 
49 #include "file-ops.h"
50 #include "lo-error.h"
51 #include "lo-sysdep.h"
52 #include "lo-utils.h"
53 #include "oct-env.h"
54 #include "oct-passwd.h"
55 #include "oct-syscalls.h"
57 #include "singleton-cleanup.h"
58 #include "unistd-wrappers.h"
59 
60 namespace octave
61 {
62  namespace sys
63  {
64  env::env (void)
65  : follow_symbolic_links (true), verbatim_pwd (true),
66  current_directory (), prog_name (), prog_invocation_name (),
67  user_name (), host_name ()
68  {
69  // Get a real value for the current directory.
70  do_getcwd ();
71 
72  // Etc.
74 
76  }
77 
78  env *env::instance = nullptr;
79 
80  bool
82  {
83  bool retval = true;
84 
85  if (! instance)
86  {
87  instance = new env ();
88 
89  if (instance)
91  }
92 
93  if (! instance)
94  (*current_liboctave_error_handler)
95  ("unable to create current working directory object!");
96 
97  return retval;
98  }
99 
102  {
103  return (instance_ok ())
105  }
106 
107  bool
109  {
110  return (instance_ok ())
111  ? instance->do_absolute_pathname (s) : false;
112  }
113 
114  bool
116  {
117  return (instance_ok ())
119  }
120 
123  {
124  return (instance_ok ())
125  ? instance->do_base_pathname (s) : "";
126  }
127 
129  env::make_absolute (const std::string& s, const std::string& dot_path)
130  {
131  return (instance_ok ())
132  ? instance->do_make_absolute (s, dot_path) : "";
133  }
134 
137  {
138  return (instance_ok ())
139  ? instance->do_getcwd () : "";
140  }
141 
144  {
145  return (instance_ok ())
146  ? instance->do_get_home_directory () : "";
147  }
148 
151  {
152  return (instance_ok ())
153  ? instance->do_get_temp_directory () : "";
154  }
155 
158  {
159  return (instance_ok ())
160  ? instance->prog_name : "";
161  }
162 
165  {
166  return (instance_ok ())
168  }
169 
170  void
172  {
173  if (instance_ok ())
175  }
176 
179  {
180  return (instance_ok ())
181  ? instance->do_get_user_name () : "";
182  }
183 
186  {
187  return (instance_ok ())
188  ? instance->do_get_host_name () : "";
189  }
190 
193  {
194  std::string tempd;
195 
196 #if defined (__MINGW32__) || defined (_MSC_VER)
197 
198  tempd = do_getenv ("TEMP");
199 
200  if (tempd.empty ())
201  tempd = do_getenv ("TMP");
202 
203 #if defined (P_tmpdir)
204  if (tempd.empty ())
205  tempd = P_tmpdir;
206 #endif
207 
208  // Some versions of MinGW and MSVC either don't define P_tmpdir, or
209  // define it to a single backslash. In such cases just use C:\temp.
210  if (tempd.empty () || tempd == R"(\)")
211  tempd = R"(c:\temp)";
212 
213 #else
214 
215  tempd = do_getenv ("TMP");
216 
217 #if defined (P_tmpdir)
218  if (tempd.empty ())
219  tempd = P_tmpdir;
220 #else
221  if (tempd.empty ())
222  tempd = "/tmp";
223 #endif
224 
225 #endif
226 
227  return tempd;
228  }
229 
230  // FIXME: this leaves no way to distinguish between a
231  // variable that is not set and one that is set to the empty string.
232  // Is this a problem?
233 
236  {
237  return (instance_ok ())
238  ? instance->do_getenv (name) : "";
239  }
240 
241  void
243  {
245  }
246 
247  bool
249  {
250  std::string display = getenv ("DISPLAY");
251 
252  return ! display.empty ();
253  }
254 
255  bool
256  env::chdir (const std::string& newdir)
257  {
258  return (instance_ok ())
259  ? instance->do_chdir (newdir) : false;
260  }
261 
262  void
264  {
265  static bool initialized = false;
266 
267  if (! initialized)
268  {
269  // octave_set_program_name_wrapper returns a cleaned up
270  // version of the program name (stripping libtool's "lt-"
271  // prefix, for example).
272 
273  // The string passed to gnulib's ::set_program_name function must
274  // exist for the duration of the program so allocate a copy here
275  // instead of passing S.c_str () which only exists as long as the
276  // string object S.
277 
280 
281  size_t pos
283 
284  // Also keep a shortened version of the program name.
285  prog_name = (pos == std::string::npos
287  : prog_invocation_name.substr (pos+1));
288 
289  initialized = true;
290  }
291  }
292 
293  // Return a pretty pathname. If the first part of the pathname is the
294  // same as $HOME, then replace that with '~'.
295 
298  {
300 
301  std::string home_dir = do_get_home_directory ();
302 
303  size_t len = home_dir.length ();
304 
305  if (len > 1 && home_dir == name.substr (0, len)
306  && (name.length () == len || sys::file_ops::is_dir_sep (name[len])))
307  {
308  retval = "~";
309  retval.append (name.substr (len));
310  }
311  else
312  retval = name;
313 
314  return retval;
315  }
316 
317  bool
319  {
320  size_t len = s.length ();
321 
322  if (len == 0)
323  return false;
324 
325  if (sys::file_ops::is_dir_sep (s[0]))
326  return true;
327 
328 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
329  if ((len == 2 && isalpha (s[0]) && s[1] == ':')
330  || (len > 2 && isalpha (s[0]) && s[1] == ':'
331  && sys::file_ops::is_dir_sep (s[2])))
332  return true;
333 #endif
334 
335  return false;
336  }
337 
338  bool
340  {
341  size_t len = s.length ();
342 
343  if (len == 0)
344  return false;
345 
346  if (len == 1 && s[0] == '.')
347  return true;
348 
349  if (len > 1 && s[0] == '.' && sys::file_ops::is_dir_sep (s[1]))
350  return true;
351 
352  if (len == 2 && s[0] == '.' && s[1] == '.')
353  return true;
354 
355  if (len > 2 && s[0] == '.' && s[1] == '.'
357  return true;
358 
359  return false;
360  }
361 
362  // Return the 'basename' of the pathname in STRING (the stuff after
363  // the last directory separator). If STRING is not a full pathname,
364  // simply return it.
365 
368  {
370  return s;
371 
372  size_t pos = s.find_last_of (sys::file_ops::dir_sep_chars ());
373 
374  if (pos == std::string::npos)
375  return s;
376  else
377  return s.substr (pos+1);
378  }
379 
380  // Turn STRING (a pathname) into an absolute pathname, assuming that
381  // DOT_PATH contains the symbolic location of the current directory.
382 
385  const std::string& dot_path) const
386  {
387  if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
388  return s;
389 
390  // Optimization: every time Octave returns to the prompt it calls
391  // make_absolute_filename with '.' as argument.
392  if (s == ".")
393  return dot_path;
394 
395  std::string current_dir = dot_path;
396 
397  if (! sys::file_ops::is_dir_sep (current_dir.back ()))
398  current_dir.append (sys::file_ops::dir_sep_str ());
399 
400  size_t i = 0;
401  size_t slen = s.length ();
402 
403  while (i < slen)
404  {
405  if (s[i] == '.')
406  {
407  if (i + 1 == slen)
408  break;
409 
410  if (sys::file_ops::is_dir_sep (s[i+1]))
411  {
412  i += 2;
413  continue;
414  }
415 
416  if (s[i+1] == '.'
417  && (i + 2 == slen
418  || sys::file_ops::is_dir_sep (s[i+2])))
419  {
420  i += 2;
421  if (i != slen)
422  i++;
423 
424  pathname_backup (current_dir, 1);
425 
426  continue;
427  }
428  }
429 
430  size_t sep_pos;
431  sep_pos = s.find_first_of (sys::file_ops::dir_sep_chars (), i);
432 
433  if (sep_pos == std::string::npos)
434  {
435  current_dir.append (s, i, sep_pos-i);
436  break;
437  }
438  else if (sep_pos == i)
439  {
440  /* Two separators in a row, skip adding 2nd separator */
441  i++;
442  }
443  else
444  {
445  current_dir.append (s, i, sep_pos-i+1);
446  i = sep_pos + 1;
447  }
448  }
449 
450  // Strip any trailing directory separator
451  if (sys::file_ops::is_dir_sep (current_dir.back ()))
452  current_dir.pop_back ();
453 
454  return current_dir;
455  }
456 
457  // Return a string which is the current working directory.
458 
460  env::do_getcwd () const
461  {
462  if (! follow_symbolic_links)
463  current_directory = "";
464 
465  if (verbatim_pwd || current_directory.empty ())
467 
468  return current_directory;
469  }
470 
471  // This value is not cached because it can change while Octave is
472  // running.
473 
476  {
477  std::string hd = do_getenv ("HOME");
478 
479 #if defined (__MINGW32__) || defined (_MSC_VER)
480  // Maybe we are started directly from cmd.exe.
481  if (hd.empty ())
482  {
483  std::string drv = do_getenv ("HOMEDRIVE");
484  if (drv.empty ())
485  hd = do_getenv ("HOMEPATH");
486  else
487  hd = drv + do_getenv ("HOMEPATH");
488  }
489 #endif
490 
491  if (hd.empty ())
492  {
494  sys::getuid ());
495 
496  hd = (pw ? pw.dir () : std::string (sys::file_ops::dir_sep_str ()));
497  }
498 
499  return hd;
500  }
501 
504  {
505  if (user_name.empty ())
506  {
508  sys::getuid ());
509 
510  user_name = (pw ? pw.name () : "unknown");
511  }
512 
513  return user_name;
514  }
515 
518  {
519  if (host_name.empty ())
520  {
521  char hostname[1024];
522 
523  int status = octave_gethostname_wrapper (hostname, 1023);
524 
525  host_name = (status < 0) ? "unknown" : hostname;
526  }
527 
528  return host_name;
529  }
530 
533  {
534  char *value = ::getenv (name.c_str ());
535 
536  return value ? value : "";
537  }
538 
539  // Do the work of changing to the directory NEWDIR.
540  // Handle symbolic link following, etc.
541 
542  bool
543  env::do_chdir (const std::string& newdir)
544  {
545  bool retval = false;
546 
548 
550  {
551  if (current_directory.empty ())
552  do_getcwd ();
553 
554  if (current_directory.empty ())
555  tmp = newdir;
556  else
558 
559  // Get rid of trailing directory separator.
560  if (tmp.length () > 1 && sys::file_ops::is_dir_sep (tmp.back ()))
561  tmp.pop_back ();
562 
563  if (! sys::chdir (tmp))
564  {
566  retval = true;
567  }
568  }
569  else
570  retval = (! sys::chdir (newdir));
571 
572  return retval;
573  }
574 
575  // Remove the last N directories from PATH.
576 
577  void
578  env::pathname_backup (std::string& path, int n) const
579  {
580  if (path.empty ())
581  return;
582 
583  size_t i = path.length () - 1;
584 
585  while (n--)
586  {
587  while (sys::file_ops::is_dir_sep (path[i]) && i > 0)
588  i--;
589 
590  while (! sys::file_ops::is_dir_sep (path[i]) && i > 0)
591  i--;
592 
593  i++;
594  }
595 
596  path.resize (i);
597  }
598 
599  void
600  env::error (int err_num) const
601  {
602  (*current_liboctave_error_handler) ("%s", std::strerror (err_num));
603  }
604 
605  void
606  env::error (const std::string& s) const
607  {
608  (*current_liboctave_error_handler) ("%s", s.c_str ());
609  }
610  }
611 }
void pathname_backup(std::string &path, int n) const
Definition: oct-env.cc:578
static std::string get_current_directory(void)
Definition: oct-env.cc:136
void octave_putenv(const std::string &name, const std::string &value)
Definition: lo-utils.cc:92
bool do_absolute_pathname(const std::string &s) const
Definition: oct-env.cc:318
static void putenv(const std::string &name, const std::string &value)
Definition: oct-env.cc:242
void error(int) const
Definition: oct-env.cc:600
std::string dir(void) const
Definition: oct-passwd.cc:96
static bool chdir(const std::string &newdir)
Definition: oct-env.cc:256
std::string dir_sep_chars(void)
Definition: file-ops.cc:242
std::string do_make_absolute(const std::string &s, const std::string &dot_path) const
Definition: oct-env.cc:384
void do_set_program_name(const std::string &s) const
Definition: oct-env.cc:263
std::string do_getenv(const std::string &name) const
Definition: oct-env.cc:532
std::string current_directory
Definition: oct-env.h:139
static password getpwuid(uid_t uid)
Definition: oct-passwd.cc:133
static bool rooted_relative_pathname(const std::string &s)
Definition: oct-env.cc:115
std::string do_get_user_name(void) const
Definition: oct-env.cc:503
s
Definition: file-io.cc:2729
bool follow_symbolic_links
Definition: oct-env.h:132
std::string host_name
Definition: oct-env.h:148
std::string dir_sep_str(void)
Definition: file-ops.cc:233
static std::string getenv(const std::string &name)
Definition: oct-env.cc:235
static bool instance_ok(void)
Definition: oct-env.cc:81
static std::string make_absolute(const std::string &s, const std::string &dot_path=get_current_directory())
Definition: oct-env.cc:129
nd deftypefn *std::string name
Definition: sysdep.cc:647
bool is_dir_sep(char c)
Definition: file-ops.cc:270
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 env * instance
Definition: oct-env.h:126
std::string getcwd(void)
Definition: lo-sysdep.cc:39
static void add(fptr f)
bool do_rooted_relative_pathname(const std::string &s) const
Definition: oct-env.cc:339
static std::string get_host_name(void)
Definition: oct-env.cc:185
static std::string get_user_name(void)
Definition: oct-env.cc:178
static bool absolute_pathname(const std::string &s)
Definition: oct-env.cc:108
double tmp
Definition: data.cc:6252
std::string do_get_home_directory(void) const
Definition: oct-env.cc:475
octave_value retval
Definition: data.cc:6246
std::string do_getcwd(void) const
Definition: oct-env.cc:460
static std::string base_pathname(const std::string &s)
Definition: oct-env.cc:122
static void cleanup_instance(void)
Definition: oct-env.h:128
static bool initialized
Definition: defaults.cc:48
bool do_chdir(const std::string &newdir)
Definition: oct-env.cc:543
std::string name(void) const
Definition: oct-passwd.cc:51
std::string do_base_pathname(const std::string &s) const
Definition: oct-env.cc:367
std::string prog_name
Definition: oct-env.h:142
static char * strsave(const char *s)
Definition: main.in.cc:190
std::string do_polite_directory_format(const std::string &name) const
Definition: oct-env.cc:297
static void set_program_name(const std::string &s)
Definition: oct-env.cc:171
std::string user_name
Definition: oct-env.h:146
std::string prog_invocation_name
Definition: oct-env.h:144
std::string do_get_host_name(void) const
Definition: oct-env.cc:517
int octave_gethostname_wrapper(char *nm, size_t len)
int chdir(const std::string &path_arg)
Definition: lo-sysdep.cc:59
for i
Definition: data.cc:5264
static bool have_x11_display(void)
Definition: oct-env.cc:248
static std::string get_program_invocation_name(void)
Definition: oct-env.cc:164
static std::string get_program_name(void)
Definition: oct-env.cc:157
bool verbatim_pwd
Definition: oct-env.h:136
uid_t getuid(void)
const char * octave_set_program_name_wrapper(const char *pname)
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:888
nd group nd example For each display the value
Definition: sysdep.cc:866
std::string do_get_temp_directory(void) const
Definition: oct-env.cc:192
static std::string polite_directory_format(const std::string &name)
Definition: oct-env.cc:101