diff options
Diffstat (limited to 'Source/kwsys/SystemTools.cxx')
-rw-r--r-- | Source/kwsys/SystemTools.cxx | 271 |
1 files changed, 176 insertions, 95 deletions
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index c6e668d..0526372 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -388,6 +388,72 @@ class SystemToolsTranslationMap : { }; +/* Type of character storing the environment. */ +#if defined(_WIN32) +typedef wchar_t envchar; +#else +typedef char envchar; +#endif + +/* Order by environment key only (VAR from VAR=VALUE). */ +struct kwsysEnvCompare +{ + bool operator() (const envchar* l, const envchar* r) const + { +#if defined(_WIN32) + const wchar_t* leq = wcschr(l, L'='); + const wchar_t* req = wcschr(r, L'='); + 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 + 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 + } +}; + +class kwsysEnvSet: public std::set<const envchar*, kwsysEnvCompare> +{ +public: + class Free + { + const envchar* Env; + public: + Free(const envchar* env): Env(env) {} + ~Free() { free(const_cast<envchar*>(this->Env)); } + }; + + const envchar* Release(const envchar* env) + { + const envchar* old = 0; + iterator i = this->find(env); + if(i != this->end()) + { + old = *i; + this->erase(i); + } + return old; + } +}; + #ifdef _WIN32 struct SystemToolsPathCaseCmp { @@ -406,6 +472,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 @@ -421,14 +490,12 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env) { env = "PATH"; } - const char* cpathEnv = SystemTools::GetEnv(env); - if ( !cpathEnv ) + std::string pathEnv; + if ( !SystemTools::GetEnv(env, pathEnv) ) { return; } - std::string pathEnv = cpathEnv; - // A hack to make the below algorithm work. if(!pathEnv.empty() && *pathEnv.rbegin() != pathSep) { @@ -458,7 +525,19 @@ 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 = (*SystemTools::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 +547,23 @@ 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) { result = v; return true; } - else - { - return false; - } +#endif + return false; } bool SystemTools::GetEnv(const std::string& key, std::string& result) @@ -485,13 +571,23 @@ bool SystemTools::GetEnv(const std::string& key, std::string& result) return SystemTools::GetEnv(key.c_str(), result); } -//---------------------------------------------------------------------------- - -#if defined(__CYGWIN__) || defined(__GLIBC__) -# define KWSYS_PUTENV_NAME /* putenv("A") removes A. */ -#elif defined(_WIN32) -# define KWSYS_PUTENV_EMPTY /* putenv("A=") removes A. */ +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 KWSYS_CXX_HAS_UNSETENV /* unsetenv("A") removes A from the environment. @@ -511,18 +607,15 @@ static int kwsysUnPutEnv(const std::string& env) return 0; } -#elif defined(KWSYS_PUTENV_EMPTY) || defined(KWSYS_PUTENV_NAME) -/* putenv("A=") or putenv("A") removes A from the environment. */ +#elif defined(__CYGWIN__) || defined(__GLIBC__) +/* putenv("A") removes A from the environment. It must not put the + memory in the environment because it does not have any "=" syntax. */ 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; -# ifdef KWSYS_PUTENV_EMPTY - size_t const sz = len + 2; -# else size_t const sz = len + 1; -# endif char local_buf[256]; char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; if(!buf) @@ -530,20 +623,11 @@ static int kwsysUnPutEnv(const std::string& env) return -1; } strncpy(buf, env.c_str(), len); -# ifdef KWSYS_PUTENV_EMPTY - buf[len] = '='; - buf[len+1] = 0; - if(putenv(buf) < 0) - { - err = errno; - } -# else buf[len] = 0; if(putenv(buf) < 0 && errno != EINVAL) { err = errno; } -# endif if(buf != local_buf) { free(buf); @@ -556,6 +640,30 @@ static int kwsysUnPutEnv(const std::string& env) return 0; } +#elif defined(_WIN32) +/* putenv("A=") places "A=" in the environment, which is as close to + removal as we can get with the putenv API. We have to leak the + most recent value placed in the environment for each variable name + on program exit in case exit routines access it. */ + +static kwsysEnvSet kwsysUnPutEnvSet; + +static int kwsysUnPutEnv(std::string const& env) +{ + std::wstring wEnv = Encoding::ToWide(env); + size_t const pos = wEnv.find('='); + size_t const len = pos == wEnv.npos ? wEnv.size() : pos; + wEnv.resize(len+1, L'='); + wchar_t* newEnv = _wcsdup(wEnv.c_str()); + if(!newEnv) + { + return -1; + } + kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv)); + kwsysUnPutEnvSet.insert(newEnv); + return _wputenv(newEnv); +} + #else /* Manipulate the "environ" global directly. */ static int kwsysUnPutEnv(const std::string& env) @@ -623,68 +731,46 @@ 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 kwsysEnvSet { - class Free - { - const char* Env; - public: - Free(const char* env): Env(env) {} - ~Free() { free(const_cast<char*>(this->Env)); } - }; public: - typedef std::set<const char*, kwsysEnvCompare> derived; ~kwsysEnv() { - for(derived::iterator i = this->begin(); i != this->end(); ++i) + for(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)); - } - } - const char* Release(const char* env) - { - const char* old = 0; - derived::iterator i = this->find(env); - if(i != this->end()) - { - old = *i; - this->erase(i); +#endif + free(const_cast<envchar*>(*i)); } - return old; } 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)); this->insert(newEnv); +#if defined(_WIN32) + return _wputenv(newEnv) == 0; +#else 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)); - static_cast<void>(oldEnv); +#endif return kwsysUnPutEnv(env) == 0; } }; @@ -2044,8 +2130,8 @@ void SystemTools::ConvertToUnixSlashes(std::string& path) pathCString = path.c_str(); if(pathCString[0] == '~' && (pathCString[1] == '/' || pathCString[1] == '\0')) { - const char* homeEnv = SystemTools::GetEnv("HOME"); - if (homeEnv) + std::string homeEnv; + if (SystemTools::GetEnv("HOME", homeEnv)) { path.replace(0,1,homeEnv); } @@ -4061,16 +4147,9 @@ void SystemTools::SplitPath(const std::string& p, if(root.size() == 1) { #if defined(_WIN32) && !defined(__CYGWIN__) - if(const char* userp = getenv("USERPROFILE")) - { - homedir = userp; - } - else + if (!SystemTools::GetEnv("USERPROFILE", homedir)) #endif - if(const char* h = getenv("HOME")) - { - homedir = h; - } + SystemTools::GetEnv("HOME", homedir); } #ifdef HAVE_GETPWNAM else if(passwd* pw = getpwnam(root.c_str()+1)) @@ -4811,7 +4890,7 @@ int SystemTools::GetTerminalWidth() int width = -1; #ifdef HAVE_TTY_INFO struct winsize ws; - char *columns; /* Unix98 environment variable */ + std::string columns; /* Unix98 environment variable */ if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) { width = ws.ws_col; @@ -4820,12 +4899,11 @@ int SystemTools::GetTerminalWidth() { width = -1; } - columns = getenv("COLUMNS"); - if(columns && *columns) + if(SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) { long t; char *endptr; - t = strtol(columns, &endptr, 0); + t = strtol(columns.c_str(), &endptr, 0); if(endptr && !*endptr && (t>0) && (t<1000)) { width = static_cast<int>(t); @@ -5371,6 +5449,7 @@ static unsigned int SystemToolsManagerCount; SystemToolsTranslationMap *SystemTools::TranslationMap; #ifdef _WIN32 SystemToolsPathCaseMap *SystemTools::PathCaseMap; +SystemToolsEnvMap *SystemTools::EnvMap; #endif #ifdef __CYGWIN__ SystemToolsTranslationMap *SystemTools::Cyg2Win32Map; @@ -5421,6 +5500,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; @@ -5435,7 +5515,8 @@ void SystemTools::ClassInitialize() // If the current working directory is a logical path then keep the // logical name. - if(const char* pwd = getenv("PWD")) + std::string pwd_str; + if(SystemTools::GetEnv("PWD", pwd_str)) { char buf[2048]; if(const char* cwd = Getcwd(buf, 2048)) @@ -5447,10 +5528,9 @@ void SystemTools::ClassInitialize() std::string pwd_changed; // Test progressively shorter logical-to-physical mappings. - std::string pwd_str = pwd; std::string cwd_str = cwd; std::string pwd_path; - Realpath(pwd, pwd_path); + Realpath(pwd_str.c_str(), pwd_path); while(cwd_str == pwd_path && cwd_str != pwd_str) { // The current pair of paths is a working logical mapping. @@ -5480,6 +5560,7 @@ void SystemTools::ClassFinalize() delete SystemTools::TranslationMap; #ifdef _WIN32 delete SystemTools::PathCaseMap; + delete SystemTools::EnvMap; #endif #ifdef __CYGWIN__ delete SystemTools::Cyg2Win32Map; @@ -5505,8 +5586,8 @@ static int SystemToolsDebugReport(int, char* message, int*) void SystemTools::EnableMSVCDebugHook() { - if (getenv("DART_TEST_FROM_DART") || - getenv("DASHBOARD_TEST_FROM_CTEST")) + if (SystemTools::HasEnv("DART_TEST_FROM_DART") || + SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { _CrtSetReportHook(SystemToolsDebugReport); } |