core: enable environment variable for Windows
This commit is contained in:
committed by
Gabriel Ferreira
parent
74035411bd
commit
ce4026523a
@@ -21,15 +21,78 @@
|
||||
|
||||
#include "ns3/string.h"
|
||||
|
||||
#include <cstdlib> // getenv
|
||||
#include <cstdlib> // std::getenv
|
||||
#include <cstring> // strlen
|
||||
#include <iostream> // clog
|
||||
#include <stdlib.h> // Global functions setenv, unsetenv
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup core-environ
|
||||
* Class EnvironmentVariable implementation.
|
||||
*/
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <cerrno>
|
||||
|
||||
/**
|
||||
* Windows implementation of the POSIX function `setenv()`
|
||||
*
|
||||
* \param [in] var_name The environment variable to set.
|
||||
* Must not be a null-pointer, and must not contain `=`.
|
||||
* \param [in] new_value The new value to set \p var_name to.
|
||||
* Must not by a null pointer or empty.
|
||||
* \param [in] change_flag Must be non-zero to actually change the environment.
|
||||
* \returns 0 if successful, -1 if failed.
|
||||
*/
|
||||
int
|
||||
setenv(const char* var_name, const char* new_value, int change_flag)
|
||||
{
|
||||
std::string variable{var_name};
|
||||
std::string value{new_value};
|
||||
|
||||
// In case arguments are null pointers, return invalid error
|
||||
// Windows does not accept empty environment variables
|
||||
if (variable.empty() || value.empty())
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Posix does not accept '=', so impose that here
|
||||
if (variable.find('=') != std::string::npos)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Change flag equals to zero preserves a pre-existing value
|
||||
if (change_flag == 0)
|
||||
{
|
||||
char* old_value = std::getenv(var_name);
|
||||
if (old_value != nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Write new value for the environment variable
|
||||
return _putenv_s(var_name, new_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows implementation of the POSIX function `unsetenv()`
|
||||
* \param [in] var_name The environment variable to unset and remove from the environment.
|
||||
* \returns 0 if successful, -1 if failed.
|
||||
*/
|
||||
int
|
||||
unsetenv(const char* var_name)
|
||||
{
|
||||
return _putenv_s(var_name, "");
|
||||
}
|
||||
|
||||
#endif // __WIN32__
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
@@ -114,6 +177,22 @@ EnvironmentVariable::Get(const std::string& envvar,
|
||||
return dict->Get(key);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
EnvironmentVariable::Set(const std::string& variable, const std::string& value)
|
||||
{
|
||||
int fail = setenv(variable.c_str(), value.c_str(), 1);
|
||||
return !fail;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
EnvironmentVariable::Unset(const std::string& variable)
|
||||
{
|
||||
int fail = unsetenv(variable.c_str());
|
||||
return !fail;
|
||||
}
|
||||
|
||||
EnvironmentVariable::KeyFoundType
|
||||
EnvironmentVariable::Dictionary::Get(const std::string& key) const
|
||||
{
|
||||
|
||||
@@ -167,6 +167,28 @@ class EnvironmentVariable
|
||||
|
||||
}; // class Dictionary
|
||||
|
||||
/**
|
||||
* Set an environment variable.
|
||||
*
|
||||
* To set a variable to the empty string use `Set(variable, "")`.
|
||||
* Note: empty environment variables are not portable (unsupported on Windows).
|
||||
*
|
||||
* \param [in] variable The environment variable to set. Note this may not contain the `=`
|
||||
* character. \param [in] value The value to set. Note this must not be an empty string on
|
||||
* Windows. \returns \c true if the variable was set successfully
|
||||
*/
|
||||
static bool Set(const std::string& variable, const std::string& value);
|
||||
|
||||
/**
|
||||
* Unset an environment variable.
|
||||
* This removes the variable from the environment.
|
||||
* To set a variable to the empty string use `Set(variable, "")`.
|
||||
*
|
||||
* \param [in] variable The environment variable to unset. Note this may not contain the `=`
|
||||
* character. \returns \c true if the variable was unset successfully.
|
||||
*/
|
||||
static bool Unset(const std::string& variable);
|
||||
|
||||
/**
|
||||
* \name Singleton
|
||||
*
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#include "ns3/environment-variable.h"
|
||||
#include "ns3/test.h"
|
||||
|
||||
#include <cstdlib> // setenv, unsetenv
|
||||
#include <stdlib.h> // getenv
|
||||
#include <cstdlib> // getenv
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
@@ -52,7 +51,7 @@ class EnvVarTestCase : public TestCase
|
||||
EnvVarTestCase();
|
||||
|
||||
/** Destructor */
|
||||
~EnvVarTestCase() override = default;
|
||||
~EnvVarTestCase() override;
|
||||
|
||||
private:
|
||||
/** Run the tests */
|
||||
@@ -129,12 +128,17 @@ EnvVarTestCase::EnvVarTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
EnvVarTestCase::~EnvVarTestCase()
|
||||
{
|
||||
UnsetVariable("destructor");
|
||||
}
|
||||
|
||||
void
|
||||
EnvVarTestCase::SetVariable(const std::string& where, const std::string& value)
|
||||
{
|
||||
EnvironmentVariable::Clear();
|
||||
int ok = setenv(m_variable.c_str(), value.c_str(), 1);
|
||||
NS_TEST_EXPECT_MSG_EQ(ok, 0, where << ": failed to set variable");
|
||||
bool ok = EnvironmentVariable::Set(m_variable, value);
|
||||
NS_TEST_EXPECT_MSG_EQ(ok, true, where << ": failed to set variable");
|
||||
|
||||
// Double check
|
||||
const char* envCstr = std::getenv(m_variable.c_str());
|
||||
@@ -146,8 +150,8 @@ void
|
||||
EnvVarTestCase::UnsetVariable(const std::string& where)
|
||||
{
|
||||
EnvironmentVariable::Clear();
|
||||
int ok = unsetenv(m_variable.c_str());
|
||||
NS_TEST_EXPECT_MSG_EQ(ok, 0, where << ": failed to unset variable");
|
||||
bool ok = EnvironmentVariable::Unset(where);
|
||||
NS_TEST_EXPECT_MSG_EQ(ok, true, where << ": failed to unset variable");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -250,7 +254,10 @@ EnvVarTestCase::DoRun()
|
||||
NS_TEST_EXPECT_MSG_EQ(value.empty(), true, "unset: non-empty value from unset variable");
|
||||
|
||||
// Variable set but empty
|
||||
#ifndef __WIN32__
|
||||
// Windows doesn't support environment variables with empty values
|
||||
SetCheckAndGet("empty", "", {}, "", {true, ""});
|
||||
#endif
|
||||
|
||||
// Key not in variable
|
||||
SetCheckAndGet("no-key",
|
||||
@@ -307,7 +314,7 @@ EnvVarTestCase::DoRun()
|
||||
/**
|
||||
* \ingroup environ-var-tests
|
||||
*
|
||||
* TypeId test suites.
|
||||
* Environment variable handling test suite.
|
||||
*/
|
||||
class EnvironmentVariableTestSuite : public TestSuite
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user