summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2013-03-12 16:35:32 (GMT)
committerMarius Kintel <marius@kintel.net>2013-03-12 16:35:32 (GMT)
commit5628a18f6a0fcf2dd170cac31e386f1ad4f97c0c (patch)
treebaf407ed0a29cca328236ad2cc15e985ad44bf34
parentdccc039211eebe3f69c935557bd56abae323c26f (diff)
boostfs_relative_path was buggy, replaced with boostfs_uncomplete for now
-rw-r--r--src/boost-utils.cc128
-rw-r--r--src/boost-utils.h7
-rw-r--r--src/dxfdata.cc4
-rw-r--r--src/value.cc2
4 files changed, 135 insertions, 6 deletions
diff --git a/src/boost-utils.cc b/src/boost-utils.cc
index f81917a..5127047 100644
--- a/src/boost-utils.cc
+++ b/src/boost-utils.cc
@@ -2,10 +2,12 @@
#include <stdio.h>
#include <iostream>
-fs::path relativePath(const fs::path &path, const fs::path &relative_to)
+// If the given (absolute) path is relative to the relative_to path, return a new
+// relative path. Will normalize the given path first
+fs::path boostfs_relative_path(const fs::path &path, const fs::path &relative_to)
{
// create absolute paths
- fs::path p = fs::absolute(path);
+ fs::path p = fs::absolute(boostfs_normalize(path));
fs::path r = fs::absolute(relative_to);
// if root paths are different, return absolute path
@@ -40,3 +42,125 @@ fs::path relativePath(const fs::path &path, const fs::path &relative_to)
return result;
}
+
+// Will normalize the given path, i.e. remove any redundant ".." path elements.
+fs::path boostfs_normalize(const fs::path &path)
+{
+ fs::path absPath = absolute(path);
+ fs::path::iterator it = absPath.begin();
+ fs::path result = *it++;
+
+ // Get canonical version of the existing part
+ for(;exists(result) && it != absPath.end(); ++it) {
+ result /= *it;
+ }
+ result = canonical(result.parent_path());
+ --it;
+
+ // For the rest remove ".." and "." in a path with no symlinks
+ for (; it != absPath.end(); ++it) {
+ // Just move back on ../
+ if (*it == "..") {
+ result = result.parent_path();
+ }
+ // Ignore "."
+ else if (*it != ".") {
+ // Just cat other path entries
+ result /= *it;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * https://svn.boost.org/trac/boost/ticket/1976#comment:2
+ *
+ * "The idea: uncomplete(/foo/new, /foo/bar) => ../new
+ * The use case for this is any time you get a full path (from an open dialog, perhaps)
+ * and want to store a relative path so that the group of files can be moved to a different
+ * directory without breaking the paths. An IDE would be a simple example, so that the
+ * project file could be safely checked out of subversion."
+ *
+ * ALGORITHM:
+ * iterate path and base
+ * compare all elements so far of path and base
+ * whilst they are the same, no write to output
+x2 * when they change, or one runs out:
+ * write to output, ../ times the number of remaining elements in base
+ * write to output, the remaining elements in path
+ */
+fs::path
+boostfs_uncomplete(fs::path const p, fs::path const base)
+{
+ if (p == base) return "./";
+ /*!! this breaks stuff if path is a filename rather than a directory,
+ which it most likely is... but then base shouldn't be a filename so... */
+
+ // create absolute paths
+ fs::path abs_p = fs::absolute(boostfs_normalize(p));
+ fs::path abs_base = fs::absolute(base);
+
+ fs::path from_path, from_base, output;
+
+ fs::path::iterator path_it = abs_p.begin(), path_end = abs_p.end();
+ fs::path::iterator base_it = abs_base.begin(), base_end = abs_base.end();
+
+ // check for emptiness
+ if ((path_it == path_end) || (base_it == base_end)) {
+ throw std::runtime_error("path or base was empty; couldn't generate relative path");
+ }
+
+#ifdef WIN32
+ // drive letters are different; don't generate a relative path
+ if (*path_it != *base_it) return p;
+
+ // now advance past drive letters; relative paths should only go up
+ // to the root of the drive and not past it
+ ++path_it, ++base_it;
+#endif
+
+ // Cache system-dependent dot, double-dot and slash strings
+ const std::string _dot = ".";
+ const std::string _dots = "..";
+ const std::string _sep = "/";
+
+ // iterate over path and base
+ while (true) {
+
+ // compare all elements so far of path and base to find greatest common root;
+ // when elements of path and base differ, or run out:
+ if ((path_it == path_end) || (base_it == base_end) || (*path_it != *base_it)) {
+
+ // write to output, ../ times the number of remaining elements in base;
+ // this is how far we've had to come down the tree from base to get to the common root
+ for (; base_it != base_end; ++base_it) {
+ if (*base_it == _dot)
+ continue;
+ else if (*base_it == _sep)
+ continue;
+
+ output /= "../";
+ }
+
+ // write to output, the remaining elements in path;
+ // this is the path relative from the common root
+ fs::path::iterator path_it_start = path_it;
+ for (; path_it != path_end; ++path_it) {
+ if (path_it != path_it_start) output /= "/";
+ if (*path_it == _dot) continue;
+ if (*path_it == _sep) continue;
+ output /= *path_it;
+ }
+ break;
+ }
+
+ // add directory level to both paths and continue iteration
+ from_path /= fs::path(*path_it);
+ from_base /= fs::path(*base_it);
+
+ ++path_it, ++base_it;
+ }
+
+ return output;
+}
diff --git a/src/boost-utils.h b/src/boost-utils.h
index c431857..3678ecc 100644
--- a/src/boost-utils.h
+++ b/src/boost-utils.h
@@ -3,6 +3,11 @@
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
-fs::path relativePath(const fs::path &path, const fs::path &relative_to);
+
+// FIXME: boostfs_relative_path() has been replaced by
+// boostfs_uncomplete(), but kept around for now.
+fs::path boostfs_relative_path(const fs::path &path, const fs::path &relative_to);
+fs::path boostfs_normalize(const fs::path &path);
+fs::path boostfs_uncomplete(fs::path const p, fs::path const base);
#endif
diff --git a/src/dxfdata.cc b/src/dxfdata.cc
index be982ff..8415228 100644
--- a/src/dxfdata.cc
+++ b/src/dxfdata.cc
@@ -390,10 +390,10 @@ DxfData::DxfData(double fn, double fs, double fa,
BOOST_FOREACH(const EntityList::value_type &i, unsupported_entities_list) {
if (layername.empty()) {
PRINTB("WARNING: Unsupported DXF Entity '%s' (%x) in %s.",
- i.first % i.second % QuotedString(boosty::stringy(relativePath(filename, fs::current_path()))));
+ i.first % i.second % QuotedString(boosty::stringy(boostfs_uncomplete(filename, fs::current_path()))));
} else {
PRINTB("WARNING: Unsupported DXF Entity '%s' (%x) in layer '%s' of %s.",
- i.first % i.second % layername % QuotedString(boosty::stringy(relativePath(filename, fs::current_path()))));
+ i.first % i.second % layername % QuotedString(boosty::stringy(boostfs_uncomplete(filename, fs::current_path()))));
}
}
diff --git a/src/value.cc b/src/value.cc
index bec803a..ae810a2 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -39,7 +39,7 @@
std::ostream &operator<<(std::ostream &stream, const Filename &filename)
{
- stream << QuotedString(boosty::stringy(relativePath(filename, fs::current_path())));
+ stream << QuotedString(boosty::stringy(boostfs_uncomplete(filename, fs::current_path())));
return stream;
}
contact: Jan Huwald // Impressum