GNU Octave  8.1.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-2023 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-password.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 <windows.h>
65 # include <shlobj.h>
66 #endif
67 
69 
71 
72 env::env (void)
73  : m_follow_symbolic_links (true), m_verbatim_pwd (true),
74  m_current_directory (), m_prog_name (), m_prog_invocation_name (),
75  m_user_name (), m_host_name ()
76 {
77  // Get a real value for the current directory.
78  do_getcwd ();
79 
80  // Etc.
81  do_get_user_name ();
82 
83  do_get_host_name ();
84 }
85 
86 env *env::m_instance = nullptr;
87 
88 bool
90 {
91  bool retval = true;
92 
93  if (! m_instance)
94  {
95  m_instance = new env ();
97  }
98 
99  return retval;
100 }
101 
102 std::string
103 env::polite_directory_format (const std::string& name)
104 {
105  return (instance_ok ())
106  ? m_instance->do_polite_directory_format (name) : "";
107 }
108 
109 bool
110 env::absolute_pathname (const std::string& s)
111 {
112  return (instance_ok ())
113  ? m_instance->do_absolute_pathname (s) : false;
114 }
115 
116 bool
117 env::rooted_relative_pathname (const std::string& s)
118 {
119  return (instance_ok ())
121 }
122 
123 std::string
124 env::base_pathname (const std::string& s)
125 {
126  return (instance_ok ())
127  ? m_instance->do_base_pathname (s) : "";
128 }
129 
130 std::string
131 env::make_absolute (const std::string& s, const std::string& dot_path)
132 {
133  return (instance_ok ())
134  ? m_instance->do_make_absolute (s, dot_path) : "";
135 }
136 
137 std::string
139 {
140  return (instance_ok ())
141  ? m_instance->do_getcwd () : "";
142 }
143 
144 std::string
146 {
147  return (instance_ok ())
149 }
150 
151 std::string
153 {
154  return (instance_ok ())
156 }
157 
158 std::string
160 {
161  return (instance_ok ())
163 }
164 
165 std::string
167 {
168  return (instance_ok ())
170 }
171 
172 std::string
174 {
175  return (instance_ok ())
176  ? m_instance->m_prog_name : "";
177 }
178 
179 std::string
181 {
182  return (instance_ok ())
184 }
185 
186 void
187 env::set_program_name (const std::string& s)
188 {
189  if (instance_ok ())
191 }
192 
193 std::string
195 {
196  return (instance_ok ())
197  ? m_instance->do_get_user_name () : "";
198 }
199 
200 std::string
202 {
203  return (instance_ok ())
204  ? m_instance->do_get_host_name () : "";
205 }
206 
207 std::string
209 {
210  std::string tempd = do_getenv ("TMPDIR");
211 
212 #if defined (__MINGW32__) || defined (_MSC_VER)
213 
214  if (tempd.empty ())
215  tempd = do_getenv ("TEMP");
216 
217  if (tempd.empty ())
218  tempd = do_getenv ("TMP");
219 
220 #if defined (P_tmpdir)
221  if (tempd.empty ())
222  tempd = P_tmpdir;
223 #endif
224 
225  // Some versions of MinGW and MSVC either don't define P_tmpdir, or
226  // define it to a single backslash. In such cases just use C:\temp.
227  if (tempd.empty () || tempd == R"(\)")
228  tempd = R"(c:\temp)";
229 
230 #else
231 
232  if (tempd.empty ())
233  tempd = do_getenv ("TMP");
234 
235 #if defined (P_tmpdir)
236  if (tempd.empty ())
237  tempd = P_tmpdir;
238 #else
239  if (tempd.empty ())
240  tempd = "/tmp";
241 #endif
242 
243 #endif
244 
245  return tempd;
246 }
247 
248 std::string
250 {
251  std::string cfg_dir;
252 
253 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
254  wchar_t path[MAX_PATH+1];
255  if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
256  nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
257  cfg_dir = u8_from_wstring (path);
258 #else
259  cfg_dir = do_getenv ("XDG_CONFIG_HOME");
260 #endif
261 
262  if (cfg_dir.empty ())
264  + ".config";
265 
266  return cfg_dir;
267 }
268 
269 std::string
271 {
272  std::string data_dir;
273 
274 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
275  wchar_t path[MAX_PATH+1];
276  if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
277  nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
278  data_dir = u8_from_wstring (path);
279 #else
280  data_dir = do_getenv ("XDG_DATA_HOME");
281 #endif
282 
283  if (data_dir.empty ())
285  + ".local" + sys::file_ops::dir_sep_str () + "share";
286 
287  return data_dir;
288 }
289 
290 
291 // FIXME: this leaves no way to distinguish between a
292 // variable that is not set and one that is set to the empty string.
293 // Is this a problem?
294 
295 std::string
296 env::getenv (const std::string& name)
297 {
298  return (instance_ok ())
299  ? m_instance->do_getenv (name) : "";
300 }
301 
302 void
303 env::putenv (const std::string& name, const std::string& value)
304 {
305  putenv_wrapper (name, value);
306 }
307 
308 bool
310 {
311  std::string display = getenv ("DISPLAY");
312 
313  return ! display.empty ();
314 }
315 
316 bool
317 env::chdir (const std::string& newdir)
318 {
319  return (instance_ok ())
320  ? m_instance->do_chdir (newdir) : false;
321 }
322 
323 void
324 env::do_set_program_name (const std::string& s)
325 {
326  static bool initialized = false;
327 
328  if (! initialized)
329  {
330  // octave_set_program_name_wrapper returns a cleaned up
331  // version of the program name (stripping libtool's "lt-"
332  // prefix, for example).
333 
334  // The string passed to gnulib's ::set_program_name function must
335  // exist for the duration of the program so allocate a copy here
336  // instead of passing S.c_str () which only exists as long as the
337  // string object S.
338 
340  = octave_set_program_name_wrapper (strsave (s.c_str ()));
341 
342  std::size_t pos
344 
345  // Also keep a shortened version of the program name.
346  m_prog_name = (pos == std::string::npos
348  : m_prog_invocation_name.substr (pos+1));
349 
350  initialized = true;
351  }
352 }
353 
354 // Return a pretty pathname. If the first part of the pathname is the
355 // same as $HOME, then replace that with '~'.
356 
357 std::string
358 env::do_polite_directory_format (const std::string& name)
359 {
360  std::string retval;
361 
362  std::string home_dir = do_get_home_directory ();
363 
364  std::size_t len = home_dir.length ();
365 
366  if (len > 1 && home_dir == name.substr (0, len)
367  && (name.length () == len || sys::file_ops::is_dir_sep (name[len])))
368  {
369  retval = "~";
370  retval.append (name.substr (len));
371  }
372  else
373  retval = name;
374 
375  return retval;
376 }
377 
378 bool
379 env::do_absolute_pathname (const std::string& s) const
380 {
381  std::size_t len = s.length ();
382 
383  if (len == 0)
384  return false;
385 
386  if (sys::file_ops::is_dir_sep (s[0]))
387  return true;
388 
389 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
390  if ((len == 2 && isalpha (s[0]) && s[1] == ':')
391  || (len > 2 && isalpha (s[0]) && s[1] == ':'
392  && sys::file_ops::is_dir_sep (s[2])))
393  return true;
394 #endif
395 
396  return false;
397 }
398 
399 bool
400 env::do_rooted_relative_pathname (const std::string& s) const
401 {
402  std::size_t len = s.length ();
403 
404  if (len == 0)
405  return false;
406 
407  if (len == 1 && s[0] == '.')
408  return true;
409 
410  if (len > 1 && s[0] == '.' && sys::file_ops::is_dir_sep (s[1]))
411  return true;
412 
413  if (len == 2 && s[0] == '.' && s[1] == '.')
414  return true;
415 
416  if (len > 2 && s[0] == '.' && s[1] == '.'
417  && sys::file_ops::is_dir_sep (s[2]))
418  return true;
419 
420  return false;
421 }
422 
423 // Return the 'basename' of the pathname in STRING (the stuff after
424 // the last directory separator). If STRING is not a full pathname,
425 // simply return it.
426 
427 std::string
428 env::do_base_pathname (const std::string& s) const
429 {
431  return s;
432 
433  std::size_t pos = s.find_last_of (sys::file_ops::dir_sep_chars ());
434 
435  if (pos == std::string::npos)
436  return s;
437  else
438  return s.substr (pos+1);
439 }
440 
441 // Turn STRING (a pathname) into an absolute pathname, assuming that
442 // DOT_PATH contains the symbolic location of the current directory.
443 
444 std::string
445 env::do_make_absolute (const std::string& s,
446  const std::string& dot_path) const
447 {
448  if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
449  return s;
450 
451  // Optimization: every time Octave returns to the prompt it calls
452  // make_absolute_filename with '.' as argument.
453  if (s == ".")
454  return dot_path;
455 
456  std::string current_dir = dot_path;
457 
458  if (! sys::file_ops::is_dir_sep (current_dir.back ()))
459  current_dir.append (sys::file_ops::dir_sep_str ());
460 
461  std::size_t i = 0;
462  std::size_t slen = s.length ();
463 
464  while (i < slen)
465  {
466  if (s[i] == '.')
467  {
468  if (i + 1 == slen)
469  break;
470 
471  if (sys::file_ops::is_dir_sep (s[i+1]))
472  {
473  i += 2;
474  continue;
475  }
476 
477  if (s[i+1] == '.'
478  && (i + 2 == slen
479  || sys::file_ops::is_dir_sep (s[i+2])))
480  {
481  i += 2;
482  if (i != slen)
483  i++;
484 
485  pathname_backup (current_dir, 1);
486 
487  continue;
488  }
489  }
490 
491  std::size_t sep_pos;
492  sep_pos = s.find_first_of (sys::file_ops::dir_sep_chars (), i);
493 
494  if (sep_pos == std::string::npos)
495  {
496  current_dir.append (s, i, sep_pos-i);
497  break;
498  }
499  else if (sep_pos == i)
500  {
501  /* Two separators in a row, skip adding 2nd separator */
502  i++;
503  }
504  else
505  {
506  current_dir.append (s, i, sep_pos-i+1);
507  i = sep_pos + 1;
508  }
509  }
510 
511  // Strip any trailing directory separator
512  if (sys::file_ops::is_dir_sep (current_dir.back ()))
513  current_dir.pop_back ();
514 
515  return current_dir;
516 }
517 
518 // Return a string which is the current working directory.
519 
520 std::string
522 {
524  m_current_directory = "";
525 
526  if (m_verbatim_pwd || m_current_directory.empty ())
528 
529  return m_current_directory;
530 }
531 
532 // This value is not cached because it can change while Octave is
533 // running.
534 
535 std::string
537 {
538  std::string hd = do_getenv ("HOME");
539 
540 #if defined (__MINGW32__) || defined (_MSC_VER)
541  // Maybe we are started directly from cmd.exe.
542  if (hd.empty ())
543  {
544  std::string drv = do_getenv ("HOMEDRIVE");
545  if (drv.empty ())
546  hd = do_getenv ("HOMEPATH");
547  else
548  hd = drv + do_getenv ("HOMEPATH");
549  }
550 #endif
551 
552  if (hd.empty ())
553  {
554  sys::password pw = sys::password::getpwuid (sys::getuid ());
555 
556  hd = (pw ? pw.dir () : std::string (sys::file_ops::dir_sep_str ()));
557  }
558 
559  return hd;
560 }
561 
562 std::string
564 {
565  if (m_user_name.empty ())
566  {
567  sys::password pw = sys::password::getpwuid (sys::getuid ());
568 
569  m_user_name = (pw ? pw.name () : "unknown");
570  }
571 
572  return m_user_name;
573 }
574 
575 std::string
577 {
578  if (m_host_name.empty ())
579  {
580  char hostname[1024];
581 
582  int status = octave_gethostname_wrapper (hostname, 1023);
583 
584  m_host_name = (status < 0) ? "unknown" : hostname;
585  }
586 
587  return m_host_name;
588 }
589 
590 std::string
591 env::do_getenv (const std::string& name) const
592 {
593  return getenv_wrapper (name);
594 }
595 
596 // Do the work of changing to the directory NEWDIR.
597 // Handle symbolic link following, etc.
598 
599 bool
600 env::do_chdir (const std::string& newdir)
601 {
602  bool retval = false;
603 
604  std::string tmp;
605 
607  {
608  if (m_current_directory.empty ())
609  do_getcwd ();
610 
611  if (m_current_directory.empty ())
612  tmp = newdir;
613  else
614  tmp = do_make_absolute (newdir, m_current_directory);
615 
616  // Get rid of trailing directory separator.
617  if (tmp.length () > 1 && sys::file_ops::is_dir_sep (tmp.back ()))
618  tmp.pop_back ();
619 
620  if (! sys::chdir (tmp))
621  {
622  m_current_directory = tmp;
623  retval = true;
624  }
625  }
626  else
627  retval = (! sys::chdir (newdir));
628 
629  return retval;
630 }
631 
632 // Remove the last N directories from PATH.
633 
634 void
635 env::pathname_backup (std::string& path, int n) const
636 {
637  if (path.empty ())
638  return;
639 
640  std::size_t i = path.length () - 1;
641 
642  while (n--)
643  {
644  while (sys::file_ops::is_dir_sep (path[i]) && i > 0)
645  i--;
646 
647 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
648  // Don't strip file letter part.
649  if (i == 1 && path[i] == ':')
650  {
651  // Keep path separator if present.
652  i = std::min (i+2, path.length ());
653  break;
654  }
655 #endif
656 
657  while (! sys::file_ops::is_dir_sep (path[i]) && i > 0)
658  i--;
659 
660  i++;
661  }
662 
663  path.resize (i);
664 }
665 
666 void
667 env::error (int err_num) const
668 {
669  (*current_liboctave_error_handler) ("%s", std::strerror (err_num));
670 }
671 
672 void
673 env::error (const std::string& s) const
674 {
675  (*current_liboctave_error_handler) ("%s", s.c_str ());
676 }
677 
OCTAVE_END_NAMESPACE(octave)
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
Definition: oct-env.h:40
bool do_rooted_relative_pathname(const std::string &s) const
Definition: oct-env.cc:400
static std::string base_pathname(const std::string &s)
Definition: oct-env.cc:124
static std::string get_host_name(void)
Definition: oct-env.cc:201
std::string do_base_pathname(const std::string &s) const
Definition: oct-env.cc:428
void error(int) const
Definition: oct-env.cc:667
static std::string get_home_directory(void)
Definition: oct-env.cc:145
std::string do_get_host_name(void)
Definition: oct-env.cc:576
std::string do_polite_directory_format(const std::string &name)
Definition: oct-env.cc:358
static std::string get_user_config_directory(void)
Definition: oct-env.cc:159
static std::string getenv(const std::string &name)
Definition: oct-env.cc:296
static bool absolute_pathname(const std::string &s)
Definition: oct-env.cc:110
bool m_verbatim_pwd
Definition: oct-env.h:148
std::string do_getcwd(void)
Definition: oct-env.cc:521
std::string do_make_absolute(const std::string &s, const std::string &dot_path) const
Definition: oct-env.cc:445
std::string do_get_user_config_directory(void)
Definition: oct-env.cc:249
static std::string get_user_data_directory(void)
Definition: oct-env.cc:166
void do_set_program_name(const std::string &s)
Definition: oct-env.cc:324
std::string m_prog_invocation_name
Definition: oct-env.h:156
void pathname_backup(std::string &path, int n) const
Definition: oct-env.cc:635
static bool rooted_relative_pathname(const std::string &s)
Definition: oct-env.cc:117
static bool chdir(const std::string &newdir)
Definition: oct-env.cc:317
static std::string make_absolute(const std::string &s, const std::string &dot_path=get_current_directory())
Definition: oct-env.cc:131
std::string do_get_user_name(void)
Definition: oct-env.cc:563
std::string do_get_home_directory(void)
Definition: oct-env.cc:536
static std::string get_program_invocation_name(void)
Definition: oct-env.cc:180
static bool have_x11_display(void)
Definition: oct-env.cc:309
static std::string get_current_directory(void)
Definition: oct-env.cc:138
std::string do_get_temp_directory(void) const
Definition: oct-env.cc:208
static void putenv(const std::string &name, const std::string &value)
Definition: oct-env.cc:303
static std::string get_user_name(void)
Definition: oct-env.cc:194
std::string m_user_name
Definition: oct-env.h:158
static std::string get_program_name(void)
Definition: oct-env.cc:173
std::string do_getenv(const std::string &name) const
Definition: oct-env.cc:591
static void cleanup_instance(void)
Definition: oct-env.h:139
static std::string polite_directory_format(const std::string &name)
Definition: oct-env.cc:103
std::string m_current_directory
Definition: oct-env.h:151
bool do_chdir(const std::string &newdir)
Definition: oct-env.cc:600
bool do_absolute_pathname(const std::string &s) const
Definition: oct-env.cc:379
std::string do_get_user_data_directory(void)
Definition: oct-env.cc:270
static bool instance_ok(void)
Definition: oct-env.cc:89
std::string m_host_name
Definition: oct-env.h:160
std::string m_prog_name
Definition: oct-env.h:154
static env * m_instance
Definition: oct-env.h:137
static std::string get_temp_directory(void)
Definition: oct-env.cc:152
static void set_program_name(const std::string &s)
Definition: oct-env.cc:187
bool m_follow_symbolic_links
Definition: oct-env.h:144
env(void)
Definition: oct-env.cc:72
static void add(fptr f)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::string data_dir(void)
Definition: defaults.cc:179
std::string dir_sep_str(void)
Definition: file-ops.cc:240
std::string u8_from_wstring(const std::wstring &wchar_string)
Definition: lo-sysdep.cc:537
std::string getcwd(void)
Definition: lo-sysdep.cc:71
std::string getenv_wrapper(const std::string &name)
Definition: lo-sysdep.cc:488
int chdir(const std::string &path_arg)
Definition: lo-sysdep.cc:106
void putenv_wrapper(const std::string &name, const std::string &value)
Definition: lo-sysdep.cc:452
static char * strsave(const char *s)
Definition: main.in.cc:214
octave_idx_type n
Definition: mx-inlines.cc:753
uid_t getuid(void)
const char * octave_set_program_name_wrapper(const char *pname)
static bool is_dir_sep(char c)
Definition: shared-fcns.h:142
static std::string dir_sep_chars
Definition: shared-fcns.h:96
int octave_gethostname_wrapper(char *nm, size_t len)
F77_RET_T len
Definition: xerbla.cc:61