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 typically Windows applications (eg. MSVC compiler) use current console's codepage for output to pipes so we need to encode that to internally used encoding (KWSYS_ENCODING_DEFAULT_CODEPAGE). Next, when we're outputing to console need to use wide functions. This change allows that compilers such as MSVC on Windows can be installed in non-ASCII path and will work correctly for all console's codepages which supports that path's characters. --- Source/CPack/cmCPackGenerator.cxx | 8 +-- Source/CTest/cmCTestCoverageHandler.cxx | 12 ++-- Source/CTest/cmCTestCurl.cxx | 21 +++---- Source/CTest/cmCTestMultiProcessHandler.cxx | 8 +-- Source/cmBuildCommand.cxx | 23 +++---- Source/cmCLocaleEnvironmentScope.cxx | 4 +- Source/cmCTest.cxx | 11 ++-- Source/cmCommandArgumentParserHelper.cxx | 8 +-- Source/cmConditionEvaluator.cxx | 2 +- Source/cmExportCommand.cxx | 5 +- Source/cmExtraEclipseCDT4Generator.cxx | 9 +-- Source/cmFileCommand.cxx | 12 ++-- Source/cmFindPackageCommand.cxx | 4 +- Source/cmGlobalVisualStudio7Generator.cxx | 6 +- Source/cmMakefile.cxx | 5 +- Source/cmNinjaTargetGenerator.cxx | 2 +- Source/cmQtAutoGenerators.cxx | 2 +- Source/cmSetCommand.cxx | 6 +- Source/cmState.cxx | 5 +- Source/cmSystemTools.cxx | 11 +++- Source/cmTimestamp.cxx | 7 +-- Source/cmake.cxx | 16 ++--- Source/cmakemain.cxx | 38 ++++++++++- Source/cmcmd.cxx | 12 ++-- Source/kwsys/CMakeLists.txt | 2 + Source/kwsys/Directory.cxx | 2 +- Source/kwsys/FStream.hxx.in | 19 +++++- Source/kwsys/ProcessWin32.c | 25 +++++++- Source/kwsys/SystemInformation.cxx | 20 +++--- Source/kwsys/SystemTools.cxx | 98 +++++++++++++++++++---------- Source/kwsys/SystemTools.hxx.in | 4 +- Source/kwsys/testSystemTools.cxx | 9 +-- 32 files changed, 260 insertions(+), 156 deletions(-) diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index df8bb0f..76609e1 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -1074,11 +1074,11 @@ const char* cmCPackGenerator::GetInstallPath() return this->InstallPath.c_str(); } #if defined(_WIN32) && !defined(__CYGWIN__) - const char* prgfiles = cmsys::SystemTools::GetEnv("ProgramFiles"); - const char* sysDrive = cmsys::SystemTools::GetEnv("SystemDrive"); - if (prgfiles) { + std::string prgfiles; + std::string sysDrive; + if (cmsys::SystemTools::GetEnv("ProgramFiles", prgfiles)) { this->InstallPath = prgfiles; - } else if (sysDrive) { + } else if (cmsys::SystemTools::GetEnv("SystemDrive", sysDrive)) { this->InstallPath = sysDrive; this->InstallPath += "/Program Files"; } else { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 7102533..9410a52 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -727,10 +727,7 @@ int cmCTestCoverageHandler::HandleCoberturaCoverage( // if it doesn't exist or is empty, assume the // binary directory is used. std::string coverageXMLFile; - const char* covDir = cmSystemTools::GetEnv("COBERTURADIR"); - if (covDir && strlen(covDir) != 0) { - coverageXMLFile = std::string(covDir); - } else { + if (!cmSystemTools::GetEnv("COBERTURADIR", coverageXMLFile) || coverageXMLFile.empty()) { coverageXMLFile = this->CTest->GetBinaryDir(); } // build the find file string with the directory from above @@ -791,7 +788,8 @@ struct cmCTestCoverageHandlerLocale { cmCTestCoverageHandlerLocale() { - if (const char* l = cmSystemTools::GetEnv("LC_ALL")) { + std::string l; + if (cmSystemTools::GetEnv("LC_ALL", l)) { lc_all = l; } if (lc_all != "C") { @@ -2121,8 +2119,8 @@ int cmCTestCoverageHandler::RunBullseyeSourceSummary( int cmCTestCoverageHandler::HandleBullseyeCoverage( cmCTestCoverageHandlerContainer* cont) { - const char* covfile = cmSystemTools::GetEnv("COVFILE"); - if (!covfile || strlen(covfile) == 0) { + std::string covfile; + if (!cmSystemTools::GetEnv("COVFILE", covfile) || covfile.empty()) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " COVFILE environment variable not found, not running " " bullseye\n", diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index 6b8e5b5..19f32c8 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -219,16 +219,16 @@ bool cmCTestCurl::HttpRequest(std::string const& url, void cmCTestCurl::SetProxyType() { - if (cmSystemTools::GetEnv("HTTP_PROXY")) { - this->HTTPProxy = cmSystemTools::GetEnv("HTTP_PROXY"); - if (cmSystemTools::GetEnv("HTTP_PROXY_PORT")) { + if (cmSystemTools::GetEnv("HTTP_PROXY", this->HTTPProxy)) { + std::string port; + if (cmSystemTools::GetEnv("HTTP_PROXY_PORT", port)) { this->HTTPProxy += ":"; - this->HTTPProxy += cmSystemTools::GetEnv("HTTP_PROXY_PORT"); + this->HTTPProxy += port; } - if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE")) { + std::string type; + if (cmSystemTools::GetEnv("HTTP_PROXY_TYPE", type)) { // this is the default this->HTTPProxyType = CURLPROXY_HTTP; - std::string type = cmSystemTools::GetEnv("HTTP_PROXY_TYPE"); // HTTP/SOCKS4/SOCKS5 if (type == "HTTP") { this->HTTPProxyType = CURLPROXY_HTTP; @@ -238,12 +238,11 @@ void cmCTestCurl::SetProxyType() this->HTTPProxyType = CURLPROXY_SOCKS5; } } - if (cmSystemTools::GetEnv("HTTP_PROXY_USER")) { - this->HTTPProxyAuth = cmSystemTools::GetEnv("HTTP_PROXY_USER"); - } - if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD")) { + cmSystemTools::GetEnv("HTTP_PROXY_USER", this->HTTPProxyAuth); + std::string passwd; + if (cmSystemTools::GetEnv("HTTP_PROXY_PASSWD", passwd)) { this->HTTPProxyAuth += ":"; - this->HTTPProxyAuth += cmSystemTools::GetEnv("HTTP_PROXY_PASSWD"); + this->HTTPProxyAuth += passwd; } } } diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index ae97d32..ffd51c7 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -261,12 +261,12 @@ void cmCTestMultiProcessHandler::StartNextTests() allTestsFailedTestLoadCheck = true; // Check for a fake load average value used in testing. - if (const char* fake_load_value = - cmSystemTools::GetEnv("__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING")) { + std::string fake_load_value; + if (cmSystemTools::GetEnv("__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING", fake_load_value)) { usedFakeLoadForTesting = true; - if (!cmSystemTools::StringToULong(fake_load_value, &systemLoad)) { + if (!cmSystemTools::StringToULong(fake_load_value.c_str(), &systemLoad)) { cmSystemTools::Error("Failed to parse fake load value: ", - fake_load_value); + fake_load_value.c_str()); } } // If it's not set, look up the true load average. diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index fb143a2..d29c31f 100644 --- a/Source/cmBuildCommand.cxx +++ b/Source/cmBuildCommand.cxx @@ -36,8 +36,8 @@ bool cmBuildCommand::MainSignature(std::vector<std::string> const& args) const char* variable = args[0].c_str(); // Parse remaining arguments. - const char* configuration = CM_NULLPTR; - const char* project_name = CM_NULLPTR; + std::string configuration; + std::string project_name; std::string target; enum Doing { @@ -56,10 +56,10 @@ bool cmBuildCommand::MainSignature(std::vector<std::string> const& args) doing = DoingTarget; } else if (doing == DoingConfiguration) { doing = DoingNone; - configuration = args[i].c_str(); + configuration = args[i]; } else if (doing == DoingProjectName) { doing = DoingNone; - project_name = args[i].c_str(); + project_name = args[i]; } else if (doing == DoingTarget) { doing = DoingNone; target = args[i]; @@ -76,14 +76,14 @@ bool cmBuildCommand::MainSignature(std::vector<std::string> const& args) // so we put this code here to end up with the same default configuration // as the original 2-arg build_command signature: // - if (!configuration || !*configuration) { - configuration = getenv("CMAKE_CONFIG_TYPE"); + if (configuration.empty()) { + cmSystemTools::GetEnv("CMAKE_CONFIG_TYPE", configuration); } - if (!configuration || !*configuration) { + if (configuration.empty()) { configuration = "Release"; } - if (project_name && *project_name) { + if (!project_name.empty()) { this->Makefile->IssueMessage( cmake::AUTHOR_WARNING, "Ignoring PROJECT_NAME option because it has no effect."); @@ -91,7 +91,7 @@ bool cmBuildCommand::MainSignature(std::vector<std::string> const& args) std::string makecommand = this->Makefile->GetGlobalGenerator()->GenerateCMakeBuildCommand( - target, configuration, "", this->Makefile->IgnoreErrorsCMP0061()); + target, configuration.c_str(), "", this->Makefile->IgnoreErrorsCMP0061()); this->Makefile->AddDefinition(variable, makecommand.c_str()); @@ -109,10 +109,7 @@ bool cmBuildCommand::TwoArgsSignature(std::vector<std::string> const& args) const char* cacheValue = this->Makefile->GetDefinition(define); std::string configType = "Release"; - const char* cfg = getenv("CMAKE_CONFIG_TYPE"); - if (cfg && *cfg) { - configType = cfg; - } + cmSystemTools::GetEnv("CMAKE_CONFIG_TYPE", configType); std::string makecommand = this->Makefile->GetGlobalGenerator()->GenerateCMakeBuildCommand( diff --git a/Source/cmCLocaleEnvironmentScope.cxx b/Source/cmCLocaleEnvironmentScope.cxx index a19dbae..5661cd9 100644 --- a/Source/cmCLocaleEnvironmentScope.cxx +++ b/Source/cmCLocaleEnvironmentScope.cxx @@ -31,8 +31,8 @@ cmCLocaleEnvironmentScope::cmCLocaleEnvironmentScope() std::string cmCLocaleEnvironmentScope::GetEnv(std::string const& key) { - const char* value = cmSystemTools::GetEnv(key); - return value ? value : std::string(); + std::string value; + return cmSystemTools::GetEnv(key, value) ? value : std::string(); } void cmCLocaleEnvironmentScope::SetEnv(std::string const& key, diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 9950a84..4eb4e3a 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -298,9 +298,9 @@ cmCTest::cmCTest() this->ComputedCompressMemCheckOutput = false; this->RepeatTests = 1; // default to run each test once this->RepeatUntilFail = false; - if (const char* outOnFail = - cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE")) { - this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(outOnFail); + std::string outOnFail; + if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", outOnFail)) { + this->OutputTestOutputOnTestFailure = !cmSystemTools::IsOff(outOnFail.c_str()); } this->InitStreams(); @@ -2125,8 +2125,9 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) } // the close of the for argument loop if (!this->ParallelLevelSetInCli) { - if (const char* parallel = cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL")) { - int plevel = atoi(parallel); + std::string parallel; + if (cmSystemTools::GetEnv("CTEST_PARALLEL_LEVEL", parallel)) { + int plevel = atoi(parallel.c_str()); this->SetParallelLevel(plevel); } } diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index 294117c..42fb105 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -71,12 +71,12 @@ char* cmCommandArgumentParserHelper::ExpandSpecialVariable(const char* key, return this->EmptyVariable; } if (strcmp(key, "ENV") == 0) { - char* ptr = getenv(var); - if (ptr) { + std::string str; + if (cmSystemTools::GetEnv(var, str)) { if (this->EscapeQuotes) { - return this->AddString(cmSystemTools::EscapeQuotes(ptr)); + return this->AddString(cmSystemTools::EscapeQuotes(str.c_str())); } else { - return ptr; + return this->AddString(str); } } return this->EmptyVariable; diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 67b2571..e02221c 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -486,7 +486,7 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" && argP1->GetValue().operator[](argP1len - 1) == '}') { std::string env = argP1->GetValue().substr(4, argP1len - 5); - bdef = cmSystemTools::GetEnv(env.c_str()) ? true : false; + bdef = cmSystemTools::HasEnv(env.c_str()); } else { bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); } diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 3cb575e..fc62492 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -327,11 +327,10 @@ void cmExportCommand::StorePackageRegistryDir(std::string const& package, fname += "/cmake/packages/"; fname += package; #else - const char* home = cmSystemTools::GetEnv("HOME"); - if (!home) { + std::string fname; + if (!cmSystemTools::GetEnv("HOME", fname)) { return; } - std::string fname = home; cmSystemTools::ConvertToUnixSlashes(fname); fname += "/.cmake/packages/"; fname += package; diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 16cb082..af09cd6 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -208,7 +208,8 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, // get the variables from the environment and from the cache and then // figure out which one to use: - const char* envVarValue = getenv(envVar); + std::string envVarValue; + bool envVarSet = cmSystemTools::GetEnv(envVar, envVarValue); std::string cacheEntryName = "CMAKE_ECLIPSE_ENVVAR_"; cacheEntryName += envVar; @@ -217,17 +218,17 @@ void cmExtraEclipseCDT4Generator::AddEnvVar(std::ostream& out, // now we have both, decide which one to use std::string valueToUse; - if (envVarValue == CM_NULLPTR && cacheValue == CM_NULLPTR) { + if (!envVarSet && cacheValue == CM_NULLPTR) { // nothing known, do nothing valueToUse = ""; - } else if (envVarValue != CM_NULLPTR && cacheValue == CM_NULLPTR) { + } else if (envVarSet && cacheValue == CM_NULLPTR) { // The variable is in the env, but not in the cache. Use it and put it // in the cache valueToUse = envVarValue; mf->AddCacheDefinition(cacheEntryName, valueToUse.c_str(), cacheEntryName.c_str(), cmState::STRING, true); mf->GetCMakeInstance()->SaveCache(lg->GetBinaryDirectory()); - } else if (envVarValue == CM_NULLPTR && cacheValue != CM_NULLPTR) { + } else if (!envVarSet && cacheValue != CM_NULLPTR) { // It is already in the cache, but not in the env, so use it from the cache valueToUse = cacheValue; } else { diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 5a1238b..def137e 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -1609,8 +1609,11 @@ struct cmFileInstaller : public cmFileCopier // Installation does not use source permissions by default. this->UseSourcePermissions = false; // Check whether to copy files always or only if they have changed. - this->Always = - cmSystemTools::IsOn(cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS")); + std::string install_always; + if (cmSystemTools::GetEnv("CMAKE_INSTALL_ALWAYS", install_always)) { + this->Always = + cmSystemTools::IsOn(install_always.c_str()); + } // Get the current manifest. this->Manifest = this->Makefile->GetSafeDefinition("CMAKE_INSTALL_MANIFEST_FILES"); @@ -1869,9 +1872,8 @@ bool cmFileInstaller::HandleInstallDestination() return false; } - const char* destdir = cmSystemTools::GetEnv("DESTDIR"); - if (destdir && *destdir) { - std::string sdestdir = destdir; + std::string sdestdir; + if (cmSystemTools::GetEnv("DESTDIR", sdestdir) && !sdestdir.empty()) { cmSystemTools::ConvertToUnixSlashes(sdestdir); char ch1 = destination[0]; char ch2 = destination[1]; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index d5fd75d..260079b 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -1077,8 +1077,8 @@ void cmFindPackageCommand::FillPrefixesUserRegistry() this->LabeledPaths[PathLabel::UserRegistry]); } #else - if (const char* home = cmSystemTools::GetEnv("HOME")) { - std::string dir = home; + std::string dir; + if (cmSystemTools::GetEnv("HOME", dir)) { dir += "/.cmake/packages/"; dir += this->Name; this->LoadPackageRegistryDir(dir, diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 262909f..0a83b3a 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -122,9 +122,9 @@ void cmGlobalVisualStudio7Generator::EnableLanguage( // does not use the environment it is run in, and this allows // for running commands and using dll's that the IDE environment // does not know about. - const char* extraPath = cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH"); - if (extraPath) { - mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath, + std::string extraPath; + if (cmSystemTools::GetEnv("CMAKE_MSVCIDE_RUN_PATH", extraPath)) { + mf->AddCacheDefinition("CMAKE_MSVCIDE_RUN_PATH", extraPath.c_str(), "Saved environment variable CMAKE_MSVCIDE_RUN_PATH", cmState::STATIC); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 0d550dd..ab7de57 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2572,6 +2572,7 @@ cmake::MessageType cmMakefile::ExpandVariablesInStringNew( std::string const& lookup = result.substr(var.loc); const char* value = CM_NULLPTR; std::string varresult; + std::string svalue; static const std::string lineVar = "CMAKE_CURRENT_LIST_LINE"; switch (var.domain) { case NORMAL: @@ -2584,7 +2585,9 @@ cmake::MessageType cmMakefile::ExpandVariablesInStringNew( } break; case ENVIRONMENT: - value = cmSystemTools::GetEnv(lookup.c_str()); + if (cmSystemTools::GetEnv(lookup, svalue)) { + value = svalue.c_str(); + } break; case CACHE: value = state->GetCacheEntryValue(lookup); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 1d3e608..855a243 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -741,5 +741,5 @@ bool cmNinjaTargetGenerator::ForceResponseFile() { static std::string const forceRspFile = "CMAKE_NINJA_FORCE_RESPONSE_FILE"; return (this->GetMakefile()->IsDefinitionSet(forceRspFile) || - cmSystemTools::GetEnv(forceRspFile) != CM_NULLPTR); + cmSystemTools::HasEnv(forceRspFile)); } diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 4b40c08..b821fda 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -88,7 +88,7 @@ static std::string extractSubDir(const std::string& absPath, } cmQtAutoGenerators::cmQtAutoGenerators() - : Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != CM_NULLPTR) + : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) , ColorOutput(true) , RunMocFailed(false) , RunUicFailed(false) diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index 1484368..bbea89f 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -31,7 +31,11 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, putEnvArg += "="; // what is the current value if any - const char* currValue = getenv(varName); + std::string scurrValue; + const char* currValue = 0; + if (cmSystemTools::GetEnv(varName, scurrValue)) { + currValue = scurrValue.c_str(); + } delete[] varName; // will it be set to something, then set it diff --git a/Source/cmState.cxx b/Source/cmState.cxx index f2fe134..0470508 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -1286,8 +1286,9 @@ void cmState::Snapshot::SetDefaultDefinitions() this->SetDefinition("CMAKE_HOST_UNIX", "1"); #endif #if defined(__CYGWIN__) - if (cmSystemTools::IsOn( - cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32"))) { + std::string legacy; + if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) && + cmSystemTools::IsOn(legacy.c_str())) { this->SetDefinition("WIN32", "1"); this->SetDefinition("CMAKE_HOST_WIN32", "1"); } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 2d463f3..5656c30 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -333,7 +333,12 @@ void cmSystemTools::Message(const char* m1, const char* title) s_MessageCallbackClientData); return; } else { +#if defined(_WIN32) + std::wstring wm1 = cmsys::Encoding::ToWide(m1); + std::wcerr << wm1 << std::endl << std::flush; +#else std::cerr << m1 << std::endl << std::flush; +#endif } } @@ -2069,9 +2074,9 @@ void cmSystemTools::MakefileColorEcho(int color, const char* message, // However, we can test for some situations when the answer is most // likely no. int assumeTTY = cmsysTerminal_Color_AssumeTTY; - if (cmSystemTools::GetEnv("DART_TEST_FROM_DART") || - cmSystemTools::GetEnv("DASHBOARD_TEST_FROM_CTEST") || - cmSystemTools::GetEnv("CTEST_INTERACTIVE_DEBUG_MODE")) { + if (cmSystemTools::HasEnv("DART_TEST_FROM_DART") || + cmSystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST") || + cmSystemTools::HasEnv("CTEST_INTERACTIVE_DEBUG_MODE")) { // Avoid printing color escapes during dashboard builds. assumeTTY = 0; } diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index c3c1d17..61b74db 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -93,10 +93,9 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const #else // From Linux timegm() manpage. - std::string tz_old = "TZ="; - if (const char* tz = cmSystemTools::GetEnv("TZ")) { - tz_old += tz; - } + std::string tz_old = ""; + cmSystemTools::GetEnv("TZ", tz_old); + tz_old = "TZ=" + tz_old; // The standard says that "TZ=" or "TZ=[UNRECOGNIZED_TZ]" means UTC. // It seems that "TZ=" does NOT work, at least under Windows diff --git a/Source/cmake.cxx b/Source/cmake.cxx index c597605..1fe881c 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -955,16 +955,10 @@ void cmake::SetGlobalGenerator(cmGlobalGenerator* gg) cmSystemTools::SetForceUnixPaths(this->GlobalGenerator->GetForceUnixPaths()); // Save the environment variables CXX and CC - const char* cxx = getenv("CXX"); - const char* cc = getenv("CC"); - if (cxx) { - this->CXXEnvironment = cxx; - } else { + if (!cmSystemTools::GetEnv("CXX", this->CXXEnvironment)) { this->CXXEnvironment = ""; } - if (cc) { - this->CCEnvironment = cc; - } else { + if (!cmSystemTools::GetEnv("CC", this->CCEnvironment)) { this->CCEnvironment = ""; } } @@ -1429,7 +1423,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) // should fail (if "-i" is an option). We cannot simply test // whether "-i" is given and remove it because some make programs // encode the MAKEFLAGS variable in a strange way. - if (getenv("MAKEFLAGS")) { + if (cmSystemTools::HasEnv("MAKEFLAGS")) { cmSystemTools::PutEnv("MAKEFLAGS="); } @@ -1708,8 +1702,8 @@ int cmake::CheckBuildSystem() // the make system's VERBOSE environment variable to enable verbose // output. This can be skipped by setting CMAKE_NO_VERBOSE (which is set // by the Eclipse and KDevelop generators). - bool verbose = ((cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR) && - (cmSystemTools::GetEnv("CMAKE_NO_VERBOSE") == CM_NULLPTR)); + bool verbose = ((cmSystemTools::HasEnv("VERBOSE")) && + (!cmSystemTools::HasEnv("CMAKE_NO_VERBOSE"))); // This method will check the integrity of the build system if the // option was given on the command line. It reads the given file to diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 521a5bf..efc6d52 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -127,7 +127,13 @@ static std::string cmakemainGetStack(void* clientdata) static void cmakemainMessageCallback(const char* m, const char*, bool&, void* clientdata) { +#if defined(_WIN32) + std::wstring wm = cmsys::Encoding::ToWide(m); + std::wstring wstack = cmsys::Encoding::ToWide(cmakemainGetStack(clientdata).c_str()); + std::wcerr << wm << wstack << std::endl << std::flush; +#else std::cerr << m << cmakemainGetStack(clientdata) << std::endl << std::flush; +#endif } static void cmakemainProgressCallback(const char* m, float prog, @@ -144,15 +150,41 @@ static void cmakemainProgressCallback(const char* m, float prog, } if ((prog < 0) || (!dir.empty())) { +#if defined(_WIN32) + std::wstring wm = cmsys::Encoding::ToWide(m); + std::wstring wdir = cmsys::Encoding::ToWide(dir.c_str()); + std::wstring wstack = cmsys::Encoding::ToWide(cmakemainGetStack(clientdata).c_str()); + std::wcout << L"-- " << wm << wdir << wstack << std::endl << std::flush; +#else std::cout << "-- " << m << dir << cmakemainGetStack(clientdata) - << std::endl; + << std::endl << std::flush; +#endif } - - std::cout.flush(); } int main(int ac, char const* const* av) { +#if defined(_WIN32) + // Kinda hack, with MSVC (and MinGW) for some reason std::wcout + // (and all other std::w*) fails once it encounters non-ASCII + // string unless locale is set. + // Note that even with this, seems it can't output characters + // which aren't present in ANSI codepage no matter what encoding + // is used for console. + // Currently Microsoft's C++ library doesn't support UTF-8/UTF-16 + // locales so we can only set and output in users's ANSI codepage. + // Also once any character outside of ANSI codepage is tried to + // be outputed then after there anymore won't be output from + // any of std::w* functions. + // We need to explictly set English locale because with other + // locales number parsing can differ. + // Can't use ".ACP" as it would be ANSI codepage for locale + // we're setting not the one user uses so we manually set user's + // codepage. + std::wstring locale = L"English_United States."; + locale += std::to_wstring(GetACP()); + _wsetlocale(LC_ALL, locale.c_str()); +#endif cmsys::Encoding::CommandLineArguments args = cmsys::Encoding::CommandLineArguments::Main(ac, av); ac = args.argc(); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 010a3b2..d97d72d 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -701,8 +701,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // verbose output. This can be skipped by also setting CMAKE_NO_VERBOSE // (which is set by the Eclipse and KDevelop generators). bool verbose = - ((cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR) && - (cmSystemTools::GetEnv("CMAKE_NO_VERBOSE") == CM_NULLPTR)); + ((cmSystemTools::HasEnv("VERBOSE")) && + (!cmSystemTools::HasEnv("CMAKE_NO_VERBOSE"))); // Create a cmake object instance to process dependencies. cmake cm; @@ -900,9 +900,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // 1/10th of a second after the untar. If CMAKE_UNTAR_DELAY // is set in the env, its value will be used instead of 100. int delay = 100; - const char* delayVar = cmSystemTools::GetEnv("CMAKE_UNTAR_DELAY"); - if (delayVar) { - delay = atoi(delayVar); + std::string delayVar; + if (cmSystemTools::GetEnv("CMAKE_UNTAR_DELAY", delayVar)) { + delay = atoi(delayVar.c_str()); } if (delay) { cmSystemTools::Delay(delay); @@ -1254,7 +1254,7 @@ int cmcmd::VisualStudioLink(std::vector<std::string>& args, int type) if (args.size() < 2) { return -1; } - bool verbose = cmSystemTools::GetEnv("VERBOSE") != CM_NULLPTR; + bool verbose = cmSystemTools::HasEnv("VERBOSE"); std::vector<std::string> expandedArgs; for (std::vector<std::string>::iterator i = args.begin(); i != args.end(); ++i) { diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 8b15394..cab7f38 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -709,6 +709,8 @@ IF(KWSYS_USE_Process) IF(NOT UNIX) # Use the Windows implementation. SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) + SET_PROPERTY(SOURCE ProcessWin32.c APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) ELSE() # Use the UNIX implementation. SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index c549792..659c559 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -86,7 +86,7 @@ void Directory::Clear() // First microsoft compilers -#if defined(_MSC_VER) || defined(__WATCOMC__) +#if defined(_WIN32) || defined(__WATCOMC__) #include <windows.h> #include <io.h> #include <ctype.h> diff --git a/Source/kwsys/FStream.hxx.in b/Source/kwsys/FStream.hxx.in index 681e4d8..842148d 100644 --- a/Source/kwsys/FStream.hxx.in +++ b/Source/kwsys/FStream.hxx.in @@ -17,7 +17,7 @@ namespace @KWSYS_NAMESPACE@ { -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_WIN32) # if defined(_NOEXCEPT) # define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT # else @@ -30,8 +30,23 @@ namespace @KWSYS_NAMESPACE@ typedef std::basic_filebuf<CharType,Traits> my_base_type; basic_filebuf *open(char const *s,std::ios_base::openmode mode) { + std::wstring wstr = Encoding::ToWide(s); + const wchar_t *ws = wstr.c_str(); +#if defined(_MSC_VER) && _MSC_VER >= 1400 + const wchar_t *ss = ws; +#else + const char *ss = 0; + size_t length = std::wcstombs(0, ws, 0); + if (length != size_t(-1)) { + std::vector<char> str(length + 1); + ss = str.data(); + std::wcstombs((char *)ss, ws, str.size()); + } else { + ss = s; + } +#endif return static_cast<basic_filebuf*>( - my_base_type::open(Encoding::ToWide(s).c_str(), mode) + my_base_type::open(ss, mode) ); } }; diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 2b93e69..da21cca 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -181,7 +181,7 @@ struct kwsysProcessPipeData_s /* ------------- Data managed per call to Execute ------------- */ /* Buffer for data read in this pipe's thread. */ - char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; + char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE*2]; /* The length of the data stored in the buffer. */ DWORD DataLength; @@ -319,6 +319,9 @@ struct kwsysProcess_s /* Own handles for the child's ends of the pipes in the parent process. Used temporarily during process creation. */ HANDLE PipeChildStd[3]; + + /* Console's active codepage */ + UINT codepage; }; /*--------------------------------------------------------------------------*/ @@ -1626,6 +1629,21 @@ void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td) KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index)); } + if (td->DataLength > 0) { + if (cp->codepage != KWSYS_ENCODING_DEFAULT_CODEPAGE) { + int wlength = MultiByteToWideChar(cp->codepage, 0, td->DataBuffer, td->DataLength, NULL, 0); + wchar_t* wdata = malloc(wlength * sizeof(wchar_t)); + int r = MultiByteToWideChar(cp->codepage, 0, td->DataBuffer, td->DataLength, wdata, wlength); + if (r > 0) { + r = WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wdata, wlength, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE * 2, NULL, NULL); + if (r > 0) { + td->DataLength = r; + } + } + free(wdata); + } + } + KWSYSPE_DEBUG((stderr, "read %d\n", td->Index)); /* Wait for our turn to be handled by the main thread. */ @@ -1761,6 +1779,11 @@ int kwsysProcessInitialize(kwsysProcess* cp) } } + cp->codepage = GetConsoleCP(); + if (!cp->codepage) { + cp->codepage = GetACP(); + } + return 1; } diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 81fb2f9..1af7bdb 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -219,6 +219,8 @@ typedef struct rlimit ResourceLimitType; # define USE_CPUID 0 #endif +#include <cmsys/SystemTools.hxx> + #if USE_CPUID #define CPUID_AWARE_COMPILER @@ -3476,10 +3478,10 @@ SystemInformationImplementation::GetHostMemoryAvailable(const char *hostLimitEnv // apply a limit across a set of processes. Units are in KiB. if (hostLimitEnvVarName) { - const char *hostLimitEnvVarValue=getenv(hostLimitEnvVarName); - if (hostLimitEnvVarValue) + std::string hostLimitEnvVarValue; + if (SystemTools::GetEnv(hostLimitEnvVarName, hostLimitEnvVarValue)) { - SystemInformation::LongLong hostLimit=atoLongLong(hostLimitEnvVarValue); + SystemInformation::LongLong hostLimit=atoLongLong(hostLimitEnvVarValue.c_str()); if (hostLimit>0) { memTotal=min(hostLimit,memTotal); @@ -3506,10 +3508,10 @@ SystemInformationImplementation::GetProcMemoryAvailable( // are not employed. Units are in KiB. if (procLimitEnvVarName) { - const char *procLimitEnvVarValue=getenv(procLimitEnvVarName); - if (procLimitEnvVarValue) + std::string procLimitEnvVarValue; + if (SystemTools::GetEnv(procLimitEnvVarName, procLimitEnvVarValue)) { - SystemInformation::LongLong procLimit=atoLongLong(procLimitEnvVarValue); + SystemInformation::LongLong procLimit=atoLongLong(procLimitEnvVarValue.c_str()); if (procLimit>0) { memAvail=min(procLimit,memAvail); @@ -5408,11 +5410,7 @@ bool SystemInformationImplementation::QueryOSInformation() } this->Hostname = name; - const char* arch = getenv("PROCESSOR_ARCHITECTURE"); - if(arch) - { - this->OSPlatform = arch; - } + SystemTools::GetEnv("PROCESSOR_ARCHITECTURE", this->OSPlatform); #else diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index c6e668d..c4a3311 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -421,14 +421,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) { @@ -456,22 +454,45 @@ void SystemTools::GetPath(std::vector<std::string>& path, const char* env) } } -const char* SystemTools::GetEnv(const char* key) +bool SystemTools::GetEnv(const char* key, std::string& result) { - return getenv(key); +#if defined(_WIN32) + std::wstring wkey = Encoding::ToWide(key); + wchar_t* wv = _wgetenv(wkey.c_str()); + if (wv) { + result = Encoding::ToNarrow(wv); + return true; + } + return false; +#else + const char* v = getenv(key); + if(v) + { + result = v; + return true; + } + else + { + return false; + } +#endif } -const char* SystemTools::GetEnv(const std::string& key) +bool SystemTools::GetEnv(const std::string& key, std::string& result) { - return SystemTools::GetEnv(key.c_str()); + return SystemTools::GetEnv(key.c_str(), result); } -bool SystemTools::GetEnv(const char* key, std::string& result) +bool SystemTools::HasEnv(const char* key) { +#if defined(_WIN32) + std::wstring wkey = Encoding::ToWide(key); + wchar_t* v = _wgetenv(wkey.c_str()); +#else const char* v = getenv(key); +#endif if(v) { - result = v; return true; } else @@ -480,9 +501,9 @@ bool SystemTools::GetEnv(const char* key, std::string& result) } } -bool SystemTools::GetEnv(const std::string& key, std::string& result) +bool SystemTools::HasEnv(const std::string& key) { - return SystemTools::GetEnv(key.c_str(), result); + return SystemTools::HasEnv(key.c_str()); } //---------------------------------------------------------------------------- @@ -533,13 +554,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) + std::wstring wbuf = Encoding::ToWide(buf); + int r = _wputenv(wbuf.c_str()); +#else + int r = putenv(buf); +#endif + if(r < 0) { err = errno; } # else buf[len] = 0; - if(putenv(buf) < 0 && errno != EINVAL) +#if defined(_WIN32) + std::wstring wbuf = Encoding::ToWide(buf); + int r = _wputenv(wbuf.c_str()); +#else + int r = putenv(buf); +#endif + if(r < 0 && errno != EINVAL) { err = errno; } @@ -679,7 +712,12 @@ public: static_cast<void>(oldEnv); char* newEnv = strdup(env); this->insert(newEnv); +#if defined(_WIN32) + std::wstring wEnv = Encoding::ToWide(newEnv); + return _wputenv(wEnv.c_str()) == 0; +#else return putenv(newEnv) == 0; +#endif } bool UnPut(const char* env) { @@ -2044,8 +2082,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 +4099,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 +4842,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 +4851,11 @@ int SystemTools::GetTerminalWidth() { width = -1; } - columns = getenv("COLUMNS"); - if(columns && *columns) + if(SystemTools::GetEnv("COLUMNS", columns)) { 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); @@ -5435,7 +5465,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 +5478,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. @@ -5505,8 +5535,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); } diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index bba5a5c..643f0ca 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -839,10 +839,10 @@ public: /** * Read an environment variable */ - static const char* GetEnv(const char* key); - 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 */ diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 4d97688..0fcc561 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -848,9 +848,9 @@ static bool CheckPutEnv(const std::string& env, const char* name, const char* va << "\") failed!" << std::endl; return false; } - const char* v = kwsys::SystemTools::GetEnv(name); - v = v? v : "(null)"; - if(strcmp(v, value) != 0) + std::string v = "(null)"; + kwsys::SystemTools::GetEnv(name, v); + if(strcmp(v.c_str(), value) != 0) { std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \"" << value << "\"!" << std::endl; @@ -867,7 +867,8 @@ static bool CheckUnPutEnv(const char* env, const char* name) << std::endl; return false; } - if(const char* v = kwsys::SystemTools::GetEnv(name)) + std::string v; + if(kwsys::SystemTools::GetEnv(name, v)) { std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not (null)!" << std::endl; -- 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