|
@@ -49,6 +49,7 @@
|
|
|
#include <string.h>
|
|
#include <string.h>
|
|
|
#include <time.h>
|
|
#include <time.h>
|
|
|
#include <utility>
|
|
#include <utility>
|
|
|
|
|
+#include <vector>
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
#if defined(_WIN32)
|
|
|
# include <windows.h>
|
|
# include <windows.h>
|
|
@@ -1463,6 +1464,80 @@ std::string cmSystemTools::RelativePath(std::string const& local,
|
|
|
return cmsys::SystemTools::RelativePath(local, remote);
|
|
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 cmSystemTools::CollapseCombinedPath(std::string const& dir,
|
|
|
std::string const& file)
|
|
std::string const& file)
|
|
|
{
|
|
{
|