A Discrete-Event Network Simulator
API
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 
20 #include "environment-variable.h"
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 
48 int
49 setenv(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 
88 int
89 unsetenv(const char* var_name)
90 {
91  return _putenv_s(var_name, "");
92 }
93 
94 #endif // __WIN32__
95 
96 namespace 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 */
142 void
144 {
145  Instance().clear();
146 }
147 
148 /* static */
149 std::shared_ptr<EnvironmentVariable::Dictionary>
150 EnvironmentVariable::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 */
172 EnvironmentVariable::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 */
181 bool
182 EnvironmentVariable::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 */
189 bool
191 {
192  int fail = unsetenv(variable.c_str());
193  return !fail;
194 }
195 
197 EnvironmentVariable::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.