GNU Octave 7.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-2022 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
68namespace octave
69{
70 namespace sys
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.
82
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
104 {
105 return (instance_ok ())
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;
211
212#if defined (__MINGW32__) || defined (_MSC_VER)
213
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 tempd = do_getenv ("TMP");
232
233#if defined (P_tmpdir)
234 if (tempd.empty ())
235 tempd = P_tmpdir;
236#else
237 if (tempd.empty ())
238 tempd = "/tmp";
239#endif
240
241#endif
242
243 return tempd;
244 }
245
246 std::string
248 {
249 std::string cfg_dir;
250
251#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
252 wchar_t path[MAX_PATH+1];
253 if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
254 nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
255 cfg_dir = u8_from_wstring (path);
256#else
257 cfg_dir = do_getenv ("XDG_CONFIG_HOME");
258#endif
259
260 if (cfg_dir.empty ())
262 + ".config";
263
264 return cfg_dir;
265 }
266
267 std::string
269 {
270 std::string data_dir;
271
272#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
273 wchar_t path[MAX_PATH+1];
274 if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
275 nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
277#else
278 data_dir = do_getenv ("XDG_DATA_HOME");
279#endif
280
281 if (data_dir.empty ())
283 + ".local" + sys::file_ops::dir_sep_str () + "share";
284
285 return data_dir;
286 }
287
288
289 // FIXME: this leaves no way to distinguish between a
290 // variable that is not set and one that is set to the empty string.
291 // Is this a problem?
292
293 std::string
294 env::getenv (const std::string& name)
295 {
296 return (instance_ok ())
297 ? m_instance->do_getenv (name) : "";
298 }
299
300 void
301 env::putenv (const std::string& name, const std::string& value)
302 {
303 putenv_wrapper (name, value);
304 }
305
306 bool
308 {
309 std::string display = getenv ("DISPLAY");
310
311 return ! display.empty ();
312 }
313
314 bool
315 env::chdir (const std::string& newdir)
316 {
317 return (instance_ok ())
318 ? m_instance->do_chdir (newdir) : false;
319 }
320
321 void
322 env::do_set_program_name (const std::string& s)
323 {
324 static bool initialized = false;
325
326 if (! initialized)
327 {
328 // octave_set_program_name_wrapper returns a cleaned up
329 // version of the program name (stripping libtool's "lt-"
330 // prefix, for example).
331
332 // The string passed to gnulib's ::set_program_name function must
333 // exist for the duration of the program so allocate a copy here
334 // instead of passing S.c_str () which only exists as long as the
335 // string object S.
336
339
340 std::size_t pos
342
343 // Also keep a shortened version of the program name.
344 m_prog_name = (pos == std::string::npos
346 : m_prog_invocation_name.substr (pos+1));
347
348 initialized = true;
349 }
350 }
351
352 // Return a pretty pathname. If the first part of the pathname is the
353 // same as $HOME, then replace that with '~'.
354
355 std::string
357 {
358 std::string retval;
359
360 std::string home_dir = do_get_home_directory ();
361
362 std::size_t len = home_dir.length ();
363
364 if (len > 1 && home_dir == name.substr (0, len)
365 && (name.length () == len || sys::file_ops::is_dir_sep (name[len])))
366 {
367 retval = "~";
368 retval.append (name.substr (len));
369 }
370 else
371 retval = name;
372
373 return retval;
374 }
375
376 bool
377 env::do_absolute_pathname (const std::string& s) const
378 {
379 std::size_t len = s.length ();
380
381 if (len == 0)
382 return false;
383
384 if (sys::file_ops::is_dir_sep (s[0]))
385 return true;
386
387#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
388 if ((len == 2 && isalpha (s[0]) && s[1] == ':')
389 || (len > 2 && isalpha (s[0]) && s[1] == ':'
390 && sys::file_ops::is_dir_sep (s[2])))
391 return true;
392#endif
393
394 return false;
395 }
396
397 bool
398 env::do_rooted_relative_pathname (const std::string& s) const
399 {
400 std::size_t len = s.length ();
401
402 if (len == 0)
403 return false;
404
405 if (len == 1 && s[0] == '.')
406 return true;
407
408 if (len > 1 && s[0] == '.' && sys::file_ops::is_dir_sep (s[1]))
409 return true;
410
411 if (len == 2 && s[0] == '.' && s[1] == '.')
412 return true;
413
414 if (len > 2 && s[0] == '.' && s[1] == '.'
416 return true;
417
418 return false;
419 }
420
421 // Return the 'basename' of the pathname in STRING (the stuff after
422 // the last directory separator). If STRING is not a full pathname,
423 // simply return it.
424
425 std::string
426 env::do_base_pathname (const std::string& s) const
427 {
429 return s;
430
431 std::size_t pos = s.find_last_of (sys::file_ops::dir_sep_chars ());
432
433 if (pos == std::string::npos)
434 return s;
435 else
436 return s.substr (pos+1);
437 }
438
439 // Turn STRING (a pathname) into an absolute pathname, assuming that
440 // DOT_PATH contains the symbolic location of the current directory.
441
442 std::string
443 env::do_make_absolute (const std::string& s,
444 const std::string& dot_path) const
445 {
446 if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
447 return s;
448
449 // Optimization: every time Octave returns to the prompt it calls
450 // make_absolute_filename with '.' as argument.
451 if (s == ".")
452 return dot_path;
453
454 std::string current_dir = dot_path;
455
456 if (! sys::file_ops::is_dir_sep (current_dir.back ()))
457 current_dir.append (sys::file_ops::dir_sep_str ());
458
459 std::size_t i = 0;
460 std::size_t slen = s.length ();
461
462 while (i < slen)
463 {
464 if (s[i] == '.')
465 {
466 if (i + 1 == slen)
467 break;
468
469 if (sys::file_ops::is_dir_sep (s[i+1]))
470 {
471 i += 2;
472 continue;
473 }
474
475 if (s[i+1] == '.'
476 && (i + 2 == slen
477 || sys::file_ops::is_dir_sep (s[i+2])))
478 {
479 i += 2;
480 if (i != slen)
481 i++;
482
483 pathname_backup (current_dir, 1);
484
485 continue;
486 }
487 }
488
489 std::size_t sep_pos;
490 sep_pos = s.find_first_of (sys::file_ops::dir_sep_chars (), i);
491
492 if (sep_pos == std::string::npos)
493 {
494 current_dir.append (s, i, sep_pos-i);
495 break;
496 }
497 else if (sep_pos == i)
498 {
499 /* Two separators in a row, skip adding 2nd separator */
500 i++;
501 }
502 else
503 {
504 current_dir.append (s, i, sep_pos-i+1);
505 i = sep_pos + 1;
506 }
507 }
508
509 // Strip any trailing directory separator
510 if (sys::file_ops::is_dir_sep (current_dir.back ()))
511 current_dir.pop_back ();
512
513 return current_dir;
514 }
515
516 // Return a string which is the current working directory.
517
518 std::string
520 {
523
524 if (m_verbatim_pwd || m_current_directory.empty ())
526
527 return m_current_directory;
528 }
529
530 // This value is not cached because it can change while Octave is
531 // running.
532
533 std::string
535 {
536 std::string hd = do_getenv ("HOME");
537
538#if defined (__MINGW32__) || defined (_MSC_VER)
539 // Maybe we are started directly from cmd.exe.
540 if (hd.empty ())
541 {
542 std::string drv = do_getenv ("HOMEDRIVE");
543 if (drv.empty ())
544 hd = do_getenv ("HOMEPATH");
545 else
546 hd = drv + do_getenv ("HOMEPATH");
547 }
548#endif
549
550 if (hd.empty ())
551 {
553
554 hd = (pw ? pw.dir () : std::string (sys::file_ops::dir_sep_str ()));
555 }
556
557 return hd;
558 }
559
560 std::string
562 {
563 if (m_user_name.empty ())
564 {
566
567 m_user_name = (pw ? pw.name () : "unknown");
568 }
569
570 return m_user_name;
571 }
572
573 std::string
575 {
576 if (m_host_name.empty ())
577 {
578 char hostname[1024];
579
580 int status = octave_gethostname_wrapper (hostname, 1023);
581
582 m_host_name = (status < 0) ? "unknown" : hostname;
583 }
584
585 return m_host_name;
586 }
587
588 std::string
589 env::do_getenv (const std::string& name) const
590 {
591 return getenv_wrapper (name);
592 }
593
594 // Do the work of changing to the directory NEWDIR.
595 // Handle symbolic link following, etc.
596
597 bool
598 env::do_chdir (const std::string& newdir)
599 {
600 bool retval = false;
601
602 std::string tmp;
603
605 {
606 if (m_current_directory.empty ())
607 do_getcwd ();
608
609 if (m_current_directory.empty ())
610 tmp = newdir;
611 else
613
614 // Get rid of trailing directory separator.
615 if (tmp.length () > 1 && sys::file_ops::is_dir_sep (tmp.back ()))
616 tmp.pop_back ();
617
618 if (! sys::chdir (tmp))
619 {
621 retval = true;
622 }
623 }
624 else
625 retval = (! sys::chdir (newdir));
626
627 return retval;
628 }
629
630 // Remove the last N directories from PATH.
631
632 void
633 env::pathname_backup (std::string& path, int n) const
634 {
635 if (path.empty ())
636 return;
637
638 std::size_t i = path.length () - 1;
639
640 while (n--)
641 {
642 while (sys::file_ops::is_dir_sep (path[i]) && i > 0)
643 i--;
644
645#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
646 // Don't strip file letter part.
647 if (i == 1 && path[i] == ':')
648 {
649 // Keep path separator if present.
650 i = std::min (i+2, path.length ());
651 break;
652 }
653#endif
654
655 while (! sys::file_ops::is_dir_sep (path[i]) && i > 0)
656 i--;
657
658 i++;
659 }
660
661 path.resize (i);
662 }
663
664 void
665 env::error (int err_num) const
666 {
667 (*current_liboctave_error_handler) ("%s", std::strerror (err_num));
668 }
669
670 void
671 env::error (const std::string& s) const
672 {
673 (*current_liboctave_error_handler) ("%s", s.c_str ());
674 }
675 }
676}
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
static std::string get_temp_directory(void)
Definition: oct-env.cc:152
bool m_verbatim_pwd
Definition: oct-env.h:148
static std::string get_host_name(void)
Definition: oct-env.cc:201
static bool rooted_relative_pathname(const std::string &s)
Definition: oct-env.cc:117
std::string do_get_temp_directory(void) const
Definition: oct-env.cc:208
static bool have_x11_display(void)
Definition: oct-env.cc:307
static std::string base_pathname(const std::string &s)
Definition: oct-env.cc:124
bool do_rooted_relative_pathname(const std::string &s) const
Definition: oct-env.cc:398
std::string m_current_directory
Definition: oct-env.h:151
static std::string get_user_data_directory(void)
Definition: oct-env.cc:166
std::string do_base_pathname(const std::string &s) const
Definition: oct-env.cc:426
static std::string get_program_invocation_name(void)
Definition: oct-env.cc:180
void do_set_program_name(const std::string &s)
Definition: oct-env.cc:322
std::string do_get_home_directory(void)
Definition: oct-env.cc:534
static void cleanup_instance(void)
Definition: oct-env.h:139
std::string m_prog_invocation_name
Definition: oct-env.h:156
std::string do_get_host_name(void)
Definition: oct-env.cc:574
static std::string getenv(const std::string &name)
Definition: oct-env.cc:294
static bool instance_ok(void)
Definition: oct-env.cc:89
static void set_program_name(const std::string &s)
Definition: oct-env.cc:187
static std::string get_home_directory(void)
Definition: oct-env.cc:145
std::string do_get_user_config_directory(void)
Definition: oct-env.cc:247
bool m_follow_symbolic_links
Definition: oct-env.h:144
std::string do_get_user_data_directory(void)
Definition: oct-env.cc:268
std::string do_make_absolute(const std::string &s, const std::string &dot_path) const
Definition: oct-env.cc:443
static std::string polite_directory_format(const std::string &name)
Definition: oct-env.cc:103
std::string do_polite_directory_format(const std::string &name)
Definition: oct-env.cc:356
std::string m_prog_name
Definition: oct-env.h:154
static void putenv(const std::string &name, const std::string &value)
Definition: oct-env.cc:301
static bool absolute_pathname(const std::string &s)
Definition: oct-env.cc:110
std::string m_host_name
Definition: oct-env.h:160
std::string do_get_user_name(void)
Definition: oct-env.cc:561
static std::string get_user_config_directory(void)
Definition: oct-env.cc:159
bool do_chdir(const std::string &newdir)
Definition: oct-env.cc:598
std::string do_getcwd(void)
Definition: oct-env.cc:519
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_program_name(void)
Definition: oct-env.cc:173
static std::string get_current_directory(void)
Definition: oct-env.cc:138
void error(int) const
Definition: oct-env.cc:665
static bool chdir(const std::string &newdir)
Definition: oct-env.cc:315
static env * m_instance
Definition: oct-env.h:137
bool do_absolute_pathname(const std::string &s) const
Definition: oct-env.cc:377
std::string m_user_name
Definition: oct-env.h:158
std::string do_getenv(const std::string &name) const
Definition: oct-env.cc:589
static std::string get_user_name(void)
Definition: oct-env.cc:194
void pathname_backup(std::string &path, int n) const
Definition: oct-env.cc:633
static password getpwuid(uid_t uid)
std::string dir(void) const
Definition: oct-password.cc:99
std::string name(void) const
Definition: oct-password.cc:54
static void add(fptr f)
QString path
QString name
std::string data_dir(void)
Definition: defaults.cc:179
std::string dir_sep_chars(void)
Definition: file-ops.cc:247
std::string dir_sep_str(void)
Definition: file-ops.cc:238
bool is_dir_sep(char c)
Definition: file-ops.cc:275
std::string getcwd(void)
Definition: lo-sysdep.cc:71
std::string u8_from_wstring(const std::wstring &wchar_string)
Definition: lo-sysdep.cc:513
uid_t getuid(void)
std::string getenv_wrapper(const std::string &name)
Definition: lo-sysdep.cc:464
void putenv_wrapper(const std::string &name, const std::string &value)
Definition: lo-sysdep.cc:428
int chdir(const std::string &path_arg)
Definition: lo-sysdep.cc:106
char * strsave(const char *s)
Definition: lo-utils.cc:74
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