aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2016-11-30 11:47:27 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2016-12-05 14:04:01 +0300
commite7b033d7b38bc55f934521b5f35060b43a8b0526 (patch)
tree52a99420086e7e86ac99ef4b2b96bd210504cf01
parentcf8f3b830789a6bcc538d2f4d0e8a1425a110c47 (diff)
Make path::normalize() to preserve ./, invalidate paths starting with \, / on Windows
-rw-r--r--butl/buildfile1
-rw-r--r--butl/path8
-rw-r--r--butl/path.txx26
-rw-r--r--butl/process.cxx28
-rw-r--r--tests/dir-iterator/buildfile3
-rw-r--r--tests/dir-iterator/testscript16
-rw-r--r--tests/path/driver.cxx88
7 files changed, 112 insertions, 58 deletions
diff --git a/butl/buildfile b/butl/buildfile
index 5c5aae3..6e259c8 100644
--- a/butl/buildfile
+++ b/butl/buildfile
@@ -21,6 +21,7 @@ lib{butl}: \
{hxx txx }{ prefix-map } \
{hxx ixx cxx}{ process } \
{hxx cxx}{ sha256 } \
+{hxx }{ small-vector } \
{hxx txx }{ string-table } \
{hxx cxx}{ timestamp } \
{hxx cxx}{ triplet } \
diff --git a/butl/path b/butl/path
index 2a32c70..2e243ff 100644
--- a/butl/path
+++ b/butl/path
@@ -808,7 +808,11 @@ namespace butl
// Normalize the path and return *this. Normalization involves collapsing
// the '.' and '..' directories if possible, collapsing multiple
// directory separators, and converting all directory separators to the
- // canonical form.
+ // canonical form. If cur_empty is true then collapse relative paths
+ // representing the current directory (for example, '.', './', 'foo/..')
+ // to an empty path. Otherwise convert it to the canonical form (./ on
+ // POSIX systems). Note that a non-empty path cannot become an empty one
+ // in the latter case.
//
// If actual is true, then for case-insensitive filesystems obtain the
// actual spelling of the path. Only an absolute path can be actualized.
@@ -818,7 +822,7 @@ namespace butl
// etc.) are returned in their actual spelling.
//
basic_path&
- normalize (bool actual = false);
+ normalize (bool actual = false, bool cur_empty = false);
// Make the path absolute using the current directory unless it is already
// absolute. Return *this.
diff --git a/butl/path.txx b/butl/path.txx
index 5bcaea0..0cdaf5b 100644
--- a/butl/path.txx
+++ b/butl/path.txx
@@ -147,7 +147,7 @@ namespace butl
template <typename C, typename K>
basic_path<C, K>& basic_path<C, K>::
- normalize (bool actual)
+ normalize (bool actual, bool cur_empty)
{
if (empty ())
return *this;
@@ -273,12 +273,24 @@ namespace butl
p += traits::directory_separator;
}
- if (tsep && (!p.empty () || abs)) // Distinguish "/"-empty and "."-empty.
+ if (tsep)
{
if (p.empty ())
{
- p += traits::directory_separator;
- ts = -1;
+ // Distinguish "/"-empty and "."-empty.
+ //
+ if (abs)
+ {
+ p += traits::directory_separator;
+ ts = -1;
+ }
+ else if (!cur_empty) // Collapse to canonical current directory.
+ {
+ p = ".";
+ ts = 1; // Canonical separator is always first.
+ }
+ else // Collapse to empty path.
+ ts = 0;
}
else
ts = 1; // Canonical separator is always first.
@@ -313,11 +325,11 @@ namespace butl
#ifdef _WIN32
// We do not support any special Windows path name notations like in C:abc,
- // \\?\c:\abc, \\server\abc and \\?\UNC\server\abc (more about them at
- // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx).
+ // /, \, /abc, \abc, \\?\c:\abc, \\server\abc and \\?\UNC\server\abc (more
+ // about them in "Naming Files, Paths, and Namespaces" MSDN article).
//
if ((n > 2 && s[1] == ':' && s[2] != '\\' && s[2] != '/') ||
- (n > 1 && s[0] == '\\' && s[1] == '\\'))
+ (n > 0 && (s[0] == '\\' || s[0] == '/')))
{
if (exact)
return data_type ();
diff --git a/butl/process.cxx b/butl/process.cxx
index c75cfbd..cf4b26d 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -171,7 +171,7 @@ namespace butl
ep = path (move (s)); // Move back into result.
if (norm)
- ep.normalize (); //@@ NORM
+ ep.normalize ();
return exists (ep.string ().c_str ());
};
@@ -212,10 +212,17 @@ namespace butl
e = strchr (b, traits::path_separator);
// Empty path (i.e., a double colon or a colon at the beginning or end
- // of PATH) means search in the current dirrectory.
+ // of PATH) means search in the current dirrectory. Silently skip
+ // invalid paths.
//
- if (search (b, e != nullptr ? e - b : strlen (b)))
- return r;
+ try
+ {
+ if (search (b, e != nullptr ? e - b : strlen (b)))
+ return r;
+ }
+ catch (const invalid_path&)
+ {
+ }
}
// If we were given a fallback, try that.
@@ -575,10 +582,17 @@ namespace butl
e = strchr (b, traits::path_separator);
// Empty path (i.e., a double colon or a colon at the beginning or end
- // of PATH) means search in the current dirrectory.
+ // of PATH) means search in the current dirrectory. Silently skip
+ // invalid paths.
//
- if (search (b, e != nullptr ? e - b : strlen (b)))
- return r;
+ try
+ {
+ if (search (b, e != nullptr ? e - b : strlen (b)))
+ return r;
+ }
+ catch (const invalid_path&)
+ {
+ }
}
// Finally, if we were given a fallback, try that. This case is similar to
diff --git a/tests/dir-iterator/buildfile b/tests/dir-iterator/buildfile
index 5c8736e..fe310ad 100644
--- a/tests/dir-iterator/buildfile
+++ b/tests/dir-iterator/buildfile
@@ -2,7 +2,6 @@
# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-exe{driver}: cxx{driver} ../../butl/lib{butl}
-exe{driver}: test.arguments = $src_root
+exe{driver}: cxx{driver} ../../butl/lib{butl} test{testscript}
include ../../butl/
diff --git a/tests/dir-iterator/testscript b/tests/dir-iterator/testscript
new file mode 100644
index 0000000..42dc1fa
--- /dev/null
+++ b/tests/dir-iterator/testscript
@@ -0,0 +1,16 @@
+# file : tests/dir-iterator/testscript
+# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+test.options = -v
+
+: file
+:
+mkdir a;
+touch a/b;
+$* a 2>"reg b"
+
+: dir
+:
+mkdir -p a/b;
+$* a 2>"dir b"
diff --git a/tests/path/driver.cxx b/tests/path/driver.cxx
index fbcaf33..fe192ce 100644
--- a/tests/path/driver.cxx
+++ b/tests/path/driver.cxx
@@ -42,28 +42,24 @@ main ()
return x.string () == s && x.representation () == r;
};
+#ifndef _WIN32
assert (test ("/", "/", "/"));
assert (test ("//", "/", "/"));
assert (test ("/tmp/foo", "/tmp/foo", "/tmp/foo"));
assert (test ("/tmp/foo/", "/tmp/foo", "/tmp/foo/"));
assert (test ("/tmp/foo//", "/tmp/foo", "/tmp/foo/"));
-#ifdef _WIN32
- assert (test ("/\\", "/", "/"));
+ assert (dir_test ("/", "/", "/"));
+ assert (dir_test ("/tmp/foo/", "/tmp/foo", "/tmp/foo/"));
+ assert (dir_test ("tmp/foo", "tmp/foo", "tmp/foo/"));
+#else
assert (test ("C:", "C:", "C:"));
assert (test ("C:\\", "C:", "C:\\"));
assert (test ("c:/", "c:", "c:/"));
assert (test ("C:\\tmp\\foo\\", "C:\\tmp\\foo", "C:\\tmp\\foo\\"));
assert (test ("C:\\tmp\\foo\\/\\", "C:\\tmp\\foo", "C:\\tmp\\foo\\"));
-#endif
- assert (dir_test ("/", "/", "/"));
- assert (dir_test ("/tmp/foo/", "/tmp/foo", "/tmp/foo/"));
-#ifndef _WIN32
- assert (dir_test ("tmp/foo", "tmp/foo", "tmp/foo/"));
-#else
assert (dir_test ("tmp\\foo", "tmp\\foo", "tmp\\foo\\"));
-
assert (dir_test ("C:\\", "C:", "C:\\"));
assert (dir_test ("C:\\tmp/foo\\", "C:\\tmp/foo", "C:\\tmp/foo\\"));
assert (dir_test ("c:/tmp\\foo", "c:/tmp\\foo", "c:/tmp\\foo\\"));
@@ -131,13 +127,15 @@ main ()
// base
//
+ assert (path (".txt").base ().representation () == ".txt");
+ assert (path ("foo.txt.orig").base ().representation () == "foo.txt");
+
+#ifndef _WIN32
assert (path ("/").base ().representation () == "/");
assert (path ("/foo.txt").base ().representation () == "/foo");
assert (path ("/foo.txt/").base ().representation () == "/foo/");
- assert (path (".txt").base ().representation () == ".txt");
assert (path ("/.txt").base ().representation () == "/.txt");
- assert (path ("foo.txt.orig").base ().representation () == "foo.txt");
-#ifdef _WIN32
+#else
assert (path ("C:").base ().representation () == "C:");
assert (path ("C:\\foo.txt").base ().representation () == "C:\\foo");
assert (path ("C:\\foo.txt\\").base ().representation () == "C:\\foo\\");
@@ -186,6 +184,7 @@ main ()
assert (++i != p.rend () && *i == "foo");
assert (++i == p.rend ());
}
+#ifndef _WIN32
{
path p ("/foo/bar");
path::iterator i (p.begin ());
@@ -202,7 +201,6 @@ main ()
assert (++i != p.rend () && *i == "");
assert (++i == p.rend ());
}
-#ifndef _WIN32
{
path p ("/");
path::iterator i (p.begin ());
@@ -244,16 +242,14 @@ main ()
assert (test (++p.begin (), p.end ()) == "bar");
assert (test (p.begin (), ++p.begin ()) == "foo/");
}
+#ifndef _WIN32
{
path p ("/foo/bar");
assert (test (p.begin (), p.end ()) == "/foo/bar");
assert (test (++p.begin (), p.end ()) == "foo/bar");
assert (test (++(++p.begin ()), p.end ()) == "bar");
-#ifndef _WIN32
assert (test (p.begin (), ++p.begin ()) == "/");
-#endif
-
assert (test (++p.begin (), ++(++p.begin ())) == "foo/");
assert (test (++(++p.begin ()), ++(++(++p.begin ()))) == "bar");
}
@@ -263,14 +259,10 @@ main ()
assert (test (++p.begin (), p.end ()) == "foo/bar/");
assert (test (++(++p.begin ()), p.end ()) == "bar/");
-#ifndef _WIN32
assert (test (p.begin (), ++p.begin ()) == "/");
-#endif
-
assert (test (++p.begin (), ++(++p.begin ())) == "foo/");
assert (test (++(++p.begin ()), ++(++(++p.begin ()))) == "bar/");
}
-#ifndef _WIN32
{
path p ("/");
assert (test (p.begin (), p.end ()) == "/");
@@ -287,7 +279,6 @@ main ()
assert ((path ("foo/") / path ("bar/")).representation () == "foo/bar/");
assert ((path ("foo/") / path ()).representation () == "foo/");
#else
- assert ((path ("\\") / path ("tmp")).representation () == "\\tmp");
assert ((path ("C:\\") / path ("tmp")).representation () == "C:\\tmp");
assert ((path ("foo\\") / path ("bar")).representation () == "foo\\bar");
assert ((path ("foo\\") / path ("bar\\")).representation () == "foo\\bar\\");
@@ -303,13 +294,16 @@ main ()
assert (path ("..///foo").normalize ().representation () == "../foo");
assert (path ("../../foo").normalize ().representation () == "../../foo");
assert (path (".././foo").normalize ().representation () == "../foo");
- assert (path (".").normalize ().representation () == "");
- assert (path ("././").normalize ().representation () == "");
+ assert (path (".").normalize ().representation () == "./");
+ assert (path (".").normalize (false, true).representation () == "");
+ assert (path ("././").normalize ().representation () == "./");
+ assert (path ("././").normalize (false, true).representation () == "");
assert (path ("./..").normalize ().representation () == "../");
assert (path ("./../").normalize ().representation () == "../");
assert (path ("../.").normalize ().representation () == "../");
assert (path (".././").normalize ().representation () == "../");
- assert (path ("foo/./..").normalize ().representation () == "");
+ assert (path ("foo/./..").normalize ().representation () == "./");
+ assert (path ("foo/./..").normalize (false, true).representation () == "");
assert (path ("/foo/./..").normalize ().representation () == "/");
assert (path ("/foo/./../").normalize ().representation () == "/");
assert (path ("./foo").normalize ().representation () == "foo");
@@ -319,27 +313,34 @@ main ()
assert (path ("..///foo").normalize ().representation () == "..\\foo");
assert (path ("..\\../foo").normalize ().representation () == "..\\..\\foo");
assert (path (".././foo").normalize ().representation () == "..\\foo");
- assert (path (".").normalize ().representation () == "");
- assert (path (".\\.\\").normalize ().representation () == "");
+ assert (path (".").normalize ().representation () == ".\\");
+ assert (path (".").normalize (false, true).representation () == "");
+ assert (path (".\\.\\").normalize ().representation () == ".\\");
+ assert (path (".\\.\\").normalize (false, true).representation () == "");
assert (path ("./..").normalize ().representation () == "..\\");
assert (path ("../.").normalize ().representation () == "..\\");
- assert (path ("foo/./..").normalize ().representation () == "");
+ assert (path ("foo/./..").normalize ().representation () == ".\\");
+ assert (path ("foo/./..").normalize (false, true).representation () == "");
assert (path ("C:/foo/./..").normalize ().representation () == "C:\\");
assert (path ("C:/foo/./../").normalize ().representation () == "C:\\");
assert (path ("./foo").normalize ().representation () == "foo");
assert (path ("./foo\\").normalize ().representation () == "foo\\");
assert (path ("C:\\").normalize ().representation () == "C:\\");
- assert (path ("C:\\Foo12//Bar").normalize ().representation () == "C:\\Foo12\\Bar");
+
+ assert (path ("C:\\Foo12//Bar").normalize ().representation () ==
+ "C:\\Foo12\\Bar");
#endif
// comparison
//
- assert (path ("/") == path ("/"));
assert (path ("./foo") == path ("./foo"));
assert (path ("./foo/") == path ("./foo"));
assert (path ("./boo") < path ("./foo"));
-#ifdef _WIN32
+
+#ifndef _WIN32
+ assert (path ("/") == path ("/"));
+#else
assert (path (".\\foo") == path ("./FoO"));
assert (path (".\\foo") == path ("./foo\\"));
assert (path (".\\boo") < path (".\\Foo"));
@@ -371,19 +372,20 @@ main ()
assert (test ("foo/bar", "foo"));
assert (test ("foo/bar", "foo/"));
assert (!test ("foo/bar", "bar"));
+
+#ifndef _WIN32
assert (!test ("/foo-bar", "/foo"));
assert (test ("/foo/bar", "/foo"));
assert (test ("/foo/bar/baz", "/foo/bar"));
assert (!test ("/foo/bar/baz", "/foo/baz"));
-#ifdef _WIN32
+ assert (test ("/", "/"));
+ assert (test ("/foo/bar/baz", "/"));
+#else
assert (test ("c:", "c:"));
assert (test ("c:", "c:\\"));
assert (!test ("c:", "d:"));
assert (test ("c:\\foo", "c:"));
assert (test ("c:\\foo", "c:\\"));
-#else
- assert (test ("/", "/"));
- assert (test ("/foo/bar/baz", "/"));
#endif
}
@@ -400,19 +402,19 @@ main ()
assert (test ("foo/bar", "bar"));
assert (test ("foo/bar/", "bar/"));
assert (!test ("foo/bar", "foo"));
+
+#ifndef _WIN32
+ assert (test ("/", "/"));
assert (!test ("/foo-bar", "bar"));
assert (test ("/foo/bar", "bar"));
assert (test ("/foo/bar/baz", "bar/baz"));
assert (!test ("/foo/bar/baz", "bar"));
-
-#ifdef _WIN32
+#else
assert (test ("c:", "c:"));
assert (test ("c:\\", "c:"));
assert (!test ("d:", "c:"));
assert (test ("c:\\foo", "foo"));
assert (test ("c:\\foo\\", "foo\\"));
-#else
- assert (test ("/", "/"));
#endif
}
@@ -424,11 +426,14 @@ main ()
return path (p).leaf (path (d)).representation ();
};
+#ifndef _WIN32
assert (test ("/foo", "/") == "foo");
+ assert (test ("/foo/bar", "/foo/") == "bar");
+#endif
+
//assert (test ("foo/bar", "foo") == "bar");
assert (test ("foo/bar", "foo/") == "bar");
assert (test ("foo/bar/", "foo/") == "bar/");
- assert (test ("/foo/bar", "/foo/") == "bar");
}
// directory(path)
@@ -439,12 +444,15 @@ main ()
return path (p).directory (path (l)).representation ();
};
+#ifndef _WIN32
assert (test ("/foo", "foo") == "/");
+ assert (test ("/foo/bar/baz", "bar/baz") == "/foo/");
+#endif
+
assert (test ("foo/bar", "bar") == "foo/");
assert (test ("foo/bar/", "bar/") == "foo/");
assert (test ("foo/bar/", "bar") == "foo/");
assert (test ("foo/bar/baz", "bar/baz") == "foo/");
- assert (test ("/foo/bar/baz", "bar/baz") == "/foo/");
}
// relative