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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
18 */
19
21
22#include "string.h"
23
24#include <cstdlib> // std::getenv
25#include <cstring> // strlen
26#include <iostream> // clog
27#include <stdlib.h> // Global functions setenv, unsetenv
28
35#ifdef __WIN32__
36#include <cerrno>
37
48int
49setenv(const char* var_name, const char* new_value, int change_flag)
50{
51 std::string variable{var_name};
52 std::string value{new_value};
53
54 // In case arguments are null pointers, return invalid error
55 // Windows does not accept empty environment variables
56 if (variable.empty() || value.empty())
57 {
58 errno = EINVAL;
59 return -1;
60 }
61
62 // Posix does not accept '=', so impose that here
63 if (variable.find('=') != std::string::npos)
64 {
65 errno = EINVAL;
66 return -1;
67 }
68
69 // Change flag equals to zero preserves a pre-existing value
70 if (change_flag == 0)
71 {
72 char* old_value = std::getenv(var_name);
73 if (old_value != nullptr)
74 {
75 return 0;
76 }
77 }
78
79 // Write new value for the environment variable
80 return _putenv_s(var_name, new_value);
81}
82
88int
89unsetenv(const char* var_name)
90{
91 return _putenv_s(var_name, "");
92}
93
94#endif // __WIN32__
95
96namespace ns3
97{
98
115#if 0
116#define NS_LOCAL_LOG(msg) \
117 std::cerr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): " << msg << std::endl
118
119#define NS_LOCAL_ASSERT(cond, msg) \
120 do \
121 { \
122 if (!(cond)) \
123 { \
124 NS_LOCAL_LOG("assert failed. cond=\"" << #cond << "\", " << msg); \
125 } \
126 } while (false)
127
128#else
129#define NS_LOCAL_LOG(msg)
130#define NS_LOCAL_ASSERT(cond, msg)
131#endif
132
133/* static */
136{
137 static DictionaryList instance;
138 return instance;
139}
140
141/* static */
142void
144{
145 Instance().clear();
146}
147
148/* static */
149std::shared_ptr<EnvironmentVariable::Dictionary>
150EnvironmentVariable::GetDictionary(const std::string& envvar, const std::string& delim /* ";" */)
151{
152 NS_LOCAL_LOG(envvar << ", " << delim);
153 std::shared_ptr<Dictionary> dict;
154 auto loc = Instance().find(envvar);
155 if (loc != Instance().end())
156 {
157 NS_LOCAL_LOG("found envvar in cache");
158 dict = loc->second;
159 }
160 else
161 {
162 NS_LOCAL_LOG("envvar not in cache, checking environment");
163 dict = std::make_shared<Dictionary>(envvar, delim);
164 Instance().insert({envvar, dict});
165 }
166
167 return dict;
168}
169
170/* static */
172EnvironmentVariable::Get(const std::string& envvar,
173 const std::string& key /* "" */,
174 const std::string& delim /* ";" */)
175{
176 auto dict = GetDictionary(envvar, delim);
177 return dict->Get(key);
178}
179
180/* static */
181bool
182EnvironmentVariable::Set(const std::string& variable, const std::string& value)
183{
184 int fail = setenv(variable.c_str(), value.c_str(), 1);
185 return !fail;
186}
187
188/* static */
189bool
190EnvironmentVariable::Unset(const std::string& variable)
191{
192 int fail = unsetenv(variable.c_str());
193 return !fail;
194}
195
197EnvironmentVariable::Dictionary::Get(const std::string& key) const
198{
199 NS_LOCAL_LOG(key);
200
201 if (!m_exists)
202 {
203 return {false, ""};
204 }
205
206 if (key.empty())
207 {
208 // Empty key is request for entire value
209 return {true, m_variable};
210 }
211
212 auto loc = m_dict.find(key);
213 if (loc != m_dict.end())
214 {
215 NS_LOCAL_LOG("found key in dictionary");
216 NS_LOCAL_LOG("found: key '" << key << "', value: '" << loc->second << "'");
217 return {true, loc->second};
218 }
219
220 // key not found
221 return {false, ""};
222}
223
225 const std::string& delim /* "=" */)
226{
227 NS_LOCAL_LOG(envvar << ", " << delim);
228
229 const char* envCstr = std::getenv(envvar.c_str());
230 // Returns null pointer if envvar doesn't exist
231 if (!envCstr)
232 {
233 m_exists = false;
234 return;
235 }
236
237 // So it exists
238 m_exists = true;
239 m_variable = envCstr;
240 NS_LOCAL_LOG("found envvar in environment with value '" << m_variable << "'");
241
242 // ...but might be empty
243 if (m_variable.empty())
244 {
245 return;
246 }
247
248 StringVector keyvals = SplitString(m_variable, delim);
249 NS_LOCAL_ASSERT(keyvals.empty(), "Unexpected empty keyvals from non-empty m_variable");
250 for (const auto& keyval : keyvals)
251 {
252 if (keyval.empty())
253 {
254 continue;
255 }
256
257 std::size_t equals = keyval.find_first_of('=');
258 std::string key{keyval, 0, equals};
259 std::string value;
260 if (equals < keyval.size() - 1)
261 {
262 value = keyval.substr(equals + 1, keyval.size());
263 }
264 NS_LOCAL_LOG("found key '" << key << "' with value '" << value << "'");
265 m_dict.insert({key, value});
266 }
267}
268
271{
272 return m_dict;
273}
274
275} // 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::unordered_map< std::string, std::shared_ptr< Dictionary > > DictionaryList
How Dictionaries are stored.
std::pair< bool, std::string > KeyFoundType
Result of a key lookup.
static void Clear()
Clear the instance, forcing all new lookups.
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.
std::vector< std::string > StringVector
Return type of SplitString.
Definition: string.h:37
StringVector SplitString(const std::string &str, const std::string &delim)
Split a string on a delimiter.
Definition: string.cc:34
value
Definition: second.py:48
ns3::StringValue attribute value declarations.