diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2018-06-14 18:13:04 +0200 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2018-06-15 14:21:58 +0300 |
commit | 481f9ba1aee62fea092184f2243d210a8686781f (patch) | |
tree | a54fc536d835c5277038e145fabc1255c42ff8ac /libbutl | |
parent | 5d424ea127333859a32addaf9e28eae07a4dc9f6 (diff) |
Add portable environment variable manipulation functions
Diffstat (limited to 'libbutl')
-rw-r--r-- | libbutl/path.cxx | 33 | ||||
-rw-r--r-- | libbutl/process.cxx | 41 | ||||
-rw-r--r-- | libbutl/utility.cxx | 32 | ||||
-rw-r--r-- | libbutl/utility.ixx | 13 | ||||
-rw-r--r-- | libbutl/utility.mxx | 22 |
5 files changed, 110 insertions, 31 deletions
diff --git a/libbutl/path.cxx b/libbutl/path.cxx index 11a34c9..47d691b 100644 --- a/libbutl/path.cxx +++ b/libbutl/path.cxx @@ -17,7 +17,7 @@ #else # include <pwd.h> // struct passwd, getpwuid_r() # include <errno.h> // EINVAL -# include <stdlib.h> // realpath(), getenv() +# include <stdlib.h> // realpath() # include <limits.h> // PATH_MAX # include <unistd.h> // getcwd(), chdir() # include <string.h> // strlen(), strcpy() @@ -29,6 +29,7 @@ #ifndef __cpp_lib_modules #include <string> +#include <vector> #include <cstddef> #include <utility> @@ -123,33 +124,39 @@ namespace butl } #ifndef _WIN32 - static const char* + static const vector<string> tmp_vars ({"TMPDIR", "TMP", "TEMP", "TEMPDIR"}); + + static string temp_directory () { - const char* dir (nullptr); - const char* env[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; + optional<string> dir; - for (auto e (env); dir == nullptr && *e != nullptr; ++e) - dir = getenv (*e); + for (const string& v: tmp_vars) + { + dir = getenv (v); + + if (dir) + break; + } - if (dir == nullptr) + if (!dir) dir = "/tmp"; struct stat s; - if (stat (dir, &s) != 0) + if (stat (dir->c_str (), &s) != 0) throw_generic_error (errno); if (!S_ISDIR (s.st_mode)) throw_generic_error (ENOTDIR); - return dir; + return *dir; } static string home () { - if (const char* h = getenv ("HOME")) - return h; + if (optional<string> h = getenv ("HOME")) + return *h; // Struct passwd has 5 members that will use this buffer. Two are the // home directory and shell paths. The other three are the user login @@ -214,8 +221,8 @@ namespace butl #else // Could be set by, e.g., MSYS and Cygwin shells. // - if (const char* h = getenv ("HOME")) - return h; + if (optional<string> h = getenv ("HOME")) + return *h; char h[_MAX_PATH]; HRESULT r (SHGetFolderPathA (NULL, CSIDL_PROFILE, NULL, 0, h)); diff --git a/libbutl/process.cxx b/libbutl/process.cxx index 41e2c0d..384af29 100644 --- a/libbutl/process.cxx +++ b/libbutl/process.cxx @@ -9,7 +9,6 @@ #include <errno.h> #ifndef _WIN32 -# include <stdlib.h> // setenv(), unsetenv() # include <signal.h> // SIG* # include <unistd.h> // execvp, fork, dup2, pipe, chdir, *_FILENO, getpid # include <sys/wait.h> // waitpid @@ -60,7 +59,7 @@ #include <map> #include <ratio> // milli #include <chrono> -#include <cstdlib> // getenv(), __argv[] +#include <cstdlib> // __argv[] #include <algorithm> // find() #endif #endif @@ -83,7 +82,6 @@ import std.io; import std.threading; // Clang wants it in purview (see process-details.hxx). #endif import butl.path; -import butl.optional; import butl.fdstream; import butl.vector_view; import butl.small_vector; @@ -273,7 +271,8 @@ namespace butl // 2. We do not continue searching on EACCES from execve(). // 3. We do not execute via default shell on ENOEXEC from execve(). // - for (const char* b (getenv ("PATH")), *e; + optional<string> p (getenv ("PATH")); + for (const char* b (p ? p->c_str () : nullptr), *e; b != nullptr; b = (e != nullptr ? e + 1 : e)) { @@ -460,12 +459,17 @@ namespace butl { const char* v (strchr (ev, '=')); - int r (v != nullptr - ? setenv (string (ev, v - ev).c_str (), v + 1, 1) - : unsetenv (ev)); - - if (r == -1) - fail (true); + try + { + if (v != nullptr) + setenv (string (ev, v - ev), v + 1); + else + unsetenv (ev); + } + catch (const system_error& e) + { + throw process_child_error (e.code ().value ()); + } } } @@ -845,7 +849,8 @@ namespace butl // Now search in PATH. Recall is unchanged. // - for (const char* b (getenv ("PATH")), *e; + optional<string> p (getenv ("PATH")); + for (const char* b (p ? p->c_str () : nullptr), *e; b != nullptr; b = (e != nullptr ? e + 1 : e)) { @@ -1126,7 +1131,7 @@ namespace butl // cmd.exe and passing the batch file as an argument (see CreateProcess() // for deails). // - const char* batch (nullptr); + optional<string> batch; { const char* p (pp.effect_string ()); const char* e (path::traits::find_extension (p, strlen (p))); @@ -1135,7 +1140,7 @@ namespace butl { batch = getenv ("COMSPEC"); - if (batch == nullptr) + if (!batch) batch = "C:\\Windows\\System32\\cmd.exe"; } } @@ -1240,14 +1245,14 @@ namespace butl cmd_line += '"'; }; - if (batch != nullptr) + if (batch) { - append (batch); + append (*batch); append ("/c"); append (pp.effect_string ()); } - for (const char* const* p (args + (batch != nullptr ? 1 : 0)); + for (const char* const* p (args + (batch ? 1 : 0)); *p != 0; ++p) append (*p); @@ -1463,7 +1468,7 @@ namespace butl }; bool msys (false); - if (batch == nullptr) + if (!batch) { string p (pp.effect_string ()); auto i (detect_msys_cache_.find (p)); @@ -1482,7 +1487,7 @@ namespace butl for (system_clock::duration timeout (1h);;) // Try for about 1 hour. { if (!CreateProcess ( - batch != nullptr ? batch : pp.effect_string (), + batch ? batch->c_str () : pp.effect_string (), const_cast<char*> (cmd_line.c_str ()), 0, // Process security attributes. 0, // Primary thread security attributes. diff --git a/libbutl/utility.cxx b/libbutl/utility.cxx index 8e2422aa..502586c 100644 --- a/libbutl/utility.cxx +++ b/libbutl/utility.cxx @@ -10,6 +10,8 @@ #include <libbutl/win32-utility.hxx> #endif +#include <stdlib.h> // setenv(), unsetenv(), _putenv() + #ifndef __cpp_lib_modules #include <string> #include <cstddef> @@ -124,6 +126,36 @@ namespace butl return l; } + + void + setenv (const string& name, const string& value) + { +#ifndef _WIN32 + if (::setenv (name.c_str (), value.c_str (), 1 /* overwrite */) == -1) + throw_generic_error (errno); +#else + // The documentation doesn't say how to obtain the failure reason, so we + // will assume it to always be EINVAL (as the most probable one). + // + if (_putenv (string (name + '=' + value).c_str ()) == -1) + throw_generic_error (EINVAL); +#endif + } + + void + unsetenv (const string& name) + { +#ifndef _WIN32 + if (::unsetenv (name.c_str ()) == -1) + throw_generic_error (errno); +#else + // The documentation doesn't say how to obtain the failure reason, so we + // will assume it to always be EINVAL (as the most probable one). + // + if (_putenv (string (name + '=').c_str ()) == -1) + throw_generic_error (EINVAL); +#endif + } } namespace std diff --git a/libbutl/utility.ixx b/libbutl/utility.ixx index d4aaa65..565a694 100644 --- a/libbutl/utility.ixx +++ b/libbutl/utility.ixx @@ -2,6 +2,10 @@ // copyright : Copyright (c) 2014-2018 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#ifndef __cpp_lib_modules +#include <cstdlib> // getenv() +#endif + namespace butl { inline char @@ -199,4 +203,13 @@ namespace butl throw std::istream::failure (""); } + + inline optional<std::string> + getenv (const std::string& name) + { + if (const char* r = std::getenv (name.c_str ())) + return std::string (r); + + return nullopt; + } } diff --git a/libbutl/utility.mxx b/libbutl/utility.mxx index 740b411..252a4b4 100644 --- a/libbutl/utility.mxx +++ b/libbutl/utility.mxx @@ -35,6 +35,9 @@ export module butl.utility; import std.core; import std.io; #endif +import butl.optional; +#else +#include <libbutl/optional.mxx> #endif #include <libbutl/export.hxx> @@ -183,6 +186,25 @@ LIBBUTL_MODEXPORT namespace butl bool eof (std::istream&); + // Environment variables. + // + optional<std::string> + getenv (const std::string&); + + // Throw system_error on failure. + // + // Note that on Windows setting an empty value usets the variable. + // + LIBBUTL_SYMEXPORT + void + setenv (const std::string& name, const std::string& value); + + // Throw system_error on failure. + // + LIBBUTL_SYMEXPORT + void + unsetenv (const std::string&); + // Key comparators (i.e., to be used in sets, maps, etc). // struct compare_c_string |