about summary refs log tree commit diff
path: root/src/util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cc')
-rw-r--r--src/util.cc38
1 files changed, 33 insertions, 5 deletions
diff --git a/src/util.cc b/src/util.cc
index 8ccd3c1524d8..00a3063d6d13 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;
 }