* 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.
This commit is contained in:
Eelco Dolstra 2003-07-08 19:58:41 +00:00
parent 333f4963de
commit cab3f4977a
2 changed files with 42 additions and 5 deletions

View file

@ -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

View file

@ -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;
}