Revert D4832473: [Folly] Disable EnvUtil::setAsCurrentEnvironment() on platforms...
[folly.git] / folly / experimental / EnvUtil.cpp
index f31bd37dbcb9a7631637a0831dc4dfa357e3fe0e..5c16ee7407a53b6d2a80fa8d612190c9b01f0d36 100644 (file)
 #include <folly/portability/Stdlib.h>
 #include <folly/portability/Unistd.h>
 
-namespace folly {
-namespace test {
+using namespace folly;
+using namespace folly::experimental;
 
-static std::map<std::string, std::string> getEnvVarMap() {
-  std::map<std::string, std::string> data;
-  for (auto it = environ; *it != nullptr; ++it) {
+EnvironmentState EnvironmentState::fromCurrentEnvironment() {
+  std::unordered_map<std::string, std::string> data;
+  for (auto it = environ; it && *it; ++it) {
     std::string key, value;
-    split("=", *it, key, value);
-    if (key.empty()) {
-      continue;
+    folly::StringPiece entry(*it);
+    auto equalsPosition = entry.find('=');
+    if (equalsPosition == entry.npos) {
+      throw MalformedEnvironment{to<std::string>(
+          "Environment contains an non key-value-pair string \"", entry, "\"")};
     }
-    CHECK(!data.count(key)) << "already contains: " << key;
-    data.emplace(move(key), move(value));
+    key = entry.subpiece(0, equalsPosition).toString();
+    value = entry.subpiece(equalsPosition + 1).toString();
+    if (data.count(key)) {
+      throw MalformedEnvironment{to<std::string>(
+          "Environment contains duplicate value for \"", key, "\"")};
+    }
+    data.emplace(std::move(key), std::move(value));
   }
-  return data;
-}
-
-EnvVarSaver::EnvVarSaver() {
-  saved_ = getEnvVarMap();
+  return EnvironmentState{std::move(data)};
 }
 
-EnvVarSaver::~EnvVarSaver() {
-  for (const auto& kvp : getEnvVarMap()) {
-    if (saved_.count(kvp.first)) {
-      continue;
-    }
-    PCHECK(0 == unsetenv(kvp.first.c_str()));
-  }
-  for (const auto& kvp : saved_) {
+void EnvironmentState::setAsCurrentEnvironment() {
+  PCHECK(0 == clearenv());
+  for (const auto& kvp : env_) {
     PCHECK(0 == setenv(kvp.first.c_str(), kvp.second.c_str(), (int)true));
   }
 }
+
+std::vector<std::string> EnvironmentState::toVector() const {
+  std::vector<std::string> result;
+  for (auto const& pair : env_) {
+    result.emplace_back(to<std::string>(pair.first, "=", pair.second));
+  }
+  return result;
 }
+
+std::unique_ptr<char*, void (*)(char**)> EnvironmentState::toPointerArray()
+    const {
+  size_t totalStringLength{};
+  for (auto const& pair : env_) {
+    totalStringLength += pair.first.size() + pair.second.size() +
+        2 /* intermediate '=' and the terminating NUL */;
+  }
+  size_t allocationRequired =
+      (totalStringLength / sizeof(char*) + 1) + env_.size() + 1;
+  char** raw = new char*[allocationRequired];
+  char** ptrBase = raw;
+  char* stringBase = reinterpret_cast<char*>(&raw[env_.size() + 1]);
+  char* const stringEnd = reinterpret_cast<char*>(&raw[allocationRequired]);
+  for (auto const& pair : env_) {
+    std::string const& key = pair.first;
+    std::string const& value = pair.second;
+    *ptrBase = stringBase;
+    size_t lengthIncludingNullTerminator = key.size() + 1 + value.size() + 1;
+    CHECK_GT(stringEnd - lengthIncludingNullTerminator, stringBase);
+    memcpy(stringBase, key.c_str(), key.size());
+    stringBase += key.size();
+    *stringBase++ = '=';
+    memcpy(stringBase, value.c_str(), value.size() + 1);
+    stringBase += value.size() + 1;
+    ++ptrBase;
+  }
+  *ptrBase = nullptr;
+  CHECK_EQ(env_.size(), ptrBase - raw);
+  return {raw, [](char** ptr) { delete[] ptr; }};
 }