Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_EnvVariables.cpp
1// @HEADER
2// *****************************************************************************
3// Teuchos: Common Tools Package
4//
5// Copyright 2004 NTESS and the Teuchos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#include "Teuchos_EnvVariables.hpp"
11
12#include <stddef.h>
13#include <string>
14
15#if !defined(_MSC_VER)
16#include <cerrno> // errno
17#endif
18
19#include <cstdlib> // std::free
20#include <cstring> // std::strchr, std::strerror
21#include <memory> // std::addressof
22#include <sstream>
23#include <map>
24#include <stdexcept>
25#include <string>
26#include <vector>
27
28#include "Teuchos_StrUtils.hpp"
30
31namespace Teuchos {
32
33namespace {
34
35bool environmentVariableNameIsValid(const char name[]) {
36 return name != nullptr && std::strchr(name, '=') == nullptr;
37}
38
39void throwEnvironmentVariablePlatformError(const char operation[],
40 const char name[],
41 const std::string& detail) {
42 std::ostringstream oss;
43 oss << "Teuchos environment variable " << operation << " failed";
44 if(name != nullptr) {
45 oss << " for \"" << name << "\"";
46 }
47 oss << ": " << detail;
48 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, oss.str());
49}
50
51// setenv/unsetenv are POSIX; MSVC CRT provides _putenv_s instead.
52// See setenv(3), unsetenv, _putenv_s, and _dupenv_s documentation linked from
53// Teuchos_EnvVariables.hpp.
54// Other Windows toolchains (e.g. MinGW) may still expose setenv/unsetenv.
55#if defined(_MSC_VER)
56void setEnvironmentVariableImpl(const char* name, const char* value, int overwrite) {
57 if(!environmentVariableNameIsValid(name) || value == nullptr) {
58 return;
59 }
60 if(overwrite == 0) {
61 char* buf{};
62 size_t bufSize{};
63 const errno_t dupStatus = _dupenv_s(std::addressof(buf), std::addressof(bufSize), name);
64 if(dupStatus != 0) {
65 std::ostringstream oss;
66 oss << "_dupenv_s returned " << dupStatus;
67 throwEnvironmentVariablePlatformError("set", name, oss.str());
68 }
69 if(buf != nullptr) {
70 std::free(buf);
71 return;
72 }
73 }
74 const errno_t putStatus = _putenv_s(name, value);
75 if(putStatus != 0) {
76 std::ostringstream oss;
77 oss << "_putenv_s returned " << putStatus;
78 throwEnvironmentVariablePlatformError("set", name, oss.str());
79 }
80}
81
82void unsetEnvironmentVariableImpl(const char* name) {
83 if(!environmentVariableNameIsValid(name)) {
84 return;
85 }
86 const errno_t putStatus = _putenv_s(name, "");
87 if(putStatus != 0) {
88 std::ostringstream oss;
89 oss << "_putenv_s returned " << putStatus;
90 throwEnvironmentVariablePlatformError("unset", name, oss.str());
91 }
92}
93#else // !defined(_MSC_VER)
94void setEnvironmentVariableImpl(const char* name, const char* value, int overwrite) {
95 if(!environmentVariableNameIsValid(name) || value == nullptr) {
96 return;
97 }
98 if(setenv(name, value, overwrite) != 0) {
99 const int err = errno;
100 std::ostringstream oss;
101 oss << "setenv returned -1, errno=" << err;
102 if(err != 0) {
103 oss << " (" << std::strerror(err) << ")";
104 }
105 throwEnvironmentVariablePlatformError("set", name, oss.str());
106 }
107}
108
109void unsetEnvironmentVariableImpl(const char* name) {
110 if(!environmentVariableNameIsValid(name)) {
111 return;
112 }
113 if(unsetenv(name) != 0) {
114 const int err = errno;
115 std::ostringstream oss;
116 oss << "unsetenv returned -1, errno=" << err;
117 if(err != 0) {
118 oss << " (" << std::strerror(err) << ")";
119 }
120 throwEnvironmentVariablePlatformError("unset", name, oss.str());
121 }
122}
123#endif
124
125#if defined(_MSC_VER)
126const char* getEnvironmentVariableValueImpl(const char* name) {
127 char* buf{};
128 size_t bufSize{};
129 const errno_t dupStatus = _dupenv_s(std::addressof(buf), std::addressof(bufSize), name);
130 if(dupStatus != 0) {
131 std::ostringstream oss;
132 oss << "_dupenv_s returned " << dupStatus;
133 throwEnvironmentVariablePlatformError("get", name, oss.str());
134 }
135 if(buf == nullptr) {
136 return nullptr;
137 }
138 thread_local std::string valueStorage;
139 valueStorage.assign(buf);
140 std::free(buf);
141 return valueStorage.c_str();
142}
143#else // !defined(_MSC_VER)
144const char* getEnvironmentVariableValueImpl(const char* name) {
145 // C++11 and later: concurrent std::getenv calls do not data-race only while
146 // the process environment is unchanged. setenv/unsetenv/putenv (including
147 // Teuchos set/unset helpers) require external synchronization with reads.
148 // The returned pointer is owned by the C runtime; copy to std::string if the
149 // value must outlive this call or any later environment access.
150 return std::getenv(name);
151}
152#endif
153
154} // namespace
155
156const char* getEnvironmentVariableValue(const char name[]) {
158 return nullptr;
159 }
161}
162
163namespace {
164
165const char* getEnvironmentVariableValueFromView(std::string_view environmentVariableName) {
166 const std::string nameString(environmentVariableName);
167 return getEnvironmentVariableValue(nameString.c_str());
168}
169
170} // namespace
171
172void setEnvironmentVariable(const char name[], const char value[], int overwrite) {
174}
175
177
178namespace {
179
180enum EnvironmentVariableState {
181 EnvironmentVariableIsSet_ON,
182 EnvironmentVariableIsSet_OFF,
183 EnvironmentVariableIsSet,
184 EnvironmentVariableIsNotSet
185};
186
187EnvironmentVariableState
188environmentVariableState(const std::string &environmentVariableValue) {
189 std::string v = StrUtils::allCaps(environmentVariableValue);
190 if (v == "1" || v == "YES" || v == "TRUE" || v == "ON")
191 // Environment variable is "ON"
192 return EnvironmentVariableIsSet_ON;
193 else if (v == "0" || v == "NO" || v == "FALSE" || v == "OFF")
194 // Environment variable is "OFF"
195 return EnvironmentVariableIsSet_OFF;
196 // Environment has some other non-boolean value
197 return EnvironmentVariableIsSet;
198}
199
200void setEnvironmentVariableMap(
201 const char environmentVariableName[],
202 std::map<std::string, std::map<std::string, bool>> &valsMap,
203 const bool defaultValue) {
204 using std::map;
205 using std::string;
206 using std::vector;
207
208 // Set the default value for this variable
209 valsMap[environmentVariableName] =
210 map<string, bool>{{"DEFAULT", defaultValue}};
211
212 const char *varVal = getEnvironmentVariableValue(environmentVariableName);
213 if (varVal == nullptr) {
214 // Environment variable is not set, use the default value for any named
215 // variants
216 return;
217 }
218
219 // Variable is not empty.
220 const string varStr(varVal);
221 // vector<string> names;
222 // split(varStr, [&](const string &x) { names.push_back(x); });
223 auto names = StrUtils::splitString(varStr, ',');
224 for (auto const &name : names) {
225 auto state = environmentVariableState(name);
226 if (state == EnvironmentVariableIsSet_ON) {
227 // Environment variable was set as ENVAR_NAME=[1,YES,TRUE,ON]
228 // Global value takes precedence
229 valsMap[environmentVariableName]["DEFAULT"] = true;
230 } else if (state == EnvironmentVariableIsSet_OFF) {
231 // Environment variable was set as ENVAR_NAME=[0,NO,FALSE,OFF]
232 // Global value takes precedence
233 valsMap[environmentVariableName]["DEFAULT"] = false;
234 } else {
235 // Environment variable was set as ENVAR_NAME=...:name:...
236 // So we set the mapping true for this named variant
237 valsMap[environmentVariableName][name] = true;
238 }
239 }
240 return;
241}
242} // namespace
243
244template <typename T>
245T getEnvironmentVariable(std::string_view environmentVariableName,
246 const T defaultValue) {
247 const char* varVal = getEnvironmentVariableValueFromView(environmentVariableName);
248 if (varVal == nullptr) {
249 return defaultValue;
250 } else {
251 std::stringstream ss(varVal);
252 T parsed;
253 ss >> parsed;
254
256 !ss, std::out_of_range,
257 "Environment variable \""
258 << environmentVariableName << "\" has a value " << varVal
259 << " that cannot be parsed as a " << typeid(T).name() << ".");
260
261 return parsed;
262 }
263}
264
265// full specialization of bool to preserve historical parsing behavior
266template <>
267bool getEnvironmentVariable<bool>(
268 std::string_view environmentVariableName, const bool defaultValue) {
269 const char* varVal = getEnvironmentVariableValueFromView(environmentVariableName);
270 bool retVal = defaultValue;
271 if (varVal != nullptr) {
272 auto state = environmentVariableState(std::string(varVal));
273 if (state == EnvironmentVariableIsSet_ON)
274 retVal = true;
275 else if (state == EnvironmentVariableIsSet_OFF)
276 retVal = false;
277 }
278 return retVal;
279}
280
286template <>
287size_t
289 const size_t defaultValue) {
291 if (varVal == nullptr) {
292 return defaultValue;
293 } else {
294 long long val = std::stoll(StrUtils::allCaps(varVal));
295 if (val < static_cast<long long>(0)) {
296 // If negative - user has requested threshold be lifted
297 return std::numeric_limits<size_t>::max();
298 }
299 if (sizeof(long long) > sizeof(size_t)) {
300 // It's hard to test this code, but I want to try writing it
301 // at least, in case we ever have to run on 32-bit machines or
302 // machines with sizeof(long long)=16 and sizeof(size_t)=8.
303 constexpr long long maxSizeT =
304 static_cast<long long>(std::numeric_limits<size_t>::max());
306 val > maxSizeT, std::out_of_range,
307 "Environment variable \""
308 << environmentVariableName << "\" has a value " << val
309 << " larger than the largest size_t value " << maxSizeT << ".");
310 }
311 return static_cast<size_t>(val);
312 }
313}
314
315bool idempotentlyGetNamedEnvironmentVariableAsBool(
316 const char name[], bool &initialized, const char environmentVariableName[],
317 const bool defaultValue) {
318 static std::map<std::string, std::map<std::string, bool>> namedVariableMap_;
319 if (!initialized) {
320 setEnvironmentVariableMap(environmentVariableName, namedVariableMap_,
321 defaultValue);
322 initialized = true;
323 }
324 auto thisEnvironmentVariableMap = namedVariableMap_[environmentVariableName];
325 auto thisEnvironmentVariable = thisEnvironmentVariableMap.find(name);
326 if (thisEnvironmentVariable != thisEnvironmentVariableMap.end())
327 return thisEnvironmentVariable->second;
328 return thisEnvironmentVariableMap["DEFAULT"];
329}
330
331template <typename T>
333 T &value, bool &initialized, std::string_view environmentVariableName,
334 const T defaultValue) {
335 if (!initialized) {
337 initialized = true;
338 }
339 return value;
340}
341
342
343template std::string getEnvironmentVariable<std::string>(std::string_view, const std::string);
344
345template std::string idempotentlyGetEnvironmentVariable<std::string>(std::string&, bool&, std::string_view, const std::string);
346template int idempotentlyGetEnvironmentVariable<int>(int&, bool&, std::string_view, const int);
347template unsigned long idempotentlyGetEnvironmentVariable<unsigned long>(unsigned long&, bool&, std::string_view, const unsigned long);
348template bool idempotentlyGetEnvironmentVariable<bool>(bool&, bool&, std::string_view, const bool);
349template unsigned long long idempotentlyGetEnvironmentVariable<unsigned long long>(unsigned long long&, bool&, std::string_view, const unsigned long long);
350
351} // namespace Teuchos
A std::string utilities class for Teuchos.
Standard test and throw macros.
Smart reference counting pointer class for automatic garbage collection.
static std::string allCaps(const std::string &str)
Converts a std::string to all upper case.
static Array< std::string > splitString(const std::string_view s, const char sep=',')
Split an input std::string using a seperator char sep.
This class creates a basic std::map object for platforms where the std::map is deficient,...
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
void unsetEnvironmentVariable(const char name[])
Remove a process environment variable.
T idempotentlyGetEnvironmentVariable(T &value, bool &initialized, std::string_view environmentVariableName, const T defaultValue)
Read a variable from the environment. Example usage:
size_t getEnvironmentVariable< size_t >(std::string_view environmentVariableName, const size_t defaultValue)
const char * getEnvironmentVariableValue(const char name[])
Read a process environment variable by name.
void setEnvironmentVariable(const char name[], const char value[], int overwrite)
Set a process environment variable.