GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-env.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2025 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
28The functions listed below were adapted from a similar functions
29from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
30Free 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
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
86env *env::s_instance = nullptr;
87
88bool
89env::instance_ok ()
90{
91 bool retval = true;
92
93 if (! s_instance)
94 {
95 s_instance = new env ();
96 singleton_cleanup_list::add (cleanup_instance);
97 }
98
99 return retval;
100}
101
102std::string
103env::polite_directory_format (const std::string& name)
104{
105 return (instance_ok ())
106 ? s_instance->do_polite_directory_format (name) : "";
107}
108
109bool
110env::absolute_pathname (const std::string& s)
111{
112 return (instance_ok ())
113 ? s_instance->do_absolute_pathname (s) : false;
114}
115
116bool
117env::rooted_relative_pathname (const std::string& s)
118{
119 return (instance_ok ())
120 ? s_instance->do_rooted_relative_pathname (s) : false;
121}
122
123std::string
124env::base_pathname (const std::string& s)
125{
126 return (instance_ok ())
127 ? s_instance->do_base_pathname (s) : "";
128}
129
130std::string
131env::make_absolute (const std::string& s, const std::string& dot_path)
132{
133 return (instance_ok ())
134 ? s_instance->do_make_absolute (s, dot_path) : "";
135}
136
137std::string
139{
140 return (instance_ok ())
141 ? s_instance->do_getcwd () : "";
142}
143
144std::string
146{
147 return (instance_ok ())
148 ? s_instance->do_get_home_directory () : "";
149}
150
151std::string
153{
154 return (instance_ok ())
155 ? s_instance->do_get_temp_directory () : "";
156}
157
158std::string
160{
161 return (instance_ok ())
162 ? s_instance->do_get_user_config_directory () : "";
163}
164
165std::string
167{
168 return (instance_ok ())
169 ? s_instance->do_get_user_data_directory () : "";
170}
171
172std::string
174{
175 return (instance_ok ())
176 ? s_instance->m_prog_name : "";
177}
178
179std::string
181{
182 return (instance_ok ())
183 ? s_instance->m_prog_invocation_name : "";
184}
185
186void
187env::set_program_name (const std::string& s)
188{
189 if (instance_ok ())
190 s_instance->do_set_program_name (s);
191}
192
193std::string
195{
196 return (instance_ok ())
197 ? s_instance->do_get_user_name () : "";
198}
199
200std::string
202{
203 return (instance_ok ())
204 ? s_instance->do_get_host_name () : "";
205}
206
207std::string
208env::do_get_temp_directory () const
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
248std::string
249env::do_get_user_config_directory ()
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 ())
263 cfg_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
264 + ".config";
265
266 return cfg_dir;
267}
268
269std::string
270env::do_get_user_data_directory ()
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 ())
284 data_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
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
295std::string
296env::getenv (const std::string& name)
297{
298 return (instance_ok ())
299 ? s_instance->do_getenv (name) : "";
300}
301
302bool
303env::isenv (const std::string& name)
304{
305 return isenv_wrapper (name);
306}
307
308void
309env::putenv (const std::string& name, const std::string& value)
310{
311 putenv_wrapper (name, value);
312}
313
314bool
316{
317 std::string display = getenv ("DISPLAY");
318
319 return ! display.empty ();
320}
321
322bool
323env::chdir (const std::string& newdir)
324{
325 return (instance_ok ())
326 ? s_instance->do_chdir (newdir) : false;
327}
328
329void
330env::do_set_program_name (const std::string& s)
331{
332 static bool initialized = false;
333
334 if (! initialized)
335 {
336 // octave_set_program_name_wrapper returns a cleaned up
337 // version of the program name (stripping libtool's "lt-"
338 // prefix, for example).
339
340 // The string passed to gnulib's ::set_program_name function must
341 // exist for the duration of the program so allocate a copy here
342 // instead of passing S.c_str () which only exists as long as the
343 // string object S.
344
345 m_prog_invocation_name
346 = octave_set_program_name_wrapper (strsave (s.c_str ()));
347
348 std::size_t pos
349 = m_prog_invocation_name.find_last_of (sys::file_ops::dir_sep_chars ());
350
351 // Also keep a shortened version of the program name.
352 m_prog_name = (pos == std::string::npos
353 ? m_prog_invocation_name
354 : m_prog_invocation_name.substr (pos+1));
355
356 initialized = true;
357 }
358}
359
360// Return a pretty pathname. If the first part of the pathname is the
361// same as $HOME, then replace that with '~'.
362
363std::string
364env::do_polite_directory_format (const std::string& name)
365{
366 std::string retval;
367
368 std::string home_dir = do_get_home_directory ();
369
370 std::size_t len = home_dir.length ();
371
372 if (len > 1 && home_dir == name.substr (0, len)
373 && (name.length () == len || sys::file_ops::is_dir_sep (name[len])))
374 {
375 retval = "~";
376 retval.append (name.substr (len));
377 }
378 else
379 retval = name;
380
381 return retval;
382}
383
384bool
385env::do_absolute_pathname (const std::string& s) const
386{
387 std::size_t len = s.length ();
388
389 if (len == 0)
390 return false;
391
392 if (sys::file_ops::is_dir_sep (s[0]))
393 return true;
394
395#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
396 if ((len == 2 && isalpha (s[0]) && s[1] == ':')
397 || (len > 2 && isalpha (s[0]) && s[1] == ':'
398 && sys::file_ops::is_dir_sep (s[2])))
399 return true;
400#endif
401
402 return false;
403}
404
405bool
406env::do_rooted_relative_pathname (const std::string& s) const
407{
408 std::size_t len = s.length ();
409
410 if (len == 0)
411 return false;
412
413 if (len == 1 && s[0] == '.')
414 return true;
415
416 if (len > 1 && s[0] == '.' && sys::file_ops::is_dir_sep (s[1]))
417 return true;
418
419 if (len == 2 && s[0] == '.' && s[1] == '.')
420 return true;
421
422 if (len > 2 && s[0] == '.' && s[1] == '.'
423 && sys::file_ops::is_dir_sep (s[2]))
424 return true;
425
426 return false;
427}
428
429// Return the 'basename' of the pathname in STRING (the stuff after
430// the last directory separator). If STRING is not a full pathname,
431// simply return it.
432
433std::string
434env::do_base_pathname (const std::string& s) const
435{
436 if (! (do_absolute_pathname (s) || do_rooted_relative_pathname (s)))
437 return s;
438
439 std::size_t pos = s.find_last_of (sys::file_ops::dir_sep_chars ());
440
441 if (pos == std::string::npos)
442 return s;
443 else
444 return s.substr (pos+1);
445}
446
447// Turn STRING (a pathname) into an absolute pathname, assuming that
448// DOT_PATH contains the symbolic location of the current directory.
449
450std::string
451env::do_make_absolute (const std::string& s,
452 const std::string& dot_path) const
453{
454 if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
455 return s;
456
457 // Optimization: every time Octave returns to the prompt it calls
458 // make_absolute_filename with '.' as argument.
459 if (s == ".")
460 return dot_path;
461
462 std::string current_dir = dot_path;
463
464 if (! sys::file_ops::is_dir_sep (current_dir.back ()))
465 current_dir.append (sys::file_ops::dir_sep_str ());
466
467 std::size_t i = 0;
468 std::size_t slen = s.length ();
469
470 while (i < slen)
471 {
472 if (s[i] == '.')
473 {
474 if (i + 1 == slen)
475 break;
476
477 if (sys::file_ops::is_dir_sep (s[i+1]))
478 {
479 i += 2;
480 continue;
481 }
482
483 if (s[i+1] == '.'
484 && (i + 2 == slen
485 || sys::file_ops::is_dir_sep (s[i+2])))
486 {
487 i += 2;
488 if (i != slen)
489 i++;
490
491 pathname_backup (current_dir, 1);
492
493 continue;
494 }
495 }
496
497 std::size_t sep_pos;
498 sep_pos = s.find_first_of (sys::file_ops::dir_sep_chars (), i);
499
500 if (sep_pos == std::string::npos)
501 {
502 current_dir.append (s, i, sep_pos-i);
503 break;
504 }
505 else if (sep_pos == i)
506 {
507 /* Two separators in a row, skip adding 2nd separator */
508 i++;
509 }
510 else
511 {
512 current_dir.append (s, i, sep_pos-i+1);
513 i = sep_pos + 1;
514 }
515 }
516
517 // Strip any trailing directory separator
518 if (sys::file_ops::is_dir_sep (current_dir.back ()))
519 current_dir.pop_back ();
520
521 return current_dir;
522}
523
524// Return a string which is the current working directory.
525
526std::string
527env::do_getcwd ()
528{
529 if (! m_follow_symbolic_links)
530 m_current_directory = "";
531
532 if (m_verbatim_pwd || m_current_directory.empty ())
533 m_current_directory = sys::getcwd ();
534
535 return m_current_directory;
536}
537
538// This value is not cached because it can change while Octave is
539// running.
540
541std::string
542env::do_get_home_directory ()
543{
544 std::string hd = do_getenv ("HOME");
545
546#if defined (__MINGW32__) || defined (_MSC_VER)
547 // Maybe we are started directly from cmd.exe.
548 if (hd.empty ())
549 {
550 std::string drv = do_getenv ("HOMEDRIVE");
551 if (drv.empty ())
552 hd = do_getenv ("HOMEPATH");
553 else
554 hd = drv + do_getenv ("HOMEPATH");
555 }
556#endif
557
558 if (hd.empty ())
559 {
560 sys::password pw = sys::password::getpwuid (sys::getuid ());
561
562 hd = (pw ? pw.dir () : std::string (sys::file_ops::dir_sep_str ()));
563 }
564
565 return hd;
566}
567
568std::string
569env::do_get_user_name ()
570{
571 if (m_user_name.empty ())
572 {
573 sys::password pw = sys::password::getpwuid (sys::getuid ());
574
575 m_user_name = (pw ? pw.name () : "unknown");
576 }
577
578 return m_user_name;
579}
580
581std::string
582env::do_get_host_name ()
583{
584 if (m_host_name.empty ())
585 {
586 char hostname[1024];
587
588 int status = octave_gethostname_wrapper (hostname, 1023);
589
590 m_host_name = (status < 0) ? "unknown" : hostname;
591 }
592
593 return m_host_name;
594}
595
596std::string
597env::do_getenv (const std::string& name) const
598{
599 return getenv_wrapper (name);
600}
601
602// Do the work of changing to the directory NEWDIR.
603// Handle symbolic link following, etc.
604
605bool
606env::do_chdir (const std::string& newdir)
607{
608 bool retval = false;
609
610 std::string tmp;
611
612 if (m_follow_symbolic_links)
613 {
614 if (m_current_directory.empty ())
615 do_getcwd ();
616
617 if (m_current_directory.empty ())
618 tmp = newdir;
619 else
620 tmp = do_make_absolute (newdir, m_current_directory);
621
622 // Get rid of trailing directory separator.
623 if (tmp.length () > 1 && sys::file_ops::is_dir_sep (tmp.back ()))
624 tmp.pop_back ();
625
626 if (! sys::chdir (tmp))
627 {
628 m_current_directory = tmp;
629 retval = true;
630 }
631 }
632 else
633 retval = (! sys::chdir (newdir));
634
635 return retval;
636}
637
638// Remove the last N directories from PATH.
639
640void
641env::pathname_backup (std::string& path, int n) const
642{
643 if (path.empty ())
644 return;
645
646 std::size_t i = path.length () - 1;
647
648 while (n--)
649 {
650 while (sys::file_ops::is_dir_sep (path[i]) && i > 0)
651 i--;
652
653#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
654 // Don't strip file letter part.
655 if (i == 1 && path[i] == ':')
656 {
657 // Keep path separator if present.
658 i = std::min (i+2, path.length ());
659 break;
660 }
661#endif
662
663 while (! sys::file_ops::is_dir_sep (path[i]) && i > 0)
664 i--;
665
666 i++;
667 }
668
669 path.resize (i);
670}
671
672void
673env::error (int err_num) const
674{
675 (*current_liboctave_error_handler) ("%s", std::strerror (err_num));
676}
677
678void
679env::error (const std::string& s) const
680{
681 (*current_liboctave_error_handler) ("%s", s.c_str ());
682}
683
684OCTAVE_END_NAMESPACE(sys)
685OCTAVE_END_NAMESPACE(octave)
Definition oct-env.h:38
static std::string base_pathname(const std::string &s)
Definition oct-env.cc:124
static std::string get_user_name()
Definition oct-env.cc:194
static std::string getenv(const std::string &name)
Definition oct-env.cc:296
static std::string get_home_directory()
Definition oct-env.cc:145
static bool absolute_pathname(const std::string &s)
Definition oct-env.cc:110
static bool have_x11_display()
Definition oct-env.cc:315
env()
Definition oct-env.cc:72
static std::string get_program_invocation_name()
Definition oct-env.cc:180
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:323
static std::string get_user_config_directory()
Definition oct-env.cc:159
static std::string make_absolute(const std::string &s, const std::string &dot_path=get_current_directory())
Definition oct-env.cc:131
static std::string get_temp_directory()
Definition oct-env.cc:152
static void putenv(const std::string &name, const std::string &value)
Definition oct-env.cc:309
static std::string get_current_directory()
Definition oct-env.cc:138
static std::string get_user_data_directory()
Definition oct-env.cc:166
static bool isenv(const std::string &name)
Definition oct-env.cc:303
static std::string polite_directory_format(const std::string &name)
Definition oct-env.cc:103
static std::string get_host_name()
Definition oct-env.cc:201
static std::string get_program_name()
Definition oct-env.cc:173
static void set_program_name(const std::string &s)
Definition oct-env.cc:187
static void add(fptr f)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::string data_dir()
Definition defaults.cc:192
std::string u8_from_wstring(const std::wstring &wchar_string)
Definition lo-sysdep.cc:746
std::string getenv_wrapper(const std::string &name)
Definition lo-sysdep.cc:685
bool isenv_wrapper(const std::string &name)
Definition lo-sysdep.cc:711
void putenv_wrapper(const std::string &name, const std::string &value)
Definition lo-sysdep.cc:649
const char * octave_set_program_name_wrapper(const char *pname)
int octave_gethostname_wrapper(char *nm, size_t len)
F77_RET_T len
Definition xerbla.cc:61