From: Dāvis Mosāns <davis...@gmail.com> On Windows getenv (and putenv) uses ANSI codepage so it needs to be encoded to internally used encoding (eg. UTF-8). Here we use _wgetenv (and _wputenv) instead and encode that.
Change-Id: I8cb91f2386eb0efe3ef0a3132d1603217d710b60 --- SystemTools.cxx | 190 +++++++++++++++++++++++++++++++++++++++-------------- SystemTools.hxx.in | 2 + 2 files changed, 143 insertions(+), 49 deletions(-) diff --git a/SystemTools.cxx b/SystemTools.cxx index db4d7af..79d3b96 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -388,6 +388,64 @@ class SystemToolsTranslationMap : { }; +/* Order by environment key only (VAR from VAR=VALUE). */ +#if defined(_WIN32) +typedef wchar_t envchar; +struct kwsysEnvCompare +{ + bool operator() (const wchar_t* l, const wchar_t* r) const + { + const wchar_t* leq = wcschr(l, '='); + const wchar_t* req = wcschr(r, '='); + size_t llen = leq? (leq-l) : wcslen(l); + size_t rlen = req? (req-r) : wcslen(r); + if(llen == rlen) + { + return wcsncmp(l,r,llen) < 0; + } + else + { + return wcscmp(l,r) < 0; + } + } +}; +#else +typedef char envchar; +struct kwsysEnvCompare +{ + bool operator() (const char* l, const char* r) const + { + const char* leq = strchr(l, '='); + const char* req = strchr(r, '='); + size_t llen = leq? (leq-l) : strlen(l); + size_t rlen = req? (req-r) : strlen(r); + if(llen == rlen) + { + return strncmp(l,r,llen) < 0; + } + else + { + return strcmp(l,r) < 0; + } + } +}; +#endif + +typedef std::set<const envchar*, kwsysEnvCompare> kwsysEnvSetType; + +class kwsysUnPutEnv : + public kwsysEnvSetType +{ + public: + ~kwsysUnPutEnv() { + for(kwsysEnvSetType::iterator i = this->begin(); i != this->end(); ++i) { + free(const_cast<envchar*>(*i)); + } + } +}; + +static kwsysUnPutEnv kwsysUnPutEnvInstance; + #ifdef _WIN32 struct SystemToolsPathCaseCmp { @@ -406,6 +464,9 @@ struct SystemToolsPathCaseCmp class SystemToolsPathCaseMap: public std::map<std::string, std::string, SystemToolsPathCaseCmp> {}; + +class SystemToolsEnvMap : + public std::map<std::string,std::string> {}; #endif // adds the elements of the env variable path to the arg passed in @@ -458,7 +519,18 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env) const char* SystemTools::GetEnv(const char* key) { - return getenv(key); + const char *v = 0; +#if defined(_WIN32) + std::string env; + if (SystemTools::GetEnv(key, env)) { + std::string& menv = (*EnvMap)[key]; + menv = env; + v = menv.c_str(); + } +#else + v = getenv(key); +#endif + return v; } const char* SystemTools::GetEnv(const std::string& key) @@ -468,16 +540,21 @@ const char* SystemTools::GetEnv(const std::string& key) bool SystemTools::GetEnv(const char* key, std::string& result) { +#if defined(_WIN32) + const std::wstring wkey = Encoding::ToWide(key); + const wchar_t* wv = _wgetenv(wkey.c_str()); + if (wv) { + result = Encoding::ToNarrow(wv); + return true; + } +#else const char* v = getenv(key); - if(v) - { + if (v) { result = v; return true; - } - else - { - return false; - } + } +#endif + return false; } bool SystemTools::GetEnv(const std::string& key, std::string& result) @@ -534,6 +611,7 @@ static int kwsysUnPutEnv(const std::string& env) int err = 0; size_t pos = env.find('='); size_t const len = pos == env.npos ? env.size() : pos; + pos = len; # ifdef KWSYS_PUTENV_EMPTY size_t const sz = len + 2; # else @@ -547,19 +625,31 @@ static int kwsysUnPutEnv(const std::string& env) } strncpy(buf, env.c_str(), len); # ifdef KWSYS_PUTENV_EMPTY - buf[len] = '='; - buf[len+1] = 0; - if(putenv(buf) < 0) - { - err = errno; - } + buf[pos] = '='; + pos++; +# endif + buf[pos] = 0; +# if defined(_WIN32) + const std::wstring wbuf = Encoding::ToWide(buf); + wchar_t *newbuf = wcsdup(wbuf.c_str()); + std::pair<kwsysEnvSetType::iterator,bool> val = kwsysUnPutEnvInstance.insert(newbuf); + const int r = _wputenv(*val.first); # else - buf[len] = 0; - if(putenv(buf) < 0 && errno != EINVAL) + char* newbuf = strdup(buf); + std::pair<kwsysEnvSetType::iterator,bool> val = kwsysUnPutEnvInstance.insert(newbuf); + const int r = putenv(*val.first); +# endif + if (!val.second) { + free(newbuf); + } +# ifdef KWSYS_PUTENV_EMPTY + if(r < 0) +# else + if(r < 0 && errno != EINVAL) +# endif { err = errno; } -# endif if(buf != local_buf) { free(buf); @@ -639,49 +729,33 @@ bool SystemTools::UnPutEnv(const std::string& env) # pragma warning disable 444 /* base has non-virtual destructor */ # endif -/* Order by environment key only (VAR from VAR=VALUE). */ -struct kwsysEnvCompare -{ - bool operator() (const char* l, const char* r) const - { - const char* leq = strchr(l, '='); - const char* req = strchr(r, '='); - size_t llen = leq? (leq-l) : strlen(l); - size_t rlen = req? (req-r) : strlen(r); - if(llen == rlen) - { - return strncmp(l,r,llen) < 0; - } - else - { - return strcmp(l,r) < 0; - } - } -}; - -class kwsysEnv: public std::set<const char*, kwsysEnvCompare> +class kwsysEnv: public kwsysEnvSetType { class Free { - const char* Env; + const envchar* Env; public: - Free(const char* env): Env(env) {} - ~Free() { free(const_cast<char*>(this->Env)); } + Free(const envchar* env): Env(env) {} + ~Free() { free(const_cast<envchar*>(this->Env)); } }; public: - typedef std::set<const char*, kwsysEnvCompare> derived; ~kwsysEnv() { - for(derived::iterator i = this->begin(); i != this->end(); ++i) + for(kwsysEnvSetType::iterator i = this->begin(); i != this->end(); ++i) { +#if defined(_WIN32) + const std::string s = Encoding::ToNarrow(*i); + kwsysUnPutEnv(s.c_str()); +#else kwsysUnPutEnv(*i); - free(const_cast<char*>(*i)); +#endif + free(const_cast<envchar*>(*i)); } } - const char* Release(const char* env) + const envchar* Release(const envchar* env) { - const char* old = 0; - derived::iterator i = this->find(env); + const envchar* old = 0; + kwsysEnvSetType::iterator i = this->find(env); if(i != this->end()) { old = *i; @@ -691,15 +765,30 @@ public: } bool Put(const char* env) { - Free oldEnv(this->Release(env)); - static_cast<void>(oldEnv); +#if defined(_WIN32) + const std::wstring wEnv = Encoding::ToWide(env); + wchar_t* newEnv = wcsdup(wEnv.c_str()); +#else char* newEnv = strdup(env); +#endif + Free oldEnv(this->Release(newEnv)); + static_cast<void>(oldEnv); +#if defined(_WIN32) + this->insert(newEnv); + return _wputenv(newEnv) == 0; +#else this->insert(newEnv); return putenv(newEnv) == 0; +#endif } bool UnPut(const char* env) { +#if defined(_WIN32) + const std::wstring wEnv = Encoding::ToWide(env); + Free oldEnv(this->Release(wEnv.c_str())); +#else Free oldEnv(this->Release(env)); +#endif static_cast<void>(oldEnv); return kwsysUnPutEnv(env) == 0; } @@ -5387,6 +5476,7 @@ static unsigned int SystemToolsManagerCount; SystemToolsTranslationMap *SystemTools::TranslationMap; #ifdef _WIN32 SystemToolsPathCaseMap *SystemTools::PathCaseMap; +SystemToolsEnvMap *SystemTools::EnvMap; #endif #ifdef __CYGWIN__ SystemToolsTranslationMap *SystemTools::Cyg2Win32Map; @@ -5437,6 +5527,7 @@ void SystemTools::ClassInitialize() SystemTools::TranslationMap = new SystemToolsTranslationMap; #ifdef _WIN32 SystemTools::PathCaseMap = new SystemToolsPathCaseMap; + SystemTools::EnvMap = new SystemToolsEnvMap; #endif #ifdef __CYGWIN__ SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap; @@ -5496,6 +5587,7 @@ void SystemTools::ClassFinalize() delete SystemTools::TranslationMap; #ifdef _WIN32 delete SystemTools::PathCaseMap; + delete SystemTools::EnvMap; #endif #ifdef __CYGWIN__ delete SystemTools::Cyg2Win32Map; diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in index c9b18b7..8f01e75 100644 --- a/SystemTools.hxx.in +++ b/SystemTools.hxx.in @@ -53,6 +53,7 @@ namespace @KWSYS_NAMESPACE@ class SystemToolsTranslationMap; class SystemToolsPathCaseMap; +class SystemToolsEnvMap; /** \class SystemToolsManager * \brief Use to make sure SystemTools is initialized before it is used @@ -991,6 +992,7 @@ private: static SystemToolsTranslationMap *TranslationMap; #ifdef _WIN32 static SystemToolsPathCaseMap *PathCaseMap; + static SystemToolsEnvMap *EnvMap; #endif #ifdef __CYGWIN__ static SystemToolsTranslationMap *Cyg2Win32Map; -- 2.9.0 -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake-developers