A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
environment-variable.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Lawrence Livermore National Laboratory
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
7 */
8
10
11#include "string.h"
12
13#include <cstdlib> // Global functions std::getenv, setenv, unsetenv
14#include <cstring> // strlen
15
16/**
17 * @file
18 * @ingroup core-environ
19 * Class EnvironmentVariable implementation.
20 */
21
22#ifdef __WIN32__
23#include <cerrno>
24
25/**
26 * Windows implementation of the POSIX function `setenv()`
27 *
28 * @param [in] var_name The environment variable to set.
29 * Must not be a null-pointer, and must not contain `=`.
30 * @param [in] new_value The new value to set \p var_name to.
31 * Must not by a null pointer or empty.
32 * @param [in] change_flag Must be non-zero to actually change the environment.
33 * @returns 0 if successful, -1 if failed.
34 */
35int
36setenv(const char* var_name, const char* new_value, int change_flag)
37{
38 std::string variable{var_name};
39 std::string value{new_value};
40
41 // In case arguments are null pointers, return invalid error
42 // Windows does not accept empty environment variables
43 if (variable.empty() || value.empty())
44 {
45 errno = EINVAL;
46 return -1;
47 }
48
49 // Posix does not accept '=', so impose that here
50 if (variable.find('=') != std::string::npos)
51 {
52 errno = EINVAL;
53 return -1;
54 }
55
56 // Change flag equals to zero preserves a pre-existing value
57 if (change_flag == 0)
58 {
59 char* old_value = std::getenv(var_name);
60 if (old_value != nullptr)
61 {
62 return 0;
63 }
64 }
65
66 // Write new value for the environment variable
67 return _putenv_s(var_name, new_value);
68}
69
70/**
71 * Windows implementation of the POSIX function `unsetenv()`
72 * @param [in] var_name The environment variable to unset and remove from the environment.
73 * @returns 0 if successful, -1 if failed.
74 */
75int
76unsetenv(const char* var_name)
77{
78 return _putenv_s(var_name, "");
79}
80
81#endif // __WIN32__
82
83namespace ns3
84{
85
86/**
87 * @ingroup core-environ
88 *
89 * @def NS_LOCAL_LOG(msg)
90 * File-local logging macro for environment-variable.cc
91 * Our usual Logging doesn't work here because these functions
92 * get called during static initialization of Logging itself.
93 * @param msg The message stream to log
94 *
95 * @def NS_LOCAL_ASSERT(cond, msg)
96 * File-local assert macro for environment-variable.cc
97 * Our usual assert doesn't work here because these functions
98 * get called during static initialization of Logging itself.
99 * @param cond The condition which is asserted to be \c true
100 * @param msg The message stream to log
101 */
102#if 0
103#define NS_LOCAL_LOG(msg) \
104 std::cerr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): " << msg << std::endl
105
106#define NS_LOCAL_ASSERT(cond, msg) \
107 do \
108 { \
109 if (!(cond)) \
110 { \
111 NS_LOCAL_LOG("assert failed. cond=\"" << #cond << "\", " << msg); \
112 } \
113 } while (false)
114
115#else
116#define NS_LOCAL_LOG(msg)
117#define NS_LOCAL_ASSERT(cond, msg)
118#endif
119
120/* static */
123{
124 static DictionaryList instance;
125 return instance;
126}
127
128/* static */
129void
131{
132 Instance().clear();
133}
134
135/* static */
136std::shared_ptr<EnvironmentVariable::Dictionary>
137EnvironmentVariable::GetDictionary(const std::string& envvar, const std::string& delim /* ";" */)
138{
139 NS_LOCAL_LOG(envvar << ", " << delim);
140 std::shared_ptr<Dictionary> dict;
141 auto loc = Instance().find(envvar);
142 if (loc != Instance().end())
143 {
144 NS_LOCAL_LOG("found envvar in cache");
145 dict = loc->second;
146 }
147 else
148 {
149 NS_LOCAL_LOG("envvar not in cache, checking environment");
150 dict = std::make_shared<Dictionary>(envvar, delim);
151 Instance().insert({envvar, dict});
152 }
153
154 return dict;
155}
156
157/* static */
159EnvironmentVariable::Get(const std::string& envvar,
160 const std::string& key /* "" */,
161 const std::string& delim /* ";" */)
162{
163 auto dict = GetDictionary(envvar, delim);
164 return dict->Get(key);
165}
166
167/* static */
168bool
169EnvironmentVariable::Set(const std::string& variable, const std::string& value)
170{
171 int fail = setenv(variable.c_str(), value.c_str(), 1);
172 return !fail;
173}
174
175/* static */
176bool
177EnvironmentVariable::Unset(const std::string& variable)
178{
179 int fail = unsetenv(variable.c_str());
180 return !fail;
181}
182
184EnvironmentVariable::Dictionary::Get(const std::string& key) const
185{
186 NS_LOCAL_LOG(key);
187
188 if (!m_exists)
189 {
190 return {false, ""};
191 }
192
193 if (key.empty())
194 {
195 // Empty key is request for entire value
196 return {true, m_variable};
197 }
198
199 auto loc = m_dict.find(key);
200 if (loc != m_dict.end())
201 {
202 NS_LOCAL_LOG("found key in dictionary");
203 NS_LOCAL_LOG("found: key '" << key << "', value: '" << loc->second << "'");
204 return {true, loc->second};
205 }
206
207 // key not found
208 return {false, ""};
209}
210
212 const std::string& delim /* "=" */)
213{
214 NS_LOCAL_LOG(envvar << ", " << delim);
215
216 const char* envCstr = std::getenv(envvar.c_str());
217 // Returns null pointer if envvar doesn't exist
218 if (!envCstr)
219 {
220 m_exists = false;
221 return;
222 }
223
224 // So it exists
225 m_exists = true;
226 m_variable = envCstr;
227 NS_LOCAL_LOG("found envvar in environment with value '" << m_variable << "'");
228
229 // ...but might be empty
230 if (m_variable.empty())
231 {
232 return;
233 }
234
235 StringVector keyvals = SplitString(m_variable, delim);
236 NS_LOCAL_ASSERT(keyvals.empty(), "Unexpected empty keyvals from non-empty m_variable");
237 for (const auto& keyval : keyvals)
238 {
239 if (keyval.empty())
240 {
241 continue;
242 }
243
244 std::size_t equals = keyval.find_first_of('=');
245 std::string key{keyval, 0, equals};
246 std::string value;
247 if (equals < keyval.size() - 1)
248 {
249 value = keyval.substr(equals + 1, keyval.size());
250 }
251 NS_LOCAL_LOG("found key '" << key << "' with value '" << value << "'");
252 m_dict.insert({key, value});
253 }
254}
255
261
262} // namespace ns3
Dictionary(const std::string &envvar, const std::string &delim=";")
Constructor.
KeyFoundType Get(const std::string &key="") const
Get the value corresponding to a key from this dictionary.
std::unordered_map< std::string, std::string > KeyValueStore
Key, value store type.
std::string m_variable
The raw environment variable.
bool m_exists
Whether the environment variable exists in the environment.
KeyValueStore m_dict
The key, value store.
KeyValueStore GetStore() const
Get the underlying store, for iterating.
static DictionaryList & Instance()
Access the DictionaryStore instance.
static KeyFoundType Get(const std::string &envvar, const std::string &key="", const std::string &delim=";")
Get the value corresponding to a key from an environment variable.
static bool Unset(const std::string &variable)
Unset an environment variable.
std::pair< bool, std::string > KeyFoundType
Result of a key lookup.
static void Clear()
Clear the instance, forcing all new lookups.
std::unordered_map< std::string, std::shared_ptr< Dictionary > > DictionaryList
How Dictionaries are stored.
static bool Set(const std::string &variable, const std::string &value)
Set an environment variable.
static std::shared_ptr< Dictionary > GetDictionary(const std::string &envvar, const std::string &delim=";")
Get the dictionary for a particular environment variable.
#define NS_LOCAL_ASSERT(cond, msg)
File-local assert macro for environment-variable.cc Our usual assert doesn't work here because these ...
Class Environment declaration.
#define NS_LOCAL_LOG(msg)
File-local logging macro for environment-variable.cc Our usual Logging doesn't work here because thes...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
StringVector SplitString(const std::string &str, const std::string &delim)
Split a string on a delimiter.
Definition string.cc:23
std::vector< std::string > StringVector
Return type of SplitString.
Definition string.h:26
value
Definition second.py:37
ns3::StringValue attribute value declarations.