From fe0e2fcaff57f8527570d4160eab2fd67750423a Mon Sep 17 00:00:00 2001 From: John Drouhard Date: Fri, 5 Sep 2025 09:10:16 -0500 Subject: [PATCH] ScopedEnv: add a RAII helper to temporarily manipulate the environment --- Source/cmSystemTools.cxx | 35 +++++++++++++++++++++++++++++++++++ Source/cmSystemTools.h | 23 +++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index f11d347de7..85aba246fd 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2310,6 +2310,41 @@ cmSystemTools::SaveRestoreEnvironment::~SaveRestoreEnvironment() } #endif +cmSystemTools::ScopedEnv::ScopedEnv(cm::string_view var) +{ + std::string::size_type pos = var.find('='); + if (pos != std::string::npos) { + this->Key = std::string{ var.substr(0, pos) }; + this->Original = cmSystemTools::GetEnvVar(this->Key); + + cm::string_view value = var.substr(pos + 1); + + if (!this->Original && value.empty()) { + // nothing to do if the environment variable wasn't already set and the + // new value is also empty. clear the Key member so the destructor also + // does nothing. + this->Key.clear(); + } else { + if (value.empty()) { + cmSystemTools::UnPutEnv(this->Key); + } else { + cmSystemTools::PutEnv(cmStrCat(this->Key, '=', value)); + } + } + } +} + +cmSystemTools::ScopedEnv::~ScopedEnv() +{ + if (!this->Key.empty()) { + if (this->Original) { + cmSystemTools::PutEnv(cmStrCat(this->Key, '=', *this->Original)); + } else { + cmSystemTools::UnPutEnv(Key); + } + } +} + void cmSystemTools::EnableVSConsoleOutput() { #ifdef _WIN32 diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 5c187ecb0f..53b2592825 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -517,6 +517,29 @@ public: }; #endif + /** \class ScopedEnv + * \brief An RAII class to temporarily set/unset an environment variable. + * + * The value passed to the constructor is put into the environment. This + * variable is of the form "var=value" and the original value of the "var" + * environment variable is saved. When the object is destroyed, the original + * value for the environment variable is restored. If the variable didn't + * exist, it will be unset. + */ + class ScopedEnv + { + public: + ScopedEnv(cm::string_view val); + ~ScopedEnv(); + + ScopedEnv(ScopedEnv const&) = delete; + ScopedEnv& operator=(ScopedEnv const&) = delete; + + private: + std::string Key; + cm::optional Original; + }; + /** Setup the environment to enable VS 8 IDE output. */ static void EnableVSConsoleOutput();