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