summaryrefslogtreecommitdiffstats
path: root/Source/cmSystemTools.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r--Source/cmSystemTools.cxx75
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)
{