diff options
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r-- | Source/cmSystemTools.cxx | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 6fbe482..be65853 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -49,6 +49,7 @@ #include <string.h> #include <time.h> #include <utility> +#include <vector> #if defined(_WIN32) # include <windows.h> @@ -1463,6 +1464,80 @@ std::string cmSystemTools::RelativePath(std::string const& local, return cmsys::SystemTools::RelativePath(local, remote); } +std::string cmSystemTools::ForceToRelativePath(std::string const& local_path, + std::string const& remote_path) +{ + // The paths should never be quoted. + assert(local_path.front() != '\"'); + assert(remote_path.front() != '\"'); + + // The local path should never have a trailing slash. + assert(local_path.empty() || local_path.back() != '/'); + + // If the path is already relative then just return the path. + if (!cmSystemTools::FileIsFullPath(remote_path)) { + return remote_path; + } + + // Identify the longest shared path component between the remote + // path and the local path. + std::vector<std::string> local; + cmSystemTools::SplitPath(local_path, local); + std::vector<std::string> remote; + cmSystemTools::SplitPath(remote_path, remote); + unsigned int common = 0; + while (common < remote.size() && common < local.size() && + cmSystemTools::ComparePath(remote[common], local[common])) { + ++common; + } + + // If no part of the path is in common then return the full path. + if (common == 0) { + return remote_path; + } + + // If the entire path is in common then just return a ".". + if (common == remote.size() && common == local.size()) { + return "."; + } + + // If the entire path is in common except for a trailing slash then + // just return a "./". + if (common + 1 == remote.size() && remote[common].empty() && + common == local.size()) { + return "./"; + } + + // Construct the relative path. + std::string relative; + + // First add enough ../ to get up to the level of the shared portion + // of the path. Leave off the trailing slash. Note that the last + // component of local will never be empty because local should never + // have a trailing slash. + for (unsigned int i = common; i < local.size(); ++i) { + relative += ".."; + if (i < local.size() - 1) { + relative += "/"; + } + } + + // Now add the portion of the destination path that is not included + // in the shared portion of the path. Add a slash the first time + // only if there was already something in the path. If there was a + // trailing slash in the input then the last iteration of the loop + // will add a slash followed by an empty string which will preserve + // the trailing slash in the output. + + if (!relative.empty() && !remote.empty()) { + relative += "/"; + } + relative += cmJoin(cmMakeRange(remote).advance(common), "/"); + + // Finally return the path. + return relative; +} + std::string cmSystemTools::CollapseCombinedPath(std::string const& dir, std::string const& file) { |