{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// Replace each slash character in the root-name
- if (p._M_type == _Type::_Root_name)
+ if (p._M_type == _Type::_Root_name || p._M_type == _Type::_Root_dir)
{
string_type s = p.native();
std::replace(s.begin(), s.end(), L'/', L'\\');
}
else if (!ret.has_relative_path())
{
- if (!ret.is_absolute())
+ // remove a dot-dot filename immediately after root-directory
+ if (!ret.has_root_directory())
ret /= p;
}
else
{
// Remove the filename before the trailing slash
// (equiv. to ret = ret.parent_path().remove_filename())
- ret._M_pathname.erase(elem._M_cur->_M_pos);
- ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end());
+
+ if (elem == ret.begin())
+ ret.clear();
+ else
+ {
+ ret._M_pathname.erase(elem._M_cur->_M_pos);
+ // Do we still have a trailing slash?
+ if (std::prev(elem)->_M_type == _Type::_Filename)
+ ret._M_cmpts.erase(elem._M_cur);
+ else
+ ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end());
+ }
}
else // ???
ret /= p;
#include <testsuite_hooks.h>
using std::filesystem::path;
-using __gnu_test::compare_paths;
+
+void
+compare_paths(path p, std::string expected)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ for (auto& c : expected)
+ if (c == '/')
+ c = '\\';
+#endif
+ __gnu_test::compare_paths(p, expected);
+}
void
test01()
{"/foo" , "/foo" },
{"/foo/" , "/foo/" },
{"/foo/." , "/foo/" },
- {"/foo/bar/.." , "/foo/" },
{"/foo/.." , "/" },
+ {"/foo/../.." , "/" },
+ {"/foo/bar/.." , "/foo/" },
+ {"/foo/bar/../.." , "/" },
+ {"/foo/bar/baz/../../.." , "/" }, // PR libstdc++/87116
{"/." , "/" },
{"/./" , "/" },
{"foo/.." , "." },
{"foo/../" , "." },
{"foo/../.." , ".." },
+ {"foo/../../..", "../.." },
// with root name (OS-dependent):
#if defined(_WIN32) && !defined(__CYGWIN__)
- {"C:bar/.." , "C:." },
+ {"C:bar/.." , "C:" },
#else
{"C:bar/.." , "." },
#endif
compare_paths( path(test.input).lexically_normal(), test.normalized );
}
+void
+test04()
+{
+ // PR libstdc++/87116
+ path p = "a/b/c";
+ compare_paths( (p/"../..").lexically_normal(), "a/" );
+
+ p = "a/b/c/d/e";
+ compare_paths( (p/"..").lexically_normal(), "a/b/c/d/" );
+ compare_paths( (p/"../..").lexically_normal(), "a/b/c/" );
+ compare_paths( (p/"../../..").lexically_normal(), "a/b/" );
+ compare_paths( (p/"../../../..").lexically_normal(), "a/" );
+ compare_paths( (p/"../../../../..").lexically_normal(), "." );
+ compare_paths( (p/"../../../../../..").lexically_normal(), ".." );
+
+ p = "/a/b/c/d/e";
+ compare_paths( (p/"..").lexically_normal(), "/a/b/c/d/" );
+ compare_paths( (p/"../..").lexically_normal(), "/a/b/c/" );
+ compare_paths( (p/"../../..").lexically_normal(), "/a/b/" );
+ compare_paths( (p/"../../../..").lexically_normal(), "/a/" );
+ compare_paths( (p/"../../../../..").lexically_normal(), "/" );
+ compare_paths( (p/"../../../../../..").lexically_normal(), "/" );
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ p = "A:b/c/d/e";
+ compare_paths( (p/"..").lexically_normal(), "A:b/c/d/" );
+ compare_paths( (p/"../..").lexically_normal(), "A:b/c/" );
+ compare_paths( (p/"../../..").lexically_normal(), "A:b/" );
+ compare_paths( (p/"../../../..").lexically_normal(), "A:" );
+ compare_paths( (p/"../../../../..").lexically_normal(), "A:.." );
+ compare_paths( (p/"../../../../../..").lexically_normal(), "A:../.." );
+
+ p = "A:/b/c/d/e";
+ compare_paths( (p/"..").lexically_normal(), "A:/b/c/d/" );
+ compare_paths( (p/"../..").lexically_normal(), "A:/b/c/" );
+ compare_paths( (p/"../../..").lexically_normal(), "A:/b/" );
+ compare_paths( (p/"../../../..").lexically_normal(), "A:/" );
+ compare_paths( (p/"../../../../..").lexically_normal(), "A:/" );
+ compare_paths( (p/"../../../../../..").lexically_normal(), "A:/" );
+#endif
+}
+
int
main()
{
test01();
test02();
test03();
+ test04();
}