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