[cmake-developers] [PATCH v4 fixed 1/4] On Windows use correct encoding for SystemTools::GetEnv

Dāvis Mosāns davispuh at gmail.com
Thu Jul 7 18:32:17 EDT 2016


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.

Also add SystemTools::HasEnv function.
---
 Source/kwsys/SystemTools.cxx    | 80 +++++++++++++++++++++++++++++++++++------
 Source/kwsys/SystemTools.hxx.in |  4 +++
 2 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index c6e668d..5bcf0d0 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -406,6 +406,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 +461,23 @@ 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)) {
+    const std::string skey = key;
+    SystemToolsEnvMap::iterator i = EnvMap->find(skey);
+    if (i != EnvMap->end()) {
+      i->second = env;
+    } else {
+      i = EnvMap->insert(SystemToolsEnvMap::value_type(skey, env)).first;
+    }
+    v = i->second.c_str();
+  }
+#else
+  v = getenv(key);
+#endif
+  return v;
 }
 
 const char* SystemTools::GetEnv(const std::string& key)
@@ -468,16 +487,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)
@@ -485,6 +509,22 @@ bool SystemTools::GetEnv(const std::string& key, std::string& result)
   return SystemTools::GetEnv(key.c_str(), result);
 }
 
+bool SystemTools::HasEnv(const char* key)
+{
+#if defined(_WIN32)
+  const std::wstring wkey = Encoding::ToWide(key);
+  const wchar_t* v = _wgetenv(wkey.c_str());
+#else
+  const char* v = getenv(key);
+#endif
+  return v != 0;
+}
+
+bool SystemTools::HasEnv(const std::string& key)
+{
+  return SystemTools::HasEnv(key.c_str());
+}
+
 //----------------------------------------------------------------------------
 
 #if defined(__CYGWIN__) || defined(__GLIBC__)
@@ -533,13 +573,25 @@ static int kwsysUnPutEnv(const std::string& env)
 # ifdef KWSYS_PUTENV_EMPTY
   buf[len] = '=';
   buf[len+1] = 0;
-  if(putenv(buf) < 0)
+#if defined(_WIN32)
+  const std::wstring wbuf = Encoding::ToWide(buf);
+  const int r = _wputenv(wbuf.c_str());
+#else
+  const int r = putenv(buf);
+#endif
+  if(r < 0)
     {
     err = errno;
     }
 # else
   buf[len] = 0;
-  if(putenv(buf) < 0 && errno != EINVAL)
+#if defined(_WIN32)
+  const std::wstring wbuf = Encoding::ToWide(buf);
+  const int r = _wputenv(wbuf.c_str());
+#else
+  const int r = putenv(buf);
+#endif
+  if(r < 0 && errno != EINVAL)
     {
     err = errno;
     }
@@ -679,7 +731,12 @@ public:
     static_cast<void>(oldEnv);
     char* newEnv = strdup(env);
     this->insert(newEnv);
+#if defined(_WIN32)
+    const std::wstring wEnv = Encoding::ToWide(newEnv);
+    return _wputenv(wEnv.c_str()) == 0;
+#else
     return putenv(newEnv) == 0;
+#endif
     }
   bool UnPut(const char* env)
     {
@@ -5371,6 +5428,7 @@ static unsigned int SystemToolsManagerCount;
 SystemToolsTranslationMap *SystemTools::TranslationMap;
 #ifdef _WIN32
 SystemToolsPathCaseMap *SystemTools::PathCaseMap;
+SystemToolsEnvMap *SystemTools::EnvMap;
 #endif
 #ifdef __CYGWIN__
 SystemToolsTranslationMap *SystemTools::Cyg2Win32Map;
@@ -5421,6 +5479,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;
@@ -5480,6 +5539,7 @@ void SystemTools::ClassFinalize()
   delete SystemTools::TranslationMap;
 #ifdef _WIN32
   delete SystemTools::PathCaseMap;
+  delete SystemTools::EnvMap;
 #endif
 #ifdef __CYGWIN__
   delete SystemTools::Cyg2Win32Map;
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index bba5a5c..8f01e75 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/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
@@ -843,6 +844,8 @@ public:
   static const char* GetEnv(const std::string& key);
   static bool GetEnv(const char* key, std::string& result);
   static bool GetEnv(const std::string& key, std::string& result);
+  static bool HasEnv(const char* key);
+  static bool HasEnv(const std::string& key);
 
   /** Put a string into the environment
       of the form var=value */
@@ -989,6 +992,7 @@ private:
   static SystemToolsTranslationMap *TranslationMap;
 #ifdef _WIN32
   static SystemToolsPathCaseMap *PathCaseMap;
+  static SystemToolsEnvMap *EnvMap;
 #endif
 #ifdef __CYGWIN__
   static SystemToolsTranslationMap *Cyg2Win32Map;
-- 
2.9.0



More information about the cmake-developers mailing list