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