aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/test.cc9
-rw-r--r--src/util.cc38
2 files changed, 42 insertions, 5 deletions
diff --git a/src/test.cc b/src/test.cc
index b30a5b0e9..c2a1cd3bf 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -71,6 +71,15 @@ void runTests()
abort();
} catch (BadRefError err) { };
+ /* Path canonicalisation. */
+ cout << canonPath("/./../././//") << endl;
+ cout << canonPath("/foo/bar") << endl;
+ cout << canonPath("///foo/////bar//") << endl;
+ cout << canonPath("/././/foo/////bar//.") << endl;
+ cout << canonPath("/foo////bar//..///x/") << endl;
+ cout << canonPath("/foo////bar//..//..//x/y/../z/") << endl;
+ cout << canonPath("/foo/bar/../../../..///") << endl;
+
/* Dumping. */
#if 0
diff --git a/src/util.cc b/src/util.cc
index 8ccd3c152..00a3063d6 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -40,11 +40,39 @@ string absPath(string path, string dir)
string canonPath(const string & path)
{
- char resolved[PATH_MAX];
- if (!realpath(path.c_str(), resolved))
- throw SysError(format("cannot canonicalise path `%1%'") % path);
- /* !!! check that this removes trailing slashes */
- return resolved;
+ string s;
+
+ if (path[0] != '/')
+ throw Error(format("not an absolute path: `%1%'") % path);
+
+ string::const_iterator i = path.begin(), end = path.end();
+
+ while (1) {
+
+ /* Skip slashes. */
+ while (i != end && *i == '/') i++;
+ if (i == end) break;
+
+ /* Ignore `.'. */
+ if (*i == '.' && (i + 1 == end || i[1] == '/'))
+ i++;
+
+ /* If `..', delete the last component. */
+ else if (*i == '.' && i + 1 < end && i[1] == '.' &&
+ (i + 2 == end || i[2] == '/'))
+ {
+ if (!s.empty()) s.erase(s.rfind('/'));
+ i += 2;
+ }
+
+ /* Normal component; copy it. */
+ else {
+ s += '/';
+ while (i != end && *i != '/') s += *i++;
+ }
+ }
+
+ return s.empty() ? "/" : s;
}