about summary refs log tree commit diff
path: root/src/util.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2003-07-08T19·58+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2003-07-08T19·58+0000
commitcab3f4977a412681a77767ec7307ee642b61332d (patch)
tree469274938dd5a59f93dad4f4e8dffa5f27593c80 /src/util.cc
parent333f4963de6d174d852774a88ada852f77f57994 (diff)
* A path canonicaliser that doesn't depend on the existence of paths
  (i.e., it doesn't use realpath(3), which is broken in any case).
  Therefore it doesn't resolve symlinks.

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 8ccd3c1524..00a3063d6d 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;
 }