From 854feacc60c5d1dcf53652a764841e1d9d602ac3 Mon Sep 17 00:00:00 2001 From: KWSys Upstream Date: Thu, 1 Feb 2018 07:44:45 -0500 Subject: KWSys 2018-02-01 (04fcc449) Code extracted from: https://gitlab.kitware.com/utils/kwsys.git at commit 04fcc449646eb2ff3d701986946a1db60b2161b7 (master). Upstream Shortlog ----------------- Ben Boeckel (11): ba270398 SystemToolsAppendComponents: move strings when building components cfd0f1e6 JoinPath: push back as a character 6770cb3e GetFilenameName: optionally don't search for \ on non-Windows 22b189b0 ConvertToUnixSlashes: remove escaped space logic 342d69a4 ConvertToUnixSlashes: short-circuit on hasDoubleSlash 5dd87350 ConvertToUnixSlashes: remove pos1 3b46b7c0 ConvertToUnixSlashes: bail early on empty paths 55d1d6ab CollapseFullPath: reserve space for components 68807138 CollapseFullPath: prefer .empty() to .length() == 0 71a6de42 CollapseFullPath: refactor the overloads to share implementations 318550c7 CheckCollapsePath: add more test cases --- CMakeLists.txt | 10 ++++ SystemTools.cxx | 141 ++++++++++++++++++++-------------------------------- testSystemTools.cxx | 36 ++++++++++---- 3 files changed, 89 insertions(+), 98 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2570e5b..c0154c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,6 +496,16 @@ IF(KWSYS_USE_SystemTools) KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM} KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC} ) + IF(NOT WIN32) + IF(KWSYS_STANDALONE) + OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) + ENDIF() + IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES + ) + ENDIF() + ENDIF() # Disable getpwnam for static linux builds since it depends on shared glibc GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) diff --git a/SystemTools.cxx b/SystemTools.cxx index 999beb3..38910c8 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -1884,21 +1884,23 @@ static void ConvertVMSToUnix(std::string& path) // convert windows slashes to unix slashes void SystemTools::ConvertToUnixSlashes(std::string& path) { + if (path.empty()) { + return; + } + const char* pathCString = path.c_str(); bool hasDoubleSlash = false; #ifdef __VMS ConvertVMSToUnix(path); #else const char* pos0 = pathCString; - const char* pos1 = pathCString + 1; for (std::string::size_type pos = 0; *pos0; ++pos) { - // make sure we don't convert an escaped space to a unix slash - if (*pos0 == '\\' && *pos1 != ' ') { + if (*pos0 == '\\') { path[pos] = '/'; } // Also, reuse the loop to check for slash followed by another slash - if (*pos1 == '/' && *(pos1 + 1) == '/' && !hasDoubleSlash) { + if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') { #ifdef _WIN32 // However, on windows if the first characters are both slashes, // then keep them that way, so that network paths can be handled. @@ -1911,43 +1913,41 @@ void SystemTools::ConvertToUnixSlashes(std::string& path) } pos0++; - pos1++; } if (hasDoubleSlash) { SystemTools::ReplaceString(path, "//", "/"); } #endif + // remove any trailing slash - if (!path.empty()) { - // if there is a tilda ~ then replace it with HOME - pathCString = path.c_str(); - if (pathCString[0] == '~' && - (pathCString[1] == '/' || pathCString[1] == '\0')) { - std::string homeEnv; - if (SystemTools::GetEnv("HOME", homeEnv)) { - path.replace(0, 1, homeEnv); - } + // if there is a tilda ~ then replace it with HOME + pathCString = path.c_str(); + if (pathCString[0] == '~' && + (pathCString[1] == '/' || pathCString[1] == '\0')) { + std::string homeEnv; + if (SystemTools::GetEnv("HOME", homeEnv)) { + path.replace(0, 1, homeEnv); } + } #ifdef HAVE_GETPWNAM - else if (pathCString[0] == '~') { - std::string::size_type idx = path.find_first_of("/\0"); - std::string user = path.substr(1, idx - 1); - passwd* pw = getpwnam(user.c_str()); - if (pw) { - path.replace(0, idx, pw->pw_dir); - } + else if (pathCString[0] == '~') { + std::string::size_type idx = path.find_first_of("/\0"); + std::string user = path.substr(1, idx - 1); + passwd* pw = getpwnam(user.c_str()); + if (pw) { + path.replace(0, idx, pw->pw_dir); } + } #endif - // remove trailing slash if the path is more than - // a single / - pathCString = path.c_str(); - size_t size = path.size(); - if (size > 1 && *path.rbegin() == '/') { - // if it is c:/ then do not remove the trailing slash - if (!((size == 3 && pathCString[1] == ':'))) { - path.resize(size - 1); - } + // remove trailing slash if the path is more than + // a single / + pathCString = path.c_str(); + size_t size = path.size(); + if (size > 1 && *path.rbegin() == '/') { + // if it is c:/ then do not remove the trailing slash + if (!((size == 3 && pathCString[1] == ':'))) { + path.resize(size - 1); } } } @@ -3171,8 +3171,8 @@ void SystemTools::CheckTranslationPath(std::string& path) static void SystemToolsAppendComponents( std::vector& out_components, - std::vector::const_iterator first, - std::vector::const_iterator last) + std::vector::iterator first, + std::vector::iterator last) { static const std::string up = ".."; static const std::string cur = "."; @@ -3182,7 +3182,11 @@ static void SystemToolsAppendComponents( out_components.resize(out_components.size() - 1); } } else if (!i->empty() && *i != cur) { +#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) + out_components.push_back(std::move(*i)); +#else out_components.push_back(*i); +#endif } } } @@ -3190,63 +3194,18 @@ static void SystemToolsAppendComponents( std::string SystemTools::CollapseFullPath(const std::string& in_path, const char* in_base) { - // Collect the output path components. - std::vector out_components; - - // Split the input path components. - std::vector path_components; - SystemTools::SplitPath(in_path, path_components); - - // If the input path is relative, start with a base path. - if (path_components[0].empty()) { - std::vector base_components; - if (in_base) { - // Use the given base path. - SystemTools::SplitPath(in_base, base_components); + // Use the current working directory as a base path. + char buf[2048]; + const char* res_in_base = in_base; + if (!res_in_base) { + if (const char* cwd = Getcwd(buf, 2048)) { + res_in_base = cwd; } else { - // Use the current working directory as a base path. - char buf[2048]; - if (const char* cwd = Getcwd(buf, 2048)) { - SystemTools::SplitPath(cwd, base_components); - } else { - base_components.push_back(""); - } + res_in_base = ""; } - - // Append base path components to the output path. - out_components.push_back(base_components[0]); - SystemToolsAppendComponents(out_components, base_components.begin() + 1, - base_components.end()); } - // Append input path components to the output path. - SystemToolsAppendComponents(out_components, path_components.begin(), - path_components.end()); - - // Transform the path back to a string. - std::string newPath = SystemTools::JoinPath(out_components); - - // Update the translation table with this potentially new path. I am not - // sure why this line is here, it seems really questionable, but yet I - // would put good money that if I remove it something will break, basically - // from what I can see it created a mapping from the collapsed path, to be - // replaced by the input path, which almost completely does the opposite of - // this function, the only thing preventing this from happening a lot is - // that if the in_path has a .. in it, then it is not added to the - // translation table. So for most calls this either does nothing due to the - // .. or it adds a translation between identical paths as nothing was - // collapsed, so I am going to try to comment it out, and see what hits the - // fan, hopefully quickly. - // Commented out line below: - // SystemTools::AddTranslationPath(newPath, in_path); - - SystemTools::CheckTranslationPath(newPath); -#ifdef _WIN32 - newPath = SystemTools::GetActualCaseForPath(newPath); - SystemTools::ConvertToUnixSlashes(newPath); -#endif - // Return the reconstructed path. - return newPath; + return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); } std::string SystemTools::CollapseFullPath(const std::string& in_path, @@ -3258,9 +3217,10 @@ std::string SystemTools::CollapseFullPath(const std::string& in_path, // Split the input path components. std::vector path_components; SystemTools::SplitPath(in_path, path_components); + out_components.reserve(path_components.size()); // If the input path is relative, start with a base path. - if (path_components[0].length() == 0) { + if (path_components[0].empty()) { std::vector base_components; // Use the given base path. SystemTools::SplitPath(in_base, base_components); @@ -3619,7 +3579,7 @@ std::string SystemTools::JoinPath( // All remaining components are always separated with a slash. while (first != last) { - result.append("/"); + result.push_back('/'); result.append((*first++)); } @@ -3715,7 +3675,12 @@ std::string SystemTools::GetFilenamePath(const std::string& filename) */ std::string SystemTools::GetFilenameName(const std::string& filename) { - std::string::size_type slash_pos = filename.find_last_of("/\\"); +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + const char* separators = "/\\"; +#else + char separators = '/'; +#endif + std::string::size_type slash_pos = filename.find_last_of(separators); if (slash_pos != std::string::npos) { return filename.substr(slash_pos + 1); } else { diff --git a/testSystemTools.cxx b/testSystemTools.cxx index f1321e5..e436a2b 100644 --- a/testSystemTools.cxx +++ b/testSystemTools.cxx @@ -39,19 +39,19 @@ typedef unsigned short mode_t; static const char* toUnixPaths[][2] = { { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" }, + { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" }, + { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo\\ cal/bin/pa\\ sswd" }, + { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo\\ cal/bin/pa\\ sswd" }, + { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, - { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo\\ cal/bin/pa\\ sswd" }, + { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, { KWSYS_NULLPTR, KWSYS_NULLPTR } }; @@ -700,6 +700,16 @@ static bool CheckCollapsePath() bool res = true; res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); + res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); + res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); + res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); + res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); + res &= CheckCollapsePath("/../lib", "/lib"); + res &= CheckCollapsePath("/../lib/", "/lib"); + res &= CheckCollapsePath("/", "/"); + res &= CheckCollapsePath("C:/", "C:/"); + res &= CheckCollapsePath("C:/../", "C:/"); + res &= CheckCollapsePath("C:/../../", "C:/"); return res; } @@ -764,20 +774,26 @@ static bool CheckGetFilenameName() const char* windowsFilepath = "C:\\somewhere\\something"; const char* unixFilepath = "/somewhere/something"; - std::string expectedFilename = "something"; +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + std::string expectedWindowsFilename = "something"; +#else + std::string expectedWindowsFilename = "C:\\somewhere\\something"; +#endif + std::string expectedUnixFilename = "something"; bool res = true; std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); - if (filename != expectedFilename) { + if (filename != expectedWindowsFilename) { std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " - << filename << " instead of " << expectedFilename << std::endl; + << filename << " instead of " << expectedWindowsFilename + << std::endl; res = false; } filename = kwsys::SystemTools::GetFilenameName(unixFilepath); - if (filename != expectedFilename) { + if (filename != expectedUnixFilename) { std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename - << " instead of " << expectedFilename << std::endl; + << " instead of " << expectedUnixFilename << std::endl; res = false; } return res; -- cgit v0.12