Commit 9534a5e6 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/78870 support std::filesystem on Windows

	PR libstdc++/78870 support std::filesystem on Windows
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Check for link, readlink and symlink.
	* include/bits/fs_path.h (path::operator/=(const path&)): Move
	definition out of class body.
	(path::is_absolute(), path::_M_append(path)): Likewise.
	(operator<<(basic_ostream, const path&)): Use std::quoted directly.
	(operator>>(basic_istream, path&)): Likewise.
	(u8path): Reorder definitions and fix Windows implementation.
	(path::is_absolute()): Define inline and fix for Windows.
	[!_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
	Define POSIX version inline.
	(path::_M_append(path)): Define inline.
	* include/experimental/bits/fs_path.h (path::is_absolute()): Move
	definition out of class body.
	(operator<<(basic_ostream, const path&)): Fix type of delimiter and
	escape characters.
	(operator>>(basic_istream, path&)): Likewise.
	(path::is_absolute()): Define inline and fix for Windows.
	* src/filesystem/dir-common.h (__gnu_posix): New namespace.
	(__gnu_posix::char_type, __gnu_posix::DIR, __gnu_posix::dirent)
	(__gnu_posix::opendir, __gnu_posix::readdir, __gnu_posix::closedir):
	Define as adaptors for Windows functions/types or as
	using-declarations for POSIX functions/types.
	(_Dir_base, get_file_type): Qualify names to use declarations from
	__gnu_posix namespace.
	(_Dir_base::is_dor_or_dotdot): New helper functions.
	* src/filesystem/dir.cc (_Dir, recursive_directory_iterator): Qualify
	names to use declarations from __gnu_posix namespace.
	* src/filesystem/ops-common.h (__gnu_posix): New nested namespace.
	(__gnu_posix::open, __gnu_posix::close, __gnu_posix::stat_type)
	(__gnu_posix::stat, __gnu_posix::lstat, __gnu_posix::mode_t)
	(__gnu_posix::chmod, __gnu_posix::mkdir, __gnu_posix::getcwd)
	(__gnu_posix::chdir, __gnu_posix::utimbuf, __gnu_posix::utime)
	(__gnu_posix::rename, __gnu_posix::truncate, __gnu_posix::char_type):
	Define as adaptors for Windows functions/types or as
	using-declarations for POSIX functions/types.
	(stat_type, do_copy_file): Qualify names to use declarations from
	__gnu_posix namespace.
	(do_space): Declare new function.
	(make_file_type): Only use S_ISLNK if defined.
	* src/filesystem/ops.cc (char_ptr, filesystem::canonical): Use
	path::value_type not char.
	(filesystem::copy, create_dir, filesystem::create_directory): Qualify
	names to use declarations from __gnu_posix namespace.
	(filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
	add implementation for Windows.
	(filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
	(filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
	[!_PC_PATH_MAX]: Don't use pathconf.
	[PATH_MAX]: Use if defined.
	(filesystem::current_path(const path&, error_code&))
	(filesystem::equivalent, do_stat, filesystem::hard_link_count)
	(filesystem::last_write_time, filesystem::permissions): Use names
	from __gnu_posix.
	(filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
	(filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
	implementation for Windows.
	(filesystem::rename, filesystem::resize_file): Use names from
	__gnu_posix.
	(filesystem::space): Use do_space.
	[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Get absolute path to directory.
	(filesystem::status, filesystem::symlink_status): Use names from
	__gnu_posix.
	(filesystem::temp_directory_path): Add implementation for Windows.
	* src/filesystem/path.cc (dot): Define constant.
	(path::replace_extension): Use dot.
	(path::_M_find_extension): Likewise. Use path::string_type not
	std::string.
	(path::_M_split_cmpts): Use dot.
	(filesystem_error::_M_get_what): Use u8string() not native().
	* src/filesystem/std-dir.cc (_Dir, recursive_directory_iterator):
	Qualify names to use declarations from __gnu_posix namespace.
	* src/filesystem/std-ops.cc (filesystem::absolute(const path&)): Use
	correct error_code.
	(filesystem::absolute(const path&, error_code&)): Add implementation
	for Windows.
	(char_ptr, filesystem::canonical): Use path::value_type not char.
	(do_copy_file): Use names from __gnu_posix.
	[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Do not use fchmod, fchmodat or
	sendfile.
	(filesystem::copy, create_dir, filesystem::create_directory): Qualify
	names to use declarations from __gnu_posix namespace.
	(filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
	add implementation for Windows.
	(filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
	(filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
	[!_PC_PATH_MAX]: Don't use pathconf.
	[PATH_MAX]: Use if defined.
	(filesystem::current_path(const path&, error_code&))
	(filesystem::equivalent, do_stat, filesystem::hard_link_count)
	(filesystem::last_write_time, filesystem::permissions): Use names
	from __gnu_posix.
	(filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
	(filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
	implementation for Windows.
	(filesystem::rename, filesystem::resize_file): Use names from
	__gnu_posix.
	(do_space): Define.
	(filesystem::space): Use do_space.
	(filesystem::status, filesystem::symlink_status): Use names from
	__gnu_posix.
	(filesystem::temp_directory_path): Add implementation for Windows.
	* src/filesystem/std-path.cc
	[_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
	Define for Windows.
	(dot): Define constant.
	(path::replace_extension, is_dot): Use dot.
	(path::lexically_normal): Check _M_type instead of calling
	non-existent function.
	(path::_M_find_extension): Use dot. Use path::string_type not
	std::string.
	(path::_M_split_cmpts): Use dot.
	(filesystem_error::_M_get_what): Use u8string() not native().
	* testsuite/27_io/filesystem/iterators/directory_iterator.cc: Do not
	use symlinks.
	* testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
	Likewise.
	* testsuite/27_io/filesystem/operations/absolute.cc: Use
	__gnu_test::root_path() instead of "/" and add Windows-specific tests.
	* testsuite/27_io/filesystem/operations/canonical.cc: Use
	path::string() to get narrow string, not path::native().
	* testsuite/27_io/filesystem/operations/copy.cc: Construct fstreams
	with std::filesystem::path not std::basic_string.
	* testsuite/27_io/filesystem/operations/copy_file.cc: Likewise.
	* testsuite/27_io/filesystem/operations/exists.cc: Use
	__gnu_test::root_path() instead of "/".
	* testsuite/27_io/filesystem/operations/is_empty.cc: Construct
	fstreams with std::filesystem::path not std::basic_string.
	* testsuite/27_io/filesystem/operations/last_write_time.cc: Use
	path::string() to get narrow string.
	* testsuite/27_io/filesystem/operations/space.cc: Check results for
	errors, expect sensible values otherwise.
	* testsuite/27_io/filesystem/operations/temp_directory_path.cc: Add
	helpers for adjusting the environment on Windows.
	* testsuite/27_io/filesystem/path/append/path.cc: Test
	Windows-specific behaviour.
	* testsuite/27_io/filesystem/path/construct/format.cc: Fix creation
	of path::string_type objects.
	* testsuite/27_io/filesystem/path/construct/locale.cc: Compare native
	string to wide string on Windows.
	* testsuite/27_io/filesystem/path/decompose/root_directory.cc: Allow
	for backslash as root-directory.
	* testsuite/27_io/filesystem/path/decompose/stem.cc: Use
	path::string() to get narrow string.
	* testsuite/27_io/filesystem/path/itr/traversal.cc: Test Windows-style
	paths.
	* testsuite/27_io/filesystem/path/native/string.cc: Use string_type
	not std::string.
	* testsuite/27_io/filesystem/path/query/is_absolute.cc: Adjust for
	different definintion of absolute paths on Windows.
	* testsuite/experimental/filesystem/iterators/directory_iterator.cc:
	Do not use symlinks.
	* testsuite/experimental/filesystem/operations/absolute.cc: Test
	Windows behaviour.
	* testsuite/experimental/filesystem/operations/copy.cc: Construct
	fstreams with NTCTS not std::basic_string.
	* testsuite/experimental/filesystem/operations/copy_file.cc: Likewise.
	* testsuite/experimental/filesystem/operations/exists.cc: Use
	__gnu_test::root_path() instead of "/".
	* testsuite/experimental/filesystem/operations/is_empty.cc: Construct
	fstreams with NTCTS not std::basic_string.
	* testsuite/experimental/filesystem/operations/last_write_time.cc:
	Use path::string() to get narrow string.
	* testsuite/experimental/filesystem/operations/space.cc: Use
	__gnu_test::root_path() instead of "/".
	* testsuite/experimental/filesystem/operations/temp_directory_path.cc:
	Add helpers for adjusting the environment on Windows.
	* testsuite/experimental/filesystem/path/append/path.cc: Use
	path::string() to get narrow strings for comparisons.
	* testsuite/experimental/filesystem/path/concat/path.cc: Likewise.
	* testsuite/experimental/filesystem/path/decompose/root_directory.cc:
	Likewise.
	* testsuite/experimental/filesystem/path/decompose/stem.cc: Likewise.
	* testsuite/experimental/filesystem/path/native/string.cc: Use
	string_type not std::string.
	* testsuite/experimental/filesystem/path/query/is_absolute.cc:
	Adjust for different definintion of absolute paths on Windows.
	* testsuite/util/testsuite_fs.h (__gnu_test::root_path()): New
	function.
	(__gnu_test::scoped_file): Construct fstreams with NTCTS not
	std::basic_string.

From-SVN: r261034
parent c9315097
2018-05-24 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/78870 support std::filesystem on Windows
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Check for link, readlink and symlink.
* include/bits/fs_path.h (path::operator/=(const path&)): Move
definition out of class body.
(path::is_absolute(), path::_M_append(path)): Likewise.
(operator<<(basic_ostream, const path&)): Use std::quoted directly.
(operator>>(basic_istream, path&)): Likewise.
(u8path): Reorder definitions and fix Windows implementation.
(path::is_absolute()): Define inline and fix for Windows.
[!_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
Define POSIX version inline.
(path::_M_append(path)): Define inline.
* include/experimental/bits/fs_path.h (path::is_absolute()): Move
definition out of class body.
(operator<<(basic_ostream, const path&)): Fix type of delimiter and
escape characters.
(operator>>(basic_istream, path&)): Likewise.
(path::is_absolute()): Define inline and fix for Windows.
* src/filesystem/dir-common.h (__gnu_posix): New namespace.
(__gnu_posix::char_type, __gnu_posix::DIR, __gnu_posix::dirent)
(__gnu_posix::opendir, __gnu_posix::readdir, __gnu_posix::closedir):
Define as adaptors for Windows functions/types or as
using-declarations for POSIX functions/types.
(_Dir_base, get_file_type): Qualify names to use declarations from
__gnu_posix namespace.
(_Dir_base::is_dor_or_dotdot): New helper functions.
* src/filesystem/dir.cc (_Dir, recursive_directory_iterator): Qualify
names to use declarations from __gnu_posix namespace.
* src/filesystem/ops-common.h (__gnu_posix): New nested namespace.
(__gnu_posix::open, __gnu_posix::close, __gnu_posix::stat_type)
(__gnu_posix::stat, __gnu_posix::lstat, __gnu_posix::mode_t)
(__gnu_posix::chmod, __gnu_posix::mkdir, __gnu_posix::getcwd)
(__gnu_posix::chdir, __gnu_posix::utimbuf, __gnu_posix::utime)
(__gnu_posix::rename, __gnu_posix::truncate, __gnu_posix::char_type):
Define as adaptors for Windows functions/types or as
using-declarations for POSIX functions/types.
(stat_type, do_copy_file): Qualify names to use declarations from
__gnu_posix namespace.
(do_space): Declare new function.
(make_file_type): Only use S_ISLNK if defined.
* src/filesystem/ops.cc (char_ptr, filesystem::canonical): Use
path::value_type not char.
(filesystem::copy, create_dir, filesystem::create_directory): Qualify
names to use declarations from __gnu_posix namespace.
(filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
add implementation for Windows.
(filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
(filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
[!_PC_PATH_MAX]: Don't use pathconf.
[PATH_MAX]: Use if defined.
(filesystem::current_path(const path&, error_code&))
(filesystem::equivalent, do_stat, filesystem::hard_link_count)
(filesystem::last_write_time, filesystem::permissions): Use names
from __gnu_posix.
(filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
(filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
implementation for Windows.
(filesystem::rename, filesystem::resize_file): Use names from
__gnu_posix.
(filesystem::space): Use do_space.
[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Get absolute path to directory.
(filesystem::status, filesystem::symlink_status): Use names from
__gnu_posix.
(filesystem::temp_directory_path): Add implementation for Windows.
* src/filesystem/path.cc (dot): Define constant.
(path::replace_extension): Use dot.
(path::_M_find_extension): Likewise. Use path::string_type not
std::string.
(path::_M_split_cmpts): Use dot.
(filesystem_error::_M_get_what): Use u8string() not native().
* src/filesystem/std-dir.cc (_Dir, recursive_directory_iterator):
Qualify names to use declarations from __gnu_posix namespace.
* src/filesystem/std-ops.cc (filesystem::absolute(const path&)): Use
correct error_code.
(filesystem::absolute(const path&, error_code&)): Add implementation
for Windows.
(char_ptr, filesystem::canonical): Use path::value_type not char.
(do_copy_file): Use names from __gnu_posix.
[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Do not use fchmod, fchmodat or
sendfile.
(filesystem::copy, create_dir, filesystem::create_directory): Qualify
names to use declarations from __gnu_posix namespace.
(filesystem::create_hard_link): Check HAVE_LINK autoconf macro and
add implementation for Windows.
(filesystem::create_symlink): Check HAVE_SYMLINK autoconf macro.
(filesystem::current_path(error_code&)): Use __gnu_posix::getcwd.
[!_PC_PATH_MAX]: Don't use pathconf.
[PATH_MAX]: Use if defined.
(filesystem::current_path(const path&, error_code&))
(filesystem::equivalent, do_stat, filesystem::hard_link_count)
(filesystem::last_write_time, filesystem::permissions): Use names
from __gnu_posix.
(filesystem::read_symlink): Check HAVE_READLINK autoconf macro.
(filesystem::remove) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add
implementation for Windows.
(filesystem::rename, filesystem::resize_file): Use names from
__gnu_posix.
(do_space): Define.
(filesystem::space): Use do_space.
(filesystem::status, filesystem::symlink_status): Use names from
__gnu_posix.
(filesystem::temp_directory_path): Add implementation for Windows.
* src/filesystem/std-path.cc
[_GLIBCXX_FILESYSTEM_IS_WINDOWS] (path::operator/=(const path&)):
Define for Windows.
(dot): Define constant.
(path::replace_extension, is_dot): Use dot.
(path::lexically_normal): Check _M_type instead of calling
non-existent function.
(path::_M_find_extension): Use dot. Use path::string_type not
std::string.
(path::_M_split_cmpts): Use dot.
(filesystem_error::_M_get_what): Use u8string() not native().
* testsuite/27_io/filesystem/iterators/directory_iterator.cc: Do not
use symlinks.
* testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
Likewise.
* testsuite/27_io/filesystem/operations/absolute.cc: Use
__gnu_test::root_path() instead of "/" and add Windows-specific tests.
* testsuite/27_io/filesystem/operations/canonical.cc: Use
path::string() to get narrow string, not path::native().
* testsuite/27_io/filesystem/operations/copy.cc: Construct fstreams
with std::filesystem::path not std::basic_string.
* testsuite/27_io/filesystem/operations/copy_file.cc: Likewise.
* testsuite/27_io/filesystem/operations/exists.cc: Use
__gnu_test::root_path() instead of "/".
* testsuite/27_io/filesystem/operations/is_empty.cc: Construct
fstreams with std::filesystem::path not std::basic_string.
* testsuite/27_io/filesystem/operations/last_write_time.cc: Use
path::string() to get narrow string.
* testsuite/27_io/filesystem/operations/space.cc: Check results for
errors, expect sensible values otherwise.
* testsuite/27_io/filesystem/operations/temp_directory_path.cc: Add
helpers for adjusting the environment on Windows.
* testsuite/27_io/filesystem/path/append/path.cc: Test
Windows-specific behaviour.
* testsuite/27_io/filesystem/path/construct/format.cc: Fix creation
of path::string_type objects.
* testsuite/27_io/filesystem/path/construct/locale.cc: Compare native
string to wide string on Windows.
* testsuite/27_io/filesystem/path/decompose/root_directory.cc: Allow
for backslash as root-directory.
* testsuite/27_io/filesystem/path/decompose/stem.cc: Use
path::string() to get narrow string.
* testsuite/27_io/filesystem/path/itr/traversal.cc: Test Windows-style
paths.
* testsuite/27_io/filesystem/path/native/string.cc: Use string_type
not std::string.
* testsuite/27_io/filesystem/path/query/is_absolute.cc: Adjust for
different definintion of absolute paths on Windows.
* testsuite/experimental/filesystem/iterators/directory_iterator.cc:
Do not use symlinks.
* testsuite/experimental/filesystem/operations/absolute.cc: Test
Windows behaviour.
* testsuite/experimental/filesystem/operations/copy.cc: Construct
fstreams with NTCTS not std::basic_string.
* testsuite/experimental/filesystem/operations/copy_file.cc: Likewise.
* testsuite/experimental/filesystem/operations/exists.cc: Use
__gnu_test::root_path() instead of "/".
* testsuite/experimental/filesystem/operations/is_empty.cc: Construct
fstreams with NTCTS not std::basic_string.
* testsuite/experimental/filesystem/operations/last_write_time.cc:
Use path::string() to get narrow string.
* testsuite/experimental/filesystem/operations/space.cc: Use
__gnu_test::root_path() instead of "/".
* testsuite/experimental/filesystem/operations/temp_directory_path.cc:
Add helpers for adjusting the environment on Windows.
* testsuite/experimental/filesystem/path/append/path.cc: Use
path::string() to get narrow strings for comparisons.
* testsuite/experimental/filesystem/path/concat/path.cc: Likewise.
* testsuite/experimental/filesystem/path/decompose/root_directory.cc:
Likewise.
* testsuite/experimental/filesystem/path/decompose/stem.cc: Likewise.
* testsuite/experimental/filesystem/path/native/string.cc: Use
string_type not std::string.
* testsuite/experimental/filesystem/path/query/is_absolute.cc:
Adjust for different definintion of absolute paths on Windows.
* testsuite/util/testsuite_fs.h (__gnu_test::root_path()): New
function.
(__gnu_test::scoped_file): Construct fstreams with NTCTS not
std::basic_string.
2018-05-31 Jonathan Wakely <jwakely@redhat.com> 2018-05-31 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/85951 PR libstdc++/85951
......
...@@ -264,6 +264,9 @@ ...@@ -264,6 +264,9 @@
/* Only used in build directory testsuite_hooks.h. */ /* Only used in build directory testsuite_hooks.h. */
#undef HAVE_LIMIT_VMEM #undef HAVE_LIMIT_VMEM
/* Define to 1 if you have the `link' function. */
#undef HAVE_LINK
/* Define if futex syscall is available. */ /* Define if futex syscall is available. */
#undef HAVE_LINUX_FUTEX #undef HAVE_LINUX_FUTEX
...@@ -339,6 +342,9 @@ ...@@ -339,6 +342,9 @@
/* Define to 1 if you have the `quick_exit' function. */ /* Define to 1 if you have the `quick_exit' function. */
#undef HAVE_QUICK_EXIT #undef HAVE_QUICK_EXIT
/* Define to 1 if you have the `readlink' function. */
#undef HAVE_READLINK
/* Define to 1 if you have the `setenv' function. */ /* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV #undef HAVE_SETENV
...@@ -408,6 +414,9 @@ ...@@ -408,6 +414,9 @@
/* Define if strxfrm_l is available in <string.h>. */ /* Define if strxfrm_l is available in <string.h>. */
#undef HAVE_STRXFRM_L #undef HAVE_STRXFRM_L
/* Define to 1 if you have the `symlink' function. */
#undef HAVE_SYMLINK
/* Define to 1 if the target runtime linker supports binding the same symbol /* Define to 1 if the target runtime linker supports binding the same symbol
to different versions. */ to different versions. */
#undef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT #undef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT
......
...@@ -80049,6 +80049,19 @@ fi ...@@ -80049,6 +80049,19 @@ fi
done done
for ac_func in link readlink symlink
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
eval as_val=\$$as_ac_var
if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi
done
# Check whether --enable-libstdcxx-filesystem-ts was given. # Check whether --enable-libstdcxx-filesystem-ts was given.
if test "${enable_libstdcxx_filesystem_ts+set}" = set; then : if test "${enable_libstdcxx_filesystem_ts+set}" = set; then :
...@@ -420,6 +420,7 @@ GLIBCXX_CHECK_GTHREADS ...@@ -420,6 +420,7 @@ GLIBCXX_CHECK_GTHREADS
# For Filesystem TS. # For Filesystem TS.
AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h]) AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
AC_CHECK_FUNCS(link readlink symlink)
GLIBCXX_ENABLE_FILESYSTEM_TS GLIBCXX_ENABLE_FILESYSTEM_TS
GLIBCXX_CHECK_FILESYSTEM_DEPS GLIBCXX_CHECK_FILESYSTEM_DEPS
......
...@@ -37,11 +37,11 @@ ...@@ -37,11 +37,11 @@
#include <vector> #include <vector>
#include <locale> #include <locale>
#include <iosfwd> #include <iosfwd>
#include <iomanip>
#include <codecvt> #include <codecvt>
#include <string_view> #include <string_view>
#include <system_error> #include <system_error>
#include <bits/stl_algobase.h> #include <bits/stl_algobase.h>
#include <bits/quoted_string.h>
#include <bits/locale_conv.h> #include <bits/locale_conv.h>
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
...@@ -232,37 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -232,37 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
// appends // appends
path& operator/=(const path& __p) path& operator/=(const path& __p);
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name()))
operator=(__p);
else
{
string_type __pathname;
if (__p.has_root_directory())
__pathname = root_name().native();
else if (has_filename() || (!has_root_directory() && is_absolute()))
__pathname = _M_pathname + preferred_separator;
__pathname += __p.relative_path().native(); // XXX is this right?
_M_pathname.swap(__pathname);
_M_split_cmpts();
}
#else
// Much simpler, as any path with root-name or root-dir is absolute.
if (__p.is_absolute())
operator=(__p);
else
{
if (has_filename() || (_M_type == _Type::_Root_name))
_M_pathname += preferred_separator;
_M_pathname += __p.native();
_M_split_cmpts();
}
#endif
return *this;
}
template <class _Source> template <class _Source>
_Path<_Source>& _Path<_Source>&
...@@ -378,7 +348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -378,7 +348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
bool has_filename() const; bool has_filename() const;
bool has_stem() const; bool has_stem() const;
bool has_extension() const; bool has_extension() const;
bool is_absolute() const { return has_root_directory(); } bool is_absolute() const;
bool is_relative() const { return !is_absolute(); } bool is_relative() const { return !is_absolute(); }
// generation // generation
...@@ -419,19 +389,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -419,19 +389,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
enum class _Split { _Stem, _Extension }; enum class _Split { _Stem, _Extension };
path& path& _M_append(path __p);
_M_append(path __p)
{
if (__p.is_absolute())
operator=(std::move(__p));
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
else if (__p.has_root_name() && __p.root_name() != root_name())
operator=(std::move(__p));
#endif
else
operator/=(const_cast<const path&>(__p));
return *this;
}
pair<const string_type*, size_t> _M_find_extension() const; pair<const string_type*, size_t> _M_find_extension() const;
...@@ -552,10 +510,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -552,10 +510,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
{ {
auto __tmp = __p.string<_CharT, _Traits>(); __os << std::quoted(__p.string<_CharT, _Traits>());
using __quoted_string
= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
__os << __quoted_string{__tmp, '"', '\\'};
return __os; return __os;
} }
...@@ -565,40 +520,55 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -565,40 +520,55 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
{ {
basic_string<_CharT, _Traits> __tmp; basic_string<_CharT, _Traits> __tmp;
using __quoted_string if (__is >> std::quoted(__tmp))
= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
if (__is >> __quoted_string{ __tmp, '"', '\\' })
__p = std::move(__tmp); __p = std::move(__tmp);
return __is; return __is;
} }
template<typename _Source> template<typename _InputIterator>
inline auto inline auto
u8path(const _Source& __source) u8path(_InputIterator __first, _InputIterator __last)
-> decltype(filesystem::path(__source, std::locale::classic())) -> decltype(filesystem::path(__first, __last, std::locale::classic()))
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
const std::string __u8str{__source}; codecvt_utf8<path::value_type> __cvt;
return std::filesystem::u8path(__u8str.begin(), __u8str.end()); path::string_type __tmp;
if constexpr (is_pointer_v<_InputIterator>)
{
if (__str_codecvt_in(__first, __last, __tmp, __cvt))
return path{ __tmp };
}
else
{
const std::string __u8str{__first, __last};
const char* const __ptr = __u8str.data();
if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
return path{ __tmp };
}
return {};
#else #else
return path{ __source }; return path{ __first, __last };
#endif #endif
} }
template<typename _InputIterator> template<typename _Source>
inline auto inline auto
u8path(_InputIterator __first, _InputIterator __last) u8path(const _Source& __source)
-> decltype(filesystem::path(__first, __last, std::locale::classic())) -> decltype(filesystem::path(__source, std::locale::classic()))
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
codecvt_utf8<value_type> __cvt; if constexpr (is_convertible_v<const _Source&, std::string_view>)
string_type __tmp; {
if (__str_codecvt_in(__first, __last, __tmp, __cvt)) const std::string_view __s = __source;
return path{ __tmp }; return filesystem::u8path(__s.data(), __s.data() + __s.size());
}
else else
return {}; {
std::string __s = path::_S_string_from_iter(__source);
return filesystem::u8path(__s.data(), __s.data() + __s.size());
}
#else #else
return path{ __first, __last }; return path{ __source };
#endif #endif
} }
...@@ -1068,6 +1038,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -1068,6 +1038,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return ext.first && ext.second != string_type::npos; return ext.first && ext.second != string_type::npos;
} }
inline bool
path::is_absolute() const
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
return has_root_name() && has_root_directory();
#else
return has_root_directory();
#endif
}
inline path::iterator inline path::iterator
path::begin() const path::begin() const
{ {
...@@ -1084,6 +1064,38 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -1084,6 +1064,38 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return iterator(this, true); return iterator(this, true);
} }
#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
inline path& path::operator/=(const path& __p)
{
// Much simpler than the specification in the standard,
// as any path with root-name or root-dir is absolute.
if (__p.is_absolute())
operator=(__p);
else
{
if (has_filename() || (_M_type == _Type::_Root_name))
_M_pathname += preferred_separator;
_M_pathname += __p.native();
_M_split_cmpts();
}
return *this;
}
#endif
inline path&
path::_M_append(path __p)
{
if (__p.is_absolute())
operator=(std::move(__p));
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
else if (__p.has_root_name() && __p.root_name() != root_name())
operator=(std::move(__p));
#endif
else
operator/=(const_cast<const path&>(__p));
return *this;
}
inline path::iterator& inline path::iterator&
path::iterator::operator++() path::iterator::operator++()
{ {
......
...@@ -372,7 +372,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -372,7 +372,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
bool has_filename() const; bool has_filename() const;
bool has_stem() const; bool has_stem() const;
bool has_extension() const; bool has_extension() const;
bool is_absolute() const { return has_root_directory(); } bool is_absolute() const;
bool is_relative() const { return !is_absolute(); } bool is_relative() const { return !is_absolute(); }
// iterators // iterators
...@@ -537,7 +537,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -537,7 +537,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
auto __tmp = __p.string<_CharT, _Traits>(); auto __tmp = __p.string<_CharT, _Traits>();
using __quoted_string using __quoted_string
= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
__os << __quoted_string{__tmp, '"', '\\'}; __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')};
return __os; return __os;
} }
...@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_string<_CharT, _Traits> __tmp; basic_string<_CharT, _Traits> __tmp;
using __quoted_string using __quoted_string
= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
if (__is >> __quoted_string{ __tmp, '"', '\\' }) if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') })
__p = std::move(__tmp); __p = std::move(__tmp);
return __is; return __is;
} }
...@@ -993,6 +993,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -993,6 +993,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return ext.first && ext.second != string_type::npos; return ext.first && ext.second != string_type::npos;
} }
inline bool
path::is_absolute() const
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
return has_root_name() && has_root_directory();
#else
return has_root_directory();
#endif
}
inline path::iterator inline path::iterator
path::begin() const path::begin() const
{ {
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#define _GLIBCXX_DIR_COMMON_H 1 #define _GLIBCXX_DIR_COMMON_H 1
#include <string.h> // strcmp #include <string.h> // strcmp
#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
#include <wchar.h> // wcscmp
#endif
#ifdef _GLIBCXX_HAVE_DIRENT_H #ifdef _GLIBCXX_HAVE_DIRENT_H
# ifdef _GLIBCXX_HAVE_SYS_TYPES_H # ifdef _GLIBCXX_HAVE_SYS_TYPES_H
# include <sys/types.h> # include <sys/types.h>
...@@ -35,26 +38,42 @@ ...@@ -35,26 +38,42 @@
# error "the <dirent.h> header is needed to build the Filesystem TS" # error "the <dirent.h> header is needed to build the Filesystem TS"
#endif #endif
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
# undef opendir
# define opendir _wopendir
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
_GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace filesystem namespace filesystem
{ {
namespace __gnu_posix
{
#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
using char_type = wchar_t;
using DIR = ::_WDIR;
using dirent = _wdirent;
inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); }
inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); }
inline int closedir(DIR* dir) { return ::_wclosedir(dir); }
#else
using char_type = char;
using DIR = ::DIR;
typedef struct ::dirent dirent;
using ::opendir;
using ::readdir;
using ::closedir;
#endif
} // namespace __gnu_posix
namespace posix = __gnu_posix;
struct _Dir_base struct _Dir_base
{ {
_Dir_base(DIR* dirp = nullptr) : dirp(dirp) { } _Dir_base(posix::DIR* dirp = nullptr) : dirp(dirp) { }
// If no error occurs then dirp is non-null, // If no error occurs then dirp is non-null,
// otherwise null (whether error ignored or not). // otherwise null (whether error ignored or not).
_Dir_base(const char* p, bool skip_permission_denied, _Dir_base(const posix::char_type* pathname, bool skip_permission_denied,
error_code& ec) noexcept error_code& ec) noexcept
: dirp(::opendir(p)) : dirp(posix::opendir(pathname))
{ {
if (dirp) if (dirp)
ec.clear(); ec.clear();
...@@ -72,22 +91,22 @@ struct _Dir_base ...@@ -72,22 +91,22 @@ struct _Dir_base
_Dir_base& operator=(_Dir_base&&) = delete; _Dir_base& operator=(_Dir_base&&) = delete;
~_Dir_base() { if (dirp) ::closedir(dirp); } ~_Dir_base() { if (dirp) posix::closedir(dirp); }
const struct ::dirent* const posix::dirent*
advance(bool skip_permission_denied, error_code& ec) noexcept advance(bool skip_permission_denied, error_code& ec) noexcept
{ {
ec.clear(); ec.clear();
int err = std::exchange(errno, 0); int err = std::exchange(errno, 0);
const struct ::dirent* entp = readdir(dirp); const posix::dirent* entp = posix::readdir(dirp);
// std::swap cannot be used with Bionic's errno // std::swap cannot be used with Bionic's errno
err = std::exchange(errno, err); err = std::exchange(errno, err);
if (entp) if (entp)
{ {
// skip past dot and dot-dot // skip past dot and dot-dot
if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) if (is_dot_or_dotdot(entp->d_name))
return advance(skip_permission_denied, ec); return advance(skip_permission_denied, ec);
return entp; return entp;
} }
...@@ -105,15 +124,24 @@ struct _Dir_base ...@@ -105,15 +124,24 @@ struct _Dir_base
} }
} }
DIR* dirp; static bool is_dot_or_dotdot(const char* s) noexcept
{ return !strcmp(s, ".") || !strcmp(s, ".."); }
#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
static bool is_dot_or_dotdot(const wchar_t* s) noexcept
{ return !wcscmp(s, L".") || !wcscmp(s, L".."); }
#endif
posix::DIR* dirp;
}; };
} // namespace filesystem } // namespace filesystem
// BEGIN/END macros must be defined before including this file. // BEGIN/END macros must be defined before including this file.
_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
inline file_type inline file_type
get_file_type(const ::dirent& d __attribute__((__unused__))) get_file_type(const std::filesystem::__gnu_posix::dirent& d [[gnu::unused]])
{ {
#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
switch (d.d_type) switch (d.d_type)
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "dir-common.h" #include "dir-common.h"
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
namespace posix = std::filesystem::__gnu_posix;
struct fs::_Dir : std::filesystem::_Dir_base struct fs::_Dir : std::filesystem::_Dir_base
{ {
...@@ -47,7 +48,7 @@ struct fs::_Dir : std::filesystem::_Dir_base ...@@ -47,7 +48,7 @@ struct fs::_Dir : std::filesystem::_Dir_base
path = p; path = p;
} }
_Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
_Dir(_Dir&&) = default; _Dir(_Dir&&) = default;
...@@ -185,7 +186,7 @@ recursive_directory_iterator(const path& p, directory_options options, ...@@ -185,7 +186,7 @@ recursive_directory_iterator(const path& p, directory_options options,
{ {
if (ec) if (ec)
ec->clear(); ec->clear();
if (DIR* dirp = ::opendir(p.c_str())) if (posix::DIR* dirp = posix::opendir(p.c_str()))
{ {
auto sp = std::make_shared<_Dir_stack>(); auto sp = std::make_shared<_Dir_stack>();
sp->push(_Dir{ dirp, p }); sp->push(_Dir{ dirp, p });
......
...@@ -34,12 +34,103 @@ ...@@ -34,12 +34,103 @@
# include <sys/stat.h> # include <sys/stat.h>
# endif # endif
#endif #endif
#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
# include <utime.h> // utime
#endif
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
# include <wchar.h>
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
_GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace filesystem namespace filesystem
{ {
namespace __gnu_posix
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
inline int open(const wchar_t* path, int flags)
{ return ::_wopen(path, flags); }
inline int open(const wchar_t* path, int flags, int mode)
{ return ::_wopen(path, flags, mode); }
inline int close(int fd)
{ return ::_close(fd); }
typedef struct ::_stat stat_type;
inline int stat(const wchar_t* path, stat_type* buffer)
{ return ::_wstat(path, buffer); }
inline lstat(const wchar_t* path, stat_type* buffer)
{
// TODO symlinks not currently supported
return stat(path, buffer);
}
using ::mode_t;
inline int chmod(const wchar_t* path, mode_t mode)
{ return ::_wchmod(path, mode); }
inline int mkdir(const wchar_t* path, mode_t)
{ return ::_wmkdir(path); }
inline wchar_t* getcwd(wchar_t* buf, size_t size)
{ return ::_wgetcwd(buf, size > (size_t)INT_MAX ? INT_MAX : (int)size); }
inline int chdir(const wchar_t* path)
{ return ::_wchdir(path); }
#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
using utimbuf = _utimbuf;
inline int utime(const wchar_t* path, utimbuf* times)
{ return ::_wutime(path, times); }
#endif
inline int rename(const wchar_t* oldname, const wchar_t* newname)
{ return _wrename(oldname, newname); }
inline int truncate(const wchar_t* path, _off64_t length)
{
const int fd = ::_wopen(path, _O_BINARY|_O_RDWR);
if (fd == -1)
return fd;
const int ret = ::ftruncate64(fd, length);
int err;
::_get_errno(&err);
::_close(fd);
::_set_errno(err);
return ret;
}
using char_type = wchar_t;
#else // _GLIBCXX_FILESYSTEM_IS_WINDOWS
using ::open;
using ::close;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
typedef struct ::stat stat_type;
using ::stat;
using ::lstat;
#endif
using ::mode_t;
using ::chmod;
using ::mkdir;
using ::getcwd;
using ::chdir;
#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
using ::utimbuf;
using ::utime;
#endif
using ::rename;
using ::truncate;
using char_type = char;
#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
} // namespace __gnu_posix
template<typename Bitmask> template<typename Bitmask>
inline bool is_set(Bitmask obj, Bitmask bits) inline bool is_set(Bitmask obj, Bitmask bits)
{ {
...@@ -53,7 +144,7 @@ namespace filesystem ...@@ -53,7 +144,7 @@ namespace filesystem
} }
#ifdef _GLIBCXX_HAVE_SYS_STAT_H #ifdef _GLIBCXX_HAVE_SYS_STAT_H
typedef struct ::stat stat_type; using __gnu_posix::stat_type;
inline std::chrono::system_clock::time_point inline std::chrono::system_clock::time_point
file_time(const stat_type& st, std::error_code& ec) noexcept file_time(const stat_type& st, std::error_code& ec) noexcept
...@@ -82,11 +173,17 @@ namespace filesystem ...@@ -82,11 +173,17 @@ namespace filesystem
}; };
bool bool
do_copy_file(const char* from, const char* to, do_copy_file(const __gnu_posix::char_type* from,
const __gnu_posix::char_type* to,
copy_options_existing_file options, copy_options_existing_file options,
stat_type* from_st, stat_type* to_st, stat_type* from_st, stat_type* to_st,
std::error_code& ec) noexcept; std::error_code& ec) noexcept;
void
do_space(const __gnu_posix::char_type* pathname,
uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
std::error_code&);
#endif // _GLIBCXX_HAVE_SYS_STAT_H #endif // _GLIBCXX_HAVE_SYS_STAT_H
} // namespace filesystem } // namespace filesystem
...@@ -95,7 +192,7 @@ namespace filesystem ...@@ -95,7 +192,7 @@ namespace filesystem
_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
#ifdef _GLIBCXX_HAVE_SYS_STAT_H #ifdef _GLIBCXX_HAVE_SYS_STAT_H
typedef struct ::stat stat_type; using std::filesystem::__gnu_posix::stat_type;
inline file_type inline file_type
make_file_type(const stat_type& st) noexcept make_file_type(const stat_type& st) noexcept
...@@ -111,8 +208,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM ...@@ -111,8 +208,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
return file_type::block; return file_type::block;
else if (S_ISFIFO(st.st_mode)) else if (S_ISFIFO(st.st_mode))
return file_type::fifo; return file_type::fifo;
#ifdef S_ISLNK // not present in mingw
else if (S_ISLNK(st.st_mode)) else if (S_ISLNK(st.st_mode))
return file_type::symlink; return file_type::symlink;
#endif
#ifdef S_ISSOCK // not present until POSIX:2001 #ifdef S_ISSOCK // not present until POSIX:2001
else if (S_ISSOCK(st.st_mode)) else if (S_ISSOCK(st.st_mode))
return file_type::socket; return file_type::socket;
......
...@@ -61,6 +61,12 @@ path::replace_filename(const path& replacement) ...@@ -61,6 +61,12 @@ path::replace_filename(const path& replacement)
return *this; return *this;
} }
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
const fs::path::value_type dot = L'.';
#else
const fs::path::value_type dot = '.';
#endif
path& path&
path::replace_extension(const path& replacement) path::replace_extension(const path& replacement)
{ {
...@@ -78,8 +84,8 @@ path::replace_extension(const path& replacement) ...@@ -78,8 +84,8 @@ path::replace_extension(const path& replacement)
_M_pathname.erase(back._M_pos + ext.second); _M_pathname.erase(back._M_pos + ext.second);
} }
} }
if (!replacement.empty() && replacement.native()[0] != '.') if (!replacement.empty() && replacement.native()[0] != dot)
_M_pathname += '.'; _M_pathname += dot;
_M_pathname += replacement.native(); _M_pathname += replacement.native();
_M_split_cmpts(); _M_split_cmpts();
return *this; return *this;
...@@ -297,7 +303,7 @@ path::has_filename() const ...@@ -297,7 +303,7 @@ path::has_filename() const
std::pair<const path::string_type*, std::size_t> std::pair<const path::string_type*, std::size_t>
path::_M_find_extension() const path::_M_find_extension() const
{ {
const std::string* s = nullptr; const string_type* s = nullptr;
if (_M_type != _Type::_Multi) if (_M_type != _Type::_Multi)
s = &_M_pathname; s = &_M_pathname;
...@@ -312,14 +318,14 @@ path::_M_find_extension() const ...@@ -312,14 +318,14 @@ path::_M_find_extension() const
{ {
if (auto sz = s->size()) if (auto sz = s->size())
{ {
if (sz <= 2 && (*s)[0] == '.') if (sz <= 2 && (*s)[0] == dot)
{ {
if (sz == 1 || (*s)[1] == '.') // filename is "." or ".." if (sz == 1 || (*s)[1] == dot) // filename is "." or ".."
return { s, string_type::npos }; return { s, string_type::npos };
else else
return { s, 0 }; // filename is like ".?" return { s, 0 }; // filename is like ".?"
} }
return { s, s->rfind('.') }; return { s, s->rfind(dot) };
} }
} }
return {}; return {};
...@@ -405,7 +411,7 @@ path::_M_split_cmpts() ...@@ -405,7 +411,7 @@ path::_M_split_cmpts()
{ {
const auto& last = _M_cmpts.back(); const auto& last = _M_cmpts.back();
pos = last._M_pos + last._M_pathname.size(); pos = last._M_pos + last._M_pathname.size();
_M_cmpts.emplace_back(string_type(1, '.'), _Type::_Filename, pos); _M_cmpts.emplace_back(string_type(1, dot), _Type::_Filename, pos);
} }
} }
...@@ -495,8 +501,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -495,8 +501,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
std::string filesystem_error::_M_gen_what() std::string filesystem_error::_M_gen_what()
{ {
using std::filesystem::fs_err_concat; using std::filesystem::fs_err_concat;
return fs_err_concat(system_error::what(), _M_path1.native(), return fs_err_concat(system_error::what(), _M_path1.u8string(),
_M_path2.native()); _M_path2.u8string());
} }
_GLIBCXX_END_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_CXX11
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "dir-common.h" #include "dir-common.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace posix = std::filesystem::__gnu_posix;
struct fs::_Dir : _Dir_base struct fs::_Dir : _Dir_base
{ {
...@@ -47,7 +48,7 @@ struct fs::_Dir : _Dir_base ...@@ -47,7 +48,7 @@ struct fs::_Dir : _Dir_base
path = p; path = p;
} }
_Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
_Dir(_Dir&&) = default; _Dir(_Dir&&) = default;
...@@ -180,7 +181,7 @@ recursive_directory_iterator(const path& p, directory_options options, ...@@ -180,7 +181,7 @@ recursive_directory_iterator(const path& p, directory_options options,
error_code* ecptr) error_code* ecptr)
: _M_options(options), _M_pending(true) : _M_options(options), _M_pending(true)
{ {
if (DIR* dirp = ::opendir(p.c_str())) if (posix::DIR* dirp = posix::opendir(p.c_str()))
{ {
if (ecptr) if (ecptr)
ecptr->clear(); ecptr->clear();
......
...@@ -38,6 +38,66 @@ fs::filesystem_error::~filesystem_error() = default; ...@@ -38,6 +38,66 @@ fs::filesystem_error::~filesystem_error() = default;
constexpr path::value_type path::preferred_separator; constexpr path::value_type path::preferred_separator;
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
path&
path::operator/=(const path& __p)
{
if (__p.is_absolute()
|| (__p.has_root_name() && __p.root_name() != root_name()))
return operator=(__p);
basic_string_view<value_type> __lhs = _M_pathname;
bool __add_sep = false;
if (__p.has_root_directory())
{
// Remove any root directory and relative path
if (_M_type != _Type::_Root_name)
{
if (!_M_cmpts.empty()
&& _M_cmpts.front()._M_type == _Type::_Root_name)
__lhs = _M_cmpts.front()._M_pathname;
else
__lhs = {};
}
}
else if (has_filename() || (!has_root_directory() && is_absolute()))
__add_sep = true;
basic_string_view<value_type> __rhs = __p._M_pathname;
// Omit any root-name from the generic format pathname:
if (__p._M_type == _Type::_Root_name)
__rhs = {};
else if (!__p._M_cmpts.empty()
&& __p._M_cmpts.front()._M_type == _Type::_Root_name)
__rhs.remove_prefix(__p._M_cmpts.front()._M_pathname.size());
const size_t __len = __lhs.size() + (int)__add_sep + __rhs.size();
const size_t __maxcmpts = _M_cmpts.size() + __p._M_cmpts.size();
if (_M_pathname.capacity() < __len || _M_cmpts.capacity() < __maxcmpts)
{
// Construct new path and swap (strong exception-safety guarantee).
string_type __tmp;
__tmp.reserve(__len);
__tmp = __lhs;
if (__add_sep)
__tmp += preferred_separator;
__tmp += __rhs;
path __newp = std::move(__tmp);
swap(__newp);
}
else
{
_M_pathname = __lhs;
if (__add_sep)
_M_pathname += preferred_separator;
_M_pathname += __rhs;
_M_split_cmpts();
}
return *this;
}
#endif
path& path&
path::remove_filename() path::remove_filename()
{ {
...@@ -74,6 +134,12 @@ path::replace_filename(const path& replacement) ...@@ -74,6 +134,12 @@ path::replace_filename(const path& replacement)
return *this; return *this;
} }
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
const fs::path::value_type dot = L'.';
#else
const fs::path::value_type dot = '.';
#endif
path& path&
path::replace_extension(const path& replacement) path::replace_extension(const path& replacement)
{ {
...@@ -94,8 +160,8 @@ path::replace_extension(const path& replacement) ...@@ -94,8 +160,8 @@ path::replace_extension(const path& replacement)
} }
// If replacement is not empty and does not begin with a dot character, // If replacement is not empty and does not begin with a dot character,
// a dot character is appended // a dot character is appended
if (!replacement.empty() && replacement.native()[0] != '.') if (!replacement.empty() && replacement.native()[0] != dot)
_M_pathname += '.'; _M_pathname += dot;
operator+=(replacement); operator+=(replacement);
return *this; return *this;
} }
...@@ -332,11 +398,7 @@ path::has_filename() const ...@@ -332,11 +398,7 @@ path::has_filename() const
namespace namespace
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS inline bool is_dot(fs::path::value_type c) { return c == dot; }
inline bool is_dot(wchar_t c) { return c == L'.'; }
#else
inline bool is_dot(char c) { return c == '.'; }
#endif
inline bool is_dot(const fs::path& path) inline bool is_dot(const fs::path& path)
{ {
...@@ -376,7 +438,7 @@ path::lexically_normal() const ...@@ -376,7 +438,7 @@ path::lexically_normal() const
{ {
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// Replace each slash character in the root-name // Replace each slash character in the root-name
if (p.is_root_name()) if (p._M_type == _Type::_Root_name)
{ {
string_type s = p.native(); string_type s = p.native();
std::replace(s.begin(), s.end(), L'/', L'\\'); std::replace(s.begin(), s.end(), L'/', L'\\');
...@@ -485,7 +547,7 @@ path::lexically_proximate(const path& base) const ...@@ -485,7 +547,7 @@ path::lexically_proximate(const path& base) const
std::pair<const path::string_type*, std::size_t> std::pair<const path::string_type*, std::size_t>
path::_M_find_extension() const path::_M_find_extension() const
{ {
const std::string* s = nullptr; const string_type* s = nullptr;
if (_M_type == _Type::_Filename) if (_M_type == _Type::_Filename)
s = &_M_pathname; s = &_M_pathname;
...@@ -500,9 +562,9 @@ path::_M_find_extension() const ...@@ -500,9 +562,9 @@ path::_M_find_extension() const
{ {
if (auto sz = s->size()) if (auto sz = s->size())
{ {
if (sz <= 2 && (*s)[0] == '.') if (sz <= 2 && (*s)[0] == dot)
return { s, string_type::npos }; return { s, string_type::npos };
const auto pos = s->rfind('.'); const auto pos = s->rfind(dot);
return { s, pos ? pos : string_type::npos }; return { s, pos ? pos : string_type::npos };
} }
} }
...@@ -703,8 +765,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 ...@@ -703,8 +765,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
std::string filesystem_error::_M_gen_what() std::string filesystem_error::_M_gen_what()
{ {
return fs_err_concat(system_error::what(), _M_path1.native(), return fs_err_concat(system_error::what(), _M_path1.u8string(),
_M_path2.native()); _M_path2.u8string());
} }
_GLIBCXX_END_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_CXX11
......
...@@ -47,16 +47,17 @@ test01() ...@@ -47,16 +47,17 @@ test01()
// Test non-empty directory. // Test non-empty directory.
ec = bad_ec; ec = bad_ec;
create_directory_symlink(p, p / "l", ec); create_directory(p / "x", ec);
VERIFY( !ec ); VERIFY( !ec );
ec = bad_ec; ec = bad_ec;
iter = fs::directory_iterator(p, ec); iter = fs::directory_iterator(p, ec);
VERIFY( !ec ); VERIFY( !ec );
VERIFY( iter != fs::directory_iterator() ); VERIFY( iter != fs::directory_iterator() );
VERIFY( iter->path() == p/"l" ); VERIFY( iter->path() == p/"x" );
++iter; ++iter;
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#if !(defined(__MINGW32__) || defined(__MINGW64__))
// Test inaccessible directory. // Test inaccessible directory.
ec = bad_ec; ec = bad_ec;
permissions(p, fs::perms::none, ec); permissions(p, fs::perms::none, ec);
...@@ -71,6 +72,7 @@ test01() ...@@ -71,6 +72,7 @@ test01()
iter = fs::directory_iterator(p, opts, ec); iter = fs::directory_iterator(p, opts, ec);
VERIFY( !ec ); VERIFY( !ec );
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#endif
permissions(p, fs::perms::owner_all, ec); permissions(p, fs::perms::owner_all, ec);
remove_all(p, ec); remove_all(p, ec);
...@@ -84,7 +86,7 @@ test02() ...@@ -84,7 +86,7 @@ test02()
const auto p = __gnu_test::nonexistent_path(); const auto p = __gnu_test::nonexistent_path();
ec = bad_ec; ec = bad_ec;
create_directory(p, fs::current_path(), ec); create_directory(p, fs::current_path(), ec);
create_directory_symlink(p, p / "l", ec); create_directory(p / "x", ec);
VERIFY( !ec ); VERIFY( !ec );
// Test post-increment (libstdc++/71005) // Test post-increment (libstdc++/71005)
...@@ -95,7 +97,7 @@ test02() ...@@ -95,7 +97,7 @@ test02()
const auto entry1 = *iter; const auto entry1 = *iter;
const auto entry2 = *iter++; const auto entry2 = *iter++;
VERIFY( entry1 == entry2 ); VERIFY( entry1 == entry2 );
VERIFY( entry1.path() == p/"l" ); VERIFY( entry1.path() == p/"x" );
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
remove_all(p, ec); remove_all(p, ec);
...@@ -130,7 +132,7 @@ test05() ...@@ -130,7 +132,7 @@ test05()
{ {
auto p = __gnu_test::nonexistent_path(); auto p = __gnu_test::nonexistent_path();
create_directory(p); create_directory(p);
create_directory_symlink(p, p / "l"); create_directory(p / "x");
fs::directory_iterator it(p), endit; fs::directory_iterator it(p), endit;
VERIFY( begin(it) == it ); VERIFY( begin(it) == it );
static_assert( noexcept(begin(it)), "begin is noexcept" ); static_assert( noexcept(begin(it)), "begin is noexcept" );
......
...@@ -60,6 +60,7 @@ test01() ...@@ -60,6 +60,7 @@ test01()
++iter; ++iter;
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#if ! (defined (__MINGW32__) || defined(__MINGW64__))
// Test inaccessible directory. // Test inaccessible directory.
ec = bad_ec; ec = bad_ec;
permissions(p, fs::perms::none, ec); permissions(p, fs::perms::none, ec);
...@@ -106,6 +107,7 @@ test01() ...@@ -106,6 +107,7 @@ test01()
iter.increment(ec); // should fail to recurse into p/d1/d2, so skip it iter.increment(ec); // should fail to recurse into p/d1/d2, so skip it
VERIFY( !ec ); VERIFY( !ec );
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#endif
permissions(p/"d1/d2", fs::perms::owner_all, ec); permissions(p/"d1/d2", fs::perms::owner_all, ec);
remove_all(p, ec); remove_all(p, ec);
...@@ -171,7 +173,7 @@ test05() ...@@ -171,7 +173,7 @@ test05()
{ {
auto p = __gnu_test::nonexistent_path(); auto p = __gnu_test::nonexistent_path();
create_directory(p); create_directory(p);
create_directory_symlink(p, p / "l"); create_directory(p / "x");
fs::recursive_directory_iterator it(p), endit; fs::recursive_directory_iterator it(p), endit;
VERIFY( begin(it) == it ); VERIFY( begin(it) == it );
static_assert( noexcept(begin(it)), "begin is noexcept" ); static_assert( noexcept(begin(it)), "begin is noexcept" );
......
...@@ -41,6 +41,22 @@ test01() ...@@ -41,6 +41,22 @@ test01()
void void
test02() test02()
{ {
std::error_code ec = make_error_code(std::errc::invalid_argument);
path root = __gnu_test::root_path();
VERIFY( absolute(root) == root );
VERIFY( absolute(root, ec) == root && !ec );
VERIFY( absolute(path{}, ec).empty() && ec );
#if defined(__MINGW32__) || defined(__MINGW64__)
path p1("/");
VERIFY( absolute(p1) != p1 );
path p2("/foo");
VERIFY( absolute(p2) != p2 );
path p3("foo");
VERIFY( absolute(p3) != p3 );
path p4("C:\\");
VERIFY( absolute(p4) == p4 );
#else
path p1("/"); path p1("/");
VERIFY( absolute(p1) == p1 ); VERIFY( absolute(p1) == p1 );
path p2("/foo"); path p2("/foo");
...@@ -48,6 +64,7 @@ test02() ...@@ -48,6 +64,7 @@ test02()
path p3("foo"); path p3("foo");
VERIFY( absolute(p3) != p3 ); VERIFY( absolute(p3) != p3 );
VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) ); VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) );
#endif
} }
int int
......
...@@ -41,7 +41,7 @@ test01() ...@@ -41,7 +41,7 @@ test01()
VERIFY( !ec ); VERIFY( !ec );
ec = bad_ec; ec = bad_ec;
p2 = canonical( fs::current_path() / "." / (p.native() + "////././."), ec ); p2 = canonical( fs::current_path() / "." / (p.string() + "////././."), ec );
compare_paths( p2, fs::current_path()/p ); compare_paths( p2, fs::current_path()/p );
VERIFY( !ec ); VERIFY( !ec );
......
...@@ -116,7 +116,7 @@ test03() ...@@ -116,7 +116,7 @@ test03()
auto to = __gnu_test::nonexistent_path(); auto to = __gnu_test::nonexistent_path();
// test empty file // test empty file
std::ofstream{from.native()}; std::ofstream{from};
VERIFY( fs::exists(from) ); VERIFY( fs::exists(from) );
VERIFY( fs::file_size(from) == 0 ); VERIFY( fs::file_size(from) == 0 );
fs::copy(from, to); fs::copy(from, to);
...@@ -125,7 +125,7 @@ test03() ...@@ -125,7 +125,7 @@ test03()
remove(to); remove(to);
VERIFY( !fs::exists(to) ); VERIFY( !fs::exists(to) );
std::ofstream{from.native()} << "Hello, filesystem!"; std::ofstream{from} << "Hello, filesystem!";
VERIFY( fs::file_size(from) != 0 ); VERIFY( fs::file_size(from) != 0 );
fs::copy(from, to); fs::copy(from, to);
VERIFY( fs::exists(to) ); VERIFY( fs::exists(to) );
......
...@@ -42,7 +42,7 @@ test01() ...@@ -42,7 +42,7 @@ test01()
VERIFY( !exists(to) ); VERIFY( !exists(to) );
// test empty file // test empty file
std::ofstream{from.native()}; std::ofstream{from};
VERIFY( exists(from) ); VERIFY( exists(from) );
VERIFY( file_size(from) == 0 ); VERIFY( file_size(from) == 0 );
...@@ -58,7 +58,7 @@ test01() ...@@ -58,7 +58,7 @@ test01()
VERIFY( exists(to) ); VERIFY( exists(to) );
VERIFY( file_size(to) == 0 ); VERIFY( file_size(to) == 0 );
std::ofstream{from.native()} << "Hello, filesystem!"; std::ofstream{from} << "Hello, filesystem!";
VERIFY( file_size(from) != 0 ); VERIFY( file_size(from) != 0 );
remove(to); remove(to);
VERIFY( !exists(to) ); VERIFY( !exists(to) );
......
...@@ -29,19 +29,20 @@ void ...@@ -29,19 +29,20 @@ void
test01() test01()
{ {
const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
const path root = __gnu_test::root_path();
VERIFY( exists(path{"/"}) ); VERIFY( exists(root) );
VERIFY( exists(path{"/."}) ); VERIFY( exists(root/".") );
VERIFY( exists(path{"."}) ); VERIFY( exists(path{"."}) );
VERIFY( exists(path{".."}) ); VERIFY( exists(path{".."}) );
VERIFY( exists(std::filesystem::current_path()) ); VERIFY( exists(std::filesystem::current_path()) );
std::error_code ec; std::error_code ec;
ec = bad_ec; ec = bad_ec;
VERIFY( exists(path{"/"}, ec) ); VERIFY( exists(root, ec) );
VERIFY( !ec ); VERIFY( !ec );
ec = bad_ec; ec = bad_ec;
VERIFY( exists(path{"/."}, ec) ); VERIFY( exists(root/".", ec) );
VERIFY( !ec ); VERIFY( !ec );
ec = bad_ec; ec = bad_ec;
VERIFY( exists(path{"."}, ec) ); VERIFY( exists(path{"."}, ec) );
......
...@@ -82,7 +82,7 @@ test02() ...@@ -82,7 +82,7 @@ test02()
empty = is_empty(f.path); empty = is_empty(f.path);
VERIFY( empty ); VERIFY( empty );
std::ofstream{f.path.native()} << "data"; std::ofstream{f.path} << "data";
ec = bad_ec; ec = bad_ec;
empty = is_empty(p, ec); empty = is_empty(p, ec);
VERIFY( !ec ); VERIFY( !ec );
......
...@@ -81,7 +81,7 @@ test01() ...@@ -81,7 +81,7 @@ test01()
::utimbuf times; ::utimbuf times;
times.modtime = std::numeric_limits<std::time_t>::max() - 1; times.modtime = std::numeric_limits<std::time_t>::max() - 1;
times.actime = std::numeric_limits<std::time_t>::max() - 1; times.actime = std::numeric_limits<std::time_t>::max() - 1;
VERIFY( !::utime(p.c_str(), &times) ); VERIFY( !::utime(p.string().c_str(), &times) );
#else #else
return; return;
#endif #endif
......
...@@ -25,25 +25,35 @@ ...@@ -25,25 +25,35 @@
#include <testsuite_fs.h> #include <testsuite_fs.h>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
bool check(std::filesystem::space_info const& s)
{
const std::uintmax_t err = -1;
return s.capacity != err || s.free != err || s.available != err;
}
void void
test01() test01()
{ {
std::filesystem::space_info s = std::filesystem::space("/"); const std::filesystem::path root = __gnu_test::root_path();
std::filesystem::space_info s = std::filesystem::space(root);
std::error_code ec = make_error_code(std::errc::invalid_argument); std::error_code ec = make_error_code(std::errc::invalid_argument);
s = std::filesystem::space("/", ec); s = std::filesystem::space(root, ec);
VERIFY( !ec ); VERIFY( !ec );
VERIFY( check(s) );
VERIFY( s.capacity >= s.free );
s = std::filesystem::space(__gnu_test::nonexistent_path(), ec); s = std::filesystem::space(__gnu_test::nonexistent_path()/".", ec);
VERIFY( ec ); if (ec)
VERIFY( s.capacity == static_cast<uintmax_t>(-1) ); VERIFY( ! check(s) );
VERIFY( s.free == static_cast<uintmax_t>(-1) ); else
VERIFY( s.available == static_cast<uintmax_t>(-1) ); VERIFY( check(s) );
} }
void void
test02() test02()
{ {
std::filesystem::space_info s = std::filesystem::space("."); std::filesystem::space_info s = std::filesystem::space(".");
VERIFY( check(s) );
VERIFY( s.capacity >= s.free ); VERIFY( s.capacity >= s.free );
} }
......
...@@ -27,10 +27,28 @@ ...@@ -27,10 +27,28 @@
void void
clean_env() clean_env()
{ {
#if defined(__MINGW32__) || defined(__MINGW64__)
::_putenv("TMP=");
::_putenv("TEMP=");
#else
::unsetenv("TMPDIR"); ::unsetenv("TMPDIR");
::unsetenv("TMP"); ::unsetenv("TMP");
::unsetenv("TEMPDIR"); ::unsetenv("TEMPDIR");
::unsetenv("TEMP"); ::unsetenv("TEMP");
#endif
}
bool
set_env(const char* name, std::string value)
{
#if defined(__MINGW32__) || defined(__MINGW64__)
std::string s = name;
s += '=';
s += value;
return !::_putenv(s.c_str());
#else
return !::setenv(name, value.c_str(), 1);
#endif
} }
namespace fs = std::filesystem; namespace fs = std::filesystem;
...@@ -57,7 +75,7 @@ test02() ...@@ -57,7 +75,7 @@ test02()
{ {
clean_env(); clean_env();
if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1)) if (!set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
return; // just give up return; // just give up
std::error_code ec; std::error_code ec;
...@@ -80,7 +98,7 @@ test03() ...@@ -80,7 +98,7 @@ test03()
auto p = __gnu_test::nonexistent_path(); auto p = __gnu_test::nonexistent_path();
create_directories(p/"tmp"); create_directories(p/"tmp");
permissions(p, fs::perms::none); permissions(p, fs::perms::none);
setenv("TMPDIR", (p/"tmp").c_str(), 1); set_env("TMPDIR", (p/"tmp").string());
std::error_code ec; std::error_code ec;
auto r = fs::temp_directory_path(ec); // libstdc++/PR71337 auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
VERIFY( ec == std::make_error_code(std::errc::permission_denied) ); VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
...@@ -102,7 +120,7 @@ void ...@@ -102,7 +120,7 @@ void
test04() test04()
{ {
__gnu_test::scoped_file f; __gnu_test::scoped_file f;
setenv("TMPDIR", f.path.c_str(), 1); set_env("TMPDIR", f.path.string());
std::error_code ec; std::error_code ec;
auto r = fs::temp_directory_path(ec); auto r = fs::temp_directory_path(ec);
VERIFY( ec == std::make_error_code(std::errc::not_a_directory) ); VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
......
...@@ -55,6 +55,10 @@ test01() ...@@ -55,6 +55,10 @@ test01()
compare_paths( append("dir/", "/file"), "/file" ); compare_paths( append("dir/", "/file"), "/file" );
compare_paths( append("dir/", "file"), "dir/file" ); compare_paths( append("dir/", "file"), "dir/file" );
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
compare_paths( append("c:/foo", "/bar"), "c:/bar" );
#endif
} }
void void
......
...@@ -30,7 +30,7 @@ void ...@@ -30,7 +30,7 @@ void
test01() test01()
{ {
// path(string_type&&, format) // path(string_type&&, format)
auto s = [&]() -> path::string_type { return "foo/bar"; }; auto s = [&]() -> path::string_type { return path("foo/bar").native(); };
path p0(s()); path p0(s());
path p1(s(), path::auto_format); path p1(s(), path::auto_format);
VERIFY( p1 == p0 ); VERIFY( p1 == p0 );
...@@ -44,7 +44,7 @@ void ...@@ -44,7 +44,7 @@ void
test02() test02()
{ {
// path(const Source&, format) // path(const Source&, format)
path::string_type s = "foo/bar"; const path::string_type s = path("foo/bar").native();
path p0(s); path p0(s);
path p1(s, path::auto_format); path p1(s, path::auto_format);
VERIFY( p1 == p0 ); VERIFY( p1 == p0 );
...@@ -58,7 +58,7 @@ void ...@@ -58,7 +58,7 @@ void
test03() test03()
{ {
// path(const Source&, format) // path(const Source&, format)
std::string s = "foo/bar"; const std::string s = "foo/bar";
path p0(s); path p0(s);
path p1(s, path::auto_format); path p1(s, path::auto_format);
VERIFY( p1 == p0 ); VERIFY( p1 == p0 );
...@@ -73,7 +73,7 @@ test04() ...@@ -73,7 +73,7 @@ test04()
{ {
#ifdef _GLIBCXX_USE_WCHAR_T #ifdef _GLIBCXX_USE_WCHAR_T
// path(const Source&, format) // path(const Source&, format)
std::wstring s = L"foo/bar"; const std::wstring s = L"foo/bar";
path p0(s); path p0(s);
path p1(s, path::auto_format); path p1(s, path::auto_format);
VERIFY( p1 == p0 ); VERIFY( p1 == p0 );
......
...@@ -31,7 +31,11 @@ void ...@@ -31,7 +31,11 @@ void
test01() test01()
{ {
path p("/foo/bar", std::locale::classic()); path p("/foo/bar", std::locale::classic());
#if defined(__MINGW32__) || defined(__MINGW64__)
VERIFY( p.native() == L"/foo/bar" );
#else
VERIFY( p.native() == "/foo/bar" ); VERIFY( p.native() == "/foo/bar" );
#endif
} }
void void
......
...@@ -47,7 +47,12 @@ test02() ...@@ -47,7 +47,12 @@ test02()
{ {
path rootdir = p.root_directory(); path rootdir = p.root_directory();
VERIFY( !rootdir.has_relative_path() ); VERIFY( !rootdir.has_relative_path() );
VERIFY( rootdir.empty() || rootdir.native() == "/"); if (!rootdir.empty())
#if defined(__MINGW32__) || defined(__MINGW64__)
VERIFY( rootdir.string() == "/" || rootdir.string() == "\\" );
#else
VERIFY( rootdir.string() == "/" );
#endif
} }
} }
......
...@@ -35,7 +35,7 @@ test01() ...@@ -35,7 +35,7 @@ test01()
path p = "foo.bar.baz.tar"; path p = "foo.bar.baz.tar";
std::vector<std::string> v; std::vector<std::string> v;
for (; !p.extension().empty(); p = p.stem()) for (; !p.extension().empty(); p = p.stem())
v.push_back(p.extension().native()); v.push_back(p.extension().string());
VERIFY( v.at(0) == ".tar" ); VERIFY( v.at(0) == ".tar" );
VERIFY( v.at(1) == ".baz" ); VERIFY( v.at(1) == ".baz" );
VERIFY( v.at(2) == ".bar" ); VERIFY( v.at(2) == ".bar" );
......
...@@ -83,6 +83,24 @@ test01() ...@@ -83,6 +83,24 @@ test01()
v2 = { "/", "rootname", "dir", "filename" }; v2 = { "/", "rootname", "dir", "filename" };
#endif #endif
VERIFY( v == v2 ); VERIFY( v == v2 );
p = "c:relative/path";
v.assign(p.begin(), p.end());
#if defined(__MINGW32__) || defined(__MINGW64__)
v2 = { "c:", "relative", "path" };
#else
v2 = { "c:relative", "path" };
#endif
VERIFY( v == v2 );
p = "c:/absolute/path";
v.assign(p.begin(), p.end());
#if defined(__MINGW32__) || defined(__MINGW64__)
v2 = { "c:", "/", "absolute", "path" };
#else
v2 = { "c:", "absolute", "path" };
#endif
VERIFY( v == v2 );
} }
void void
......
...@@ -27,14 +27,15 @@ void ...@@ -27,14 +27,15 @@ void
test01() test01()
{ {
using namespace std::filesystem; using namespace std::filesystem;
const std::string s = "abc"; using string_type = std::basic_string<path::value_type>;
const string_type s{ 'a', 'b', 'c' };
path p(s); path p(s);
VERIFY( p.native() == s ); VERIFY( p.native() == s );
VERIFY( p.c_str() == s ); VERIFY( p.c_str() == s );
VERIFY( static_cast<std::string>(p) == s ); VERIFY( static_cast<string_type>(p) == s );
std::string s2 = p; // implicit conversion string_type s2 = p; // implicit conversion
VERIFY( s2 == p.native() ); VERIFY( s2 == p.native() );
} }
......
...@@ -29,11 +29,17 @@ using std::filesystem::path; ...@@ -29,11 +29,17 @@ using std::filesystem::path;
void void
test01() test01()
{ {
VERIFY( path("/").is_absolute() ); #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
VERIFY( path("/foo").is_absolute() ); const bool is_posix = false;
VERIFY( path("/foo/").is_absolute() ); #else
VERIFY( path("/foo/bar").is_absolute() ); const bool is_posix = true;
VERIFY( path("/foo/bar/").is_absolute() ); #endif
VERIFY( path("/").is_absolute() == is_posix );
VERIFY( path("/foo").is_absolute() == is_posix );
VERIFY( path("/foo/").is_absolute() == is_posix );
VERIFY( path("/foo/bar").is_absolute() == is_posix );
VERIFY( path("/foo/bar/").is_absolute() == is_posix );
VERIFY( ! path("foo").is_absolute() ); VERIFY( ! path("foo").is_absolute() );
VERIFY( ! path("foo/").is_absolute() ); VERIFY( ! path("foo/").is_absolute() );
VERIFY( ! path("foo/bar").is_absolute() ); VERIFY( ! path("foo/bar").is_absolute() );
...@@ -43,16 +49,11 @@ test01() ...@@ -43,16 +49,11 @@ test01()
VERIFY( ! path("c:foo/").is_absolute() ); VERIFY( ! path("c:foo/").is_absolute() );
VERIFY( ! path("c:foo/bar").is_absolute() ); VERIFY( ! path("c:foo/bar").is_absolute() );
VERIFY( ! path("c:foo/bar/").is_absolute() ); VERIFY( ! path("c:foo/bar/").is_absolute() );
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS VERIFY( path("c:/").is_absolute() == !is_posix );
const bool drive_letter_is_root_name = true; VERIFY( path("c:/foo").is_absolute() == !is_posix );
#else VERIFY( path("c:/foo/").is_absolute() == !is_posix );
const bool drive_letter_is_root_name = false; VERIFY( path("c:/foo/bar").is_absolute() == !is_posix );
#endif VERIFY( path("c:/foo/bar/").is_absolute() == !is_posix );
VERIFY( path("c:/").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/bar").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/bar/").is_absolute() == drive_letter_is_root_name );
} }
int int
......
...@@ -44,15 +44,16 @@ test01() ...@@ -44,15 +44,16 @@ test01()
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
// Test non-empty directory. // Test non-empty directory.
create_directory_symlink(p, p / "l", ec); create_directory(p / "x", ec);
VERIFY( !ec ); VERIFY( !ec );
iter = fs::directory_iterator(p, ec); iter = fs::directory_iterator(p, ec);
VERIFY( !ec ); VERIFY( !ec );
VERIFY( iter != fs::directory_iterator() ); VERIFY( iter != fs::directory_iterator() );
VERIFY( iter->path() == p/"l" ); VERIFY( iter->path() == p/"x" );
++iter; ++iter;
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#if !(defined(__MINGW32__) || defined(__MINGW64__))
// Test inaccessible directory. // Test inaccessible directory.
permissions(p, fs::perms::none, ec); permissions(p, fs::perms::none, ec);
VERIFY( !ec ); VERIFY( !ec );
...@@ -65,6 +66,7 @@ test01() ...@@ -65,6 +66,7 @@ test01()
iter = fs::directory_iterator(p, opts, ec); iter = fs::directory_iterator(p, opts, ec);
VERIFY( !ec ); VERIFY( !ec );
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
#endif
permissions(p, fs::perms::owner_all, ec); permissions(p, fs::perms::owner_all, ec);
remove_all(p, ec); remove_all(p, ec);
...@@ -76,7 +78,7 @@ test02() ...@@ -76,7 +78,7 @@ test02()
std::error_code ec; std::error_code ec;
const auto p = __gnu_test::nonexistent_path(); const auto p = __gnu_test::nonexistent_path();
create_directory(p, fs::current_path(), ec); create_directory(p, fs::current_path(), ec);
create_directory_symlink(p, p / "l", ec); create_directory(p / "x", ec);
VERIFY( !ec ); VERIFY( !ec );
// Test post-increment (libstdc++/71005) // Test post-increment (libstdc++/71005)
...@@ -86,7 +88,7 @@ test02() ...@@ -86,7 +88,7 @@ test02()
const auto entry1 = *iter; const auto entry1 = *iter;
const auto entry2 = *iter++; const auto entry2 = *iter++;
VERIFY( entry1 == entry2 ); VERIFY( entry1 == entry2 );
VERIFY( entry1.path() == p/"l" ); VERIFY( entry1.path() == p/"x" );
VERIFY( iter == end(iter) ); VERIFY( iter == end(iter) );
remove_all(p, ec); remove_all(p, ec);
...@@ -121,7 +123,7 @@ test05() ...@@ -121,7 +123,7 @@ test05()
{ {
auto p = __gnu_test::nonexistent_path(); auto p = __gnu_test::nonexistent_path();
create_directory(p); create_directory(p);
create_directory_symlink(p, p / "l"); create_directory(p / "x");
fs::directory_iterator it(p), endit; fs::directory_iterator it(p), endit;
VERIFY( begin(it) == it ); VERIFY( begin(it) == it );
static_assert( noexcept(begin(it)), "begin is noexcept" ); static_assert( noexcept(begin(it)), "begin is noexcept" );
......
...@@ -31,12 +31,29 @@ void ...@@ -31,12 +31,29 @@ void
test01() test01()
{ {
for (const path& p : __gnu_test::test_paths) for (const path& p : __gnu_test::test_paths)
{
#if defined(__MINGW32__) || defined(__MINGW64__)
if (p.empty())
continue;
#endif
VERIFY( absolute(p).is_absolute() ); VERIFY( absolute(p).is_absolute() );
}
} }
void void
test02() test02()
{ {
#if defined(__MINGW32__) || defined(__MINGW64__)
path p1("/");
VERIFY( absolute(p1) != p1 );
path p2("/foo");
VERIFY( absolute(p2) != p2 );
path p3("foo");
VERIFY( absolute(p3) != p3 );
path p4("C:\\");
VERIFY( absolute(p3, p4) == "C:\\foo" );
VERIFY( absolute(p4) == p4 );
#else
path p1("/"); path p1("/");
VERIFY( absolute(p1) == p1 ); VERIFY( absolute(p1) == p1 );
VERIFY( absolute(p1, "/bar") == p1 ); VERIFY( absolute(p1, "/bar") == p1 );
...@@ -46,6 +63,7 @@ test02() ...@@ -46,6 +63,7 @@ test02()
path p3("foo"); path p3("foo");
VERIFY( absolute(p3) != p3 ); VERIFY( absolute(p3) != p3 );
VERIFY( absolute(p3, "/bar") == "/bar/foo" ); VERIFY( absolute(p3, "/bar") == "/bar/foo" );
#endif
} }
int int
......
...@@ -114,7 +114,7 @@ test03() ...@@ -114,7 +114,7 @@ test03()
auto to = __gnu_test::nonexistent_path(); auto to = __gnu_test::nonexistent_path();
// test empty file // test empty file
std::ofstream{from.native()}; std::ofstream{from.c_str()};
VERIFY( fs::exists(from) ); VERIFY( fs::exists(from) );
VERIFY( fs::file_size(from) == 0 ); VERIFY( fs::file_size(from) == 0 );
fs::copy(from, to); fs::copy(from, to);
...@@ -123,7 +123,7 @@ test03() ...@@ -123,7 +123,7 @@ test03()
remove(to); remove(to);
VERIFY( !fs::exists(to) ); VERIFY( !fs::exists(to) );
std::ofstream{from.native()} << "Hello, filesystem!"; std::ofstream{from.c_str()} << "Hello, filesystem!";
VERIFY( fs::file_size(from) != 0 ); VERIFY( fs::file_size(from) != 0 );
fs::copy(from, to); fs::copy(from, to);
VERIFY( fs::exists(to) ); VERIFY( fs::exists(to) );
...@@ -150,9 +150,9 @@ test04() ...@@ -150,9 +150,9 @@ test04()
} }
__gnu_test::scoped_file f1(from/"a/f1"); __gnu_test::scoped_file f1(from/"a/f1");
std::ofstream{f1.path} << "file one"; std::ofstream{f1.path.c_str()} << "file one";
__gnu_test::scoped_file f2(from/"a/b/f2"); __gnu_test::scoped_file f2(from/"a/b/f2");
std::ofstream{f2.path} << "file two"; std::ofstream{f2.path.c_str()} << "file two";
copy(from, to, ec); copy(from, to, ec);
VERIFY( !ec ); VERIFY( !ec );
......
...@@ -42,7 +42,7 @@ test01() ...@@ -42,7 +42,7 @@ test01()
VERIFY( !exists(to) ); VERIFY( !exists(to) );
// test empty file // test empty file
std::ofstream{from.native()}; std::ofstream{from.c_str()};
VERIFY( exists(from) ); VERIFY( exists(from) );
VERIFY( file_size(from) == 0 ); VERIFY( file_size(from) == 0 );
...@@ -58,7 +58,7 @@ test01() ...@@ -58,7 +58,7 @@ test01()
VERIFY( exists(to) ); VERIFY( exists(to) );
VERIFY( file_size(to) == 0 ); VERIFY( file_size(to) == 0 );
std::ofstream{from.native()} << "Hello, filesystem!"; std::ofstream{from.c_str()} << "Hello, filesystem!";
VERIFY( file_size(from) != 0 ); VERIFY( file_size(from) != 0 );
remove(to); remove(to);
VERIFY( !exists(to) ); VERIFY( !exists(to) );
......
...@@ -28,16 +28,18 @@ using std::experimental::filesystem::path; ...@@ -28,16 +28,18 @@ using std::experimental::filesystem::path;
void void
test01() test01()
{ {
VERIFY( exists(path{"/"}) ); const path root = __gnu_test::root_path();
VERIFY( exists(path{"/."}) );
VERIFY( exists(root) );
VERIFY( exists(root/".") );
VERIFY( exists(path{"."}) ); VERIFY( exists(path{"."}) );
VERIFY( exists(path{".."}) ); VERIFY( exists(path{".."}) );
VERIFY( exists(std::experimental::filesystem::current_path()) ); VERIFY( exists(std::experimental::filesystem::current_path()) );
std::error_code ec = std::make_error_code(std::errc::invalid_argument); std::error_code ec = std::make_error_code(std::errc::invalid_argument);
VERIFY( exists(path{"/"}, ec) ); VERIFY( exists(root, ec) );
VERIFY( !ec ); VERIFY( !ec );
VERIFY( exists(path{"/."}, ec) ); VERIFY( exists(root/".", ec) );
VERIFY( !ec ); VERIFY( !ec );
VERIFY( exists(path{"."}, ec) ); VERIFY( exists(path{"."}, ec) );
VERIFY( !ec ); VERIFY( !ec );
......
...@@ -82,7 +82,7 @@ test02() ...@@ -82,7 +82,7 @@ test02()
empty = is_empty(f.path); empty = is_empty(f.path);
VERIFY( empty ); VERIFY( empty );
std::ofstream{f.path.native()} << "data"; std::ofstream{f.path.c_str()} << "data";
ec = bad_ec; ec = bad_ec;
empty = is_empty(p, ec); empty = is_empty(p, ec);
VERIFY( !ec ); VERIFY( !ec );
......
...@@ -81,7 +81,7 @@ test01() ...@@ -81,7 +81,7 @@ test01()
::utimbuf times; ::utimbuf times;
times.modtime = std::numeric_limits<std::time_t>::max() - 1; times.modtime = std::numeric_limits<std::time_t>::max() - 1;
times.actime = std::numeric_limits<std::time_t>::max() - 1; times.actime = std::numeric_limits<std::time_t>::max() - 1;
VERIFY( !::utime(p.c_str(), &times) ); VERIFY( !::utime(p.string().c_str(), &times) );
#else #else
return; return;
#endif #endif
......
...@@ -30,9 +30,10 @@ namespace fs = std::experimental::filesystem; ...@@ -30,9 +30,10 @@ namespace fs = std::experimental::filesystem;
void void
test01() test01()
{ {
fs::space_info s = fs::space("/"); const fs::path root = __gnu_test::root_path();
fs::space_info s = fs::space(root);
std::error_code ec = make_error_code(std::errc::invalid_argument); std::error_code ec = make_error_code(std::errc::invalid_argument);
s = fs::space("/", ec); s = fs::space(root, ec);
VERIFY( !ec ); VERIFY( !ec );
s = fs::space(__gnu_test::nonexistent_path(), ec); s = fs::space(__gnu_test::nonexistent_path(), ec);
......
...@@ -27,10 +27,28 @@ ...@@ -27,10 +27,28 @@
void void
clean_env() clean_env()
{ {
#if defined(__MINGW32__) || defined(__MINGW64__)
::_putenv("TMP=");
::_putenv("TEMP=");
#else
::unsetenv("TMPDIR"); ::unsetenv("TMPDIR");
::unsetenv("TMP"); ::unsetenv("TMP");
::unsetenv("TEMPDIR"); ::unsetenv("TEMPDIR");
::unsetenv("TEMP"); ::unsetenv("TEMP");
#endif
}
bool
set_env(const char* name, std::string value)
{
#if defined(__MINGW32__) || defined(__MINGW64__)
std::string s = name;
s += '=';
s += value;
return !::_putenv(s.c_str());
#else
return !::setenv(name, value.c_str(), 1);
#endif
} }
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
...@@ -57,7 +75,7 @@ test02() ...@@ -57,7 +75,7 @@ test02()
{ {
clean_env(); clean_env();
if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1)) if (set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
return; // just give up return; // just give up
std::error_code ec; std::error_code ec;
...@@ -80,7 +98,7 @@ test03() ...@@ -80,7 +98,7 @@ test03()
auto p = __gnu_test::nonexistent_path(); auto p = __gnu_test::nonexistent_path();
create_directories(p/"tmp"); create_directories(p/"tmp");
permissions(p, fs::perms::none); permissions(p, fs::perms::none);
setenv("TMPDIR", (p/"tmp").c_str(), 1); set_env("TMPDIR", (p/"tmp").string());
std::error_code ec; std::error_code ec;
auto r = fs::temp_directory_path(ec); // libstdc++/PR71337 auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
VERIFY( ec == std::make_error_code(std::errc::permission_denied) ); VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
...@@ -102,7 +120,7 @@ void ...@@ -102,7 +120,7 @@ void
test04() test04()
{ {
__gnu_test::scoped_file f; __gnu_test::scoped_file f;
setenv("TMPDIR", f.path.c_str(), 1); set_env("TMPDIR", f.path.string());
std::error_code ec; std::error_code ec;
auto r = fs::temp_directory_path(ec); auto r = fs::temp_directory_path(ec);
VERIFY( ec == std::make_error_code(std::errc::not_a_directory) ); VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
......
...@@ -34,16 +34,20 @@ test01() ...@@ -34,16 +34,20 @@ test01()
path pp = p; path pp = p;
pp /= p; pp /= p;
VERIFY( pp.native() == "/foo/bar/foo/bar" ); VERIFY( pp.string() == "/foo/bar/foo/bar" );
path q("baz"); path q("baz");
path qq = q; path qq = q;
qq /= q; qq /= q;
VERIFY( qq.native() == "baz/baz" ); #if defined(__MINGW32__) || defined(__MINGW64__)
VERIFY( qq.string() == "baz\\baz" );
#else
VERIFY( qq.string() == "baz/baz" );
#endif
q /= p; q /= p;
VERIFY( q.native() == "baz/foo/bar" ); VERIFY( q.string() == "baz/foo/bar" );
path r = ""; path r = "";
r /= path(); r /= path();
...@@ -54,7 +58,7 @@ test01() ...@@ -54,7 +58,7 @@ test01()
path s = "dir/"; path s = "dir/";
s /= path("/file"); s /= path("/file");
VERIFY( s.native() == "dir//file" ); VERIFY( s.string() == "dir//file" );
} }
int int
......
...@@ -34,18 +34,18 @@ test01() ...@@ -34,18 +34,18 @@ test01()
path pp = p; path pp = p;
pp += p; pp += p;
VERIFY( pp.native() == "/foo/bar/foo/bar" ); VERIFY( pp.string() == "/foo/bar/foo/bar" );
VERIFY( std::distance(pp.begin(), pp.end()) == 5 ); VERIFY( std::distance(pp.begin(), pp.end()) == 5 );
path q("foo/bar"); path q("foo/bar");
path qq = q; path qq = q;
qq += q; qq += q;
VERIFY( qq.native() == "foo/barfoo/bar" ); VERIFY( qq.string() == "foo/barfoo/bar" );
VERIFY( std::distance(qq.begin(), qq.end()) == 3 ); VERIFY( std::distance(qq.begin(), qq.end()) == 3 );
q += p; q += p;
VERIFY( q.native() == "foo/bar/foo/bar" ); VERIFY( q.string() == "foo/bar/foo/bar" );
VERIFY( std::distance(q.begin(), q.end()) == 4 ); VERIFY( std::distance(q.begin(), q.end()) == 4 );
} }
......
...@@ -48,8 +48,8 @@ test02() ...@@ -48,8 +48,8 @@ test02()
path rootdir = p.root_directory(); path rootdir = p.root_directory();
// If root-directory is composed of 'slash name', // If root-directory is composed of 'slash name',
// 'slash' is excluded from the returned string. // 'slash' is excluded from the returned string.
if (!rootdir.empty() && rootdir.native() != "/") if (!rootdir.empty() && rootdir.string() != "/")
VERIFY( rootdir.native()[0] != '/' ); VERIFY( rootdir.string()[0] != '/' );
} }
} }
......
...@@ -35,7 +35,7 @@ test01() ...@@ -35,7 +35,7 @@ test01()
path p = "foo.bar.baz.tar"; path p = "foo.bar.baz.tar";
std::vector<std::string> v; std::vector<std::string> v;
for (; !p.extension().empty(); p = p.stem()) for (; !p.extension().empty(); p = p.stem())
v.push_back(p.extension().native()); v.push_back(p.extension().string());
VERIFY( v.at(0) == ".tar" ); VERIFY( v.at(0) == ".tar" );
VERIFY( v.at(1) == ".baz" ); VERIFY( v.at(1) == ".baz" );
VERIFY( v.at(2) == ".bar" ); VERIFY( v.at(2) == ".bar" );
......
...@@ -27,14 +27,15 @@ void ...@@ -27,14 +27,15 @@ void
test01() test01()
{ {
using namespace std::experimental::filesystem; using namespace std::experimental::filesystem;
const std::string s = "abc"; using string_type = std::basic_string<path::value_type>;
const string_type s{ 'a', 'b', 'c' };
path p(s); path p(s);
VERIFY( p.native() == s ); VERIFY( p.native() == s );
VERIFY( p.c_str() == s ); VERIFY( p.c_str() == s );
VERIFY( static_cast<std::string>(p) == s ); VERIFY( static_cast<string_type>(p) == s );
std::string s2 = p; // implicit conversion string_type s2 = p; // implicit conversion
VERIFY( s2 == p.native() ); VERIFY( s2 == p.native() );
} }
......
...@@ -29,11 +29,17 @@ using std::filesystem::path; ...@@ -29,11 +29,17 @@ using std::filesystem::path;
void void
test01() test01()
{ {
VERIFY( path("/").is_absolute() ); #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
VERIFY( path("/foo").is_absolute() ); const bool is_posix = false;
VERIFY( path("/foo/").is_absolute() ); #else
VERIFY( path("/foo/bar").is_absolute() ); const bool is_posix = true;
VERIFY( path("/foo/bar/").is_absolute() ); #endif
VERIFY( path("/").is_absolute() == is_posix );
VERIFY( path("/foo").is_absolute() == is_posix );
VERIFY( path("/foo/").is_absolute() == is_posix );
VERIFY( path("/foo/bar").is_absolute() == is_posix );
VERIFY( path("/foo/bar/").is_absolute() == is_posix );
VERIFY( ! path("foo").is_absolute() ); VERIFY( ! path("foo").is_absolute() );
VERIFY( ! path("foo/").is_absolute() ); VERIFY( ! path("foo/").is_absolute() );
VERIFY( ! path("foo/bar").is_absolute() ); VERIFY( ! path("foo/bar").is_absolute() );
...@@ -43,16 +49,11 @@ test01() ...@@ -43,16 +49,11 @@ test01()
VERIFY( ! path("c:foo/").is_absolute() ); VERIFY( ! path("c:foo/").is_absolute() );
VERIFY( ! path("c:foo/bar").is_absolute() ); VERIFY( ! path("c:foo/bar").is_absolute() );
VERIFY( ! path("c:foo/bar/").is_absolute() ); VERIFY( ! path("c:foo/bar/").is_absolute() );
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS VERIFY( path("c:/").is_absolute() == !is_posix );
const bool drive_letter_is_root_name = true; VERIFY( path("c:/foo").is_absolute() == !is_posix );
#else VERIFY( path("c:/foo/").is_absolute() == !is_posix );
const bool drive_letter_is_root_name = false; VERIFY( path("c:/foo/bar").is_absolute() == !is_posix );
#endif VERIFY( path("c:/foo/bar/").is_absolute() == !is_posix );
VERIFY( path("c:/").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/bar").is_absolute() == drive_letter_is_root_name );
VERIFY( path("c:/foo/bar/").is_absolute() == drive_letter_is_root_name );
} }
int int
......
...@@ -73,6 +73,16 @@ namespace __gnu_test ...@@ -73,6 +73,16 @@ namespace __gnu_test
"a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c" "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
}; };
test_fs::path
root_path()
{
#if defined(__MING32__) || defined(__MINGW64__)
return L"c:/";
#else
return "/";
#endif
}
// This is NOT supposed to be a secure way to get a unique name! // This is NOT supposed to be a secure way to get a unique name!
// We just need a path that doesn't exist for testing purposes. // We just need a path that doesn't exist for testing purposes.
test_fs::path test_fs::path
...@@ -111,7 +121,7 @@ namespace __gnu_test ...@@ -111,7 +121,7 @@ namespace __gnu_test
explicit explicit
scoped_file(const path_type& p = nonexistent_path()) : path(p) scoped_file(const path_type& p = nonexistent_path()) : path(p)
{ std::ofstream{p.native()}; } { std::ofstream{p.c_str()}; }
scoped_file(path_type p, adopt_file_t) : path(p) { } scoped_file(path_type p, adopt_file_t) : path(p) { }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment