[patch] Implement ISO/IEC TS 18822 C++ File system TS
Jonathan Wakely
jwakely@redhat.com
Fri May 1 19:49:00 GMT 2015
On 01/05/15 11:53 +0100, Jonathan Wakely wrote:
>On 01/05/15 10:05 +0900, Luke Allardyce wrote:
>>This fails on mingw-w64 4.02 due to
>
>Yay, thanks for trying it!
>
>>an extra typename:
>>
>>/mnt/build/native/gcc/x86_64-w64-mingw32/libstdc++-v3/include/experimental/fs_path.h:784:35:
>>error: expected nested-name-specifier
>> using _CharAlloc = typename __alloc_rebind<_Allocator, char>;
>
>Oops, forgetting how to use my own alias.
>
>
>>readdir_r not available:
>>
>>/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:169:46: error:
>>'readdir_r' was not declared in this scope
>> if (int err = readdir_r(dirp, &ent, &result))
>>
>>
>>and calling opendir with a wchar_t*
>>
>>/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:108:40: error: cannot
>>convert 'const value_type* {aka const wchar_t*}' to 'const char*' for
>>argument '1' to 'DIR* opendir(const char*)'
>> if (DIR* dirp = ::opendir(p.c_str()))
>>
>>/mnt/src/gcc/libstdc++-v3/src/filesystem/dir.cc:256:38: error: cannot
>>convert 'const value_type* {aka const wchar_t*}' to 'const char*' for
>>argument '1' to 'DIR* opendir(const char*)'
>> if (DIR* dirp = ::opendir(p.c_str()))
>
>Ah interesting, this means mingw supports <dirent.h>, I was expecting
>it to use the dummy definitions at the top of src/filesystem/dir.cc
>(where I'd made opendir take wchar_t).
>
>I've done some reading and am going to commit some fixes and
>improvements for mingw in an hour or two. It would be great if you
>could try it again after that.
I've committed the two changes attached (only tested on linux again).
patch2.txt should fix the mingw-w64 errors above, as well as the
issues Daniel reported, and should fix the error on Solaris 10
Rainer, would you be able to test with
--enable-libstdcxx-filesystem-ts before we re-enable it to build by
default on solaris* ?
patch1.txt changes path::_M_cmpts from std::list to std::vector (as
Marc suggested months ago) and fixes the pretty printer, so paths are
shown like this in GDB:
(gdb) print p
$1 = filesystem::path ""
(gdb) print c
$2 = filesystem::path "/home/jwakely" = {[root-directory] = "/", [1] = "home", [2] = "jwakely"}
(gdb) print r
$3 = filesystem::path "/" [root-directory]
(gdb) print h
$4 = filesystem::path "home"
(gdb) print l
$5 = filesystem::path "//host/foo/bar///baz/.//xyzzy/meta/syntactic/variable" = {[root-name] = "//host", [root-directory] = "/", [2] = "foo", [3] = "bar", [4] = "baz", [5] = ".", [6] = "xyzzy", [7] = "meta", [8] = "syntactic", [9] = "variable"}
That output came from debugging this code:
path p;
path c = current_path();
path r = *c.begin();
path h = *std::next(c.begin());
path l = "//host/foo/bar///baz/.//xyzzy/meta/syntactic/variable";
Thanks everyone for testing and feedback, it's been very helpful.
-------------- next part --------------
commit 44990ad8ae2cafab954b9e64556fc2ca0db97d7e
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Fri May 1 13:41:42 2015 +0100
* include/experimental/fs_path.h (path::_List): Use vector instead of
list.
* python/libstdcxx/v6/printers.py (StdExpPathPrinter): Adapt.
* src/filesystem/path.cc: Use std::prev instead of decrementing
rvalues. Fix whitespace.
* testsuite/experimental/filesystem/path/decompose/parent_path.cc:
Do not decrement iterators before begin.
diff --git a/libstdc++-v3/include/experimental/fs_path.h b/libstdc++-v3/include/experimental/fs_path.h
index 11b0561..e57a08b 100644
--- a/libstdc++-v3/include/experimental/fs_path.h
+++ b/libstdc++-v3/include/experimental/fs_path.h
@@ -36,7 +36,7 @@
#include <utility>
#include <type_traits>
-#include <list>
+#include <vector>
#include <locale>
#include <iosfwd>
#include <codecvt>
@@ -430,7 +430,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
string_type _M_pathname;
struct _Cmpt;
- using _List = std::list<_Cmpt>;
+ using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
_List _M_cmpts; // empty unless _M_type == _Type::_Multi
_Type _M_type = _Type::_Multi;
};
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 37c3b9b..c6f96d7 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -984,16 +984,51 @@ class StdExpPathPrinter:
def __init__ (self, typename, val):
self.val = val
- self.list_visualizer = gdb.default_visualizer(val['_M_cmpts'])
+ start = self.val['_M_cmpts']['_M_impl']['_M_start']
+ finish = self.val['_M_cmpts']['_M_impl']['_M_finish']
+ self.num_cmpts = int (finish - start)
+
+ def _path_type(self):
+ t = str(self.val['_M_type'])
+ if t[-9:] == '_Root_dir':
+ return "root-directory"
+ if t[-10:] == '_Root_name':
+ return "root-name"
+ return None
def to_string (self):
- path = self.val ['_M_pathname']
- if self.list_visualizer:
- list_head = self.val['_M_cmpts']['_M_impl']['_M_node']
- if list_head.address != list_head['_M_next']:
- cmpts = self.list_visualizer.to_string()
- path = "%s [Components %s]" % (path, cmpts)
- return path
+ path = "%s" % self.val ['_M_pathname']
+ if self.num_cmpts == 0:
+ t = self._path_type()
+ if t:
+ path = '%s [%s]' % (path, t)
+ return "filesystem::path %s" % path
+
+ class _iterator(Iterator):
+ def __init__(self, cmpts):
+ self.item = cmpts['_M_impl']['_M_start']
+ self.finish = cmpts['_M_impl']['_M_finish']
+ self.count = 0
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if self.item == self.finish:
+ raise StopIteration
+ item = self.item.dereference()
+ count = self.count
+ self.count = self.count + 1
+ self.item = self.item + 1
+ path = item['_M_pathname']
+ t = StdExpPathPrinter(item.type.name, item)._path_type()
+ if not t:
+ t = count
+ return ('[%s]' % t, path)
+
+ def children(self):
+ return self._iterator(self.val['_M_cmpts'])
+
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
@@ -1383,7 +1418,7 @@ def build_libstdcxx_dictionary ():
# Filesystem TS components
libstdcxx_printer.add_version('std::experimental::filesystem::v1::',
'path', StdExpPathPrinter)
- libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11',
+ libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
'path', StdExpPathPrinter)
# Extensions.
diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc
index db58f3b..cc5780f 100644
--- a/libstdc++-v3/src/filesystem/path.cc
+++ b/libstdc++-v3/src/filesystem/path.cc
@@ -35,7 +35,7 @@ path::remove_filename()
{
if (!_M_cmpts.empty())
{
- auto cmpt = --_M_cmpts.end();
+ auto cmpt = std::prev(_M_cmpts.end());
_M_pathname.erase(cmpt->_M_pos);
_M_cmpts.erase(cmpt);
_M_trim();
@@ -109,7 +109,7 @@ path::compare(const path& p) const noexcept
{
if (_M_type == _Type::_Multi && p._M_type == _Type::_Multi)
return do_compare(_M_cmpts.begin(), _M_cmpts.end(),
- p._M_cmpts.begin(), p._M_cmpts.end());
+ p._M_cmpts.begin(), p._M_cmpts.end());
else if (_M_type == _Type::_Multi)
{
_Cmpt c[1] = { { p._M_pathname, p._M_type, 0 } };
@@ -130,8 +130,7 @@ path::root_name() const
path __ret;
if (_M_type == _Type::_Root_name)
__ret = *this;
- else if (_M_cmpts.size()
- && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+ else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
__ret = *_M_cmpts.begin();
return __ret;
}
@@ -203,8 +202,8 @@ path::parent_path() const
path __ret;
if (_M_cmpts.size() < 2)
return __ret;
- for (auto __it = _M_cmpts.begin(), __end = --_M_cmpts.end();
- __it != __end; ++__it)
+ for (auto __it = _M_cmpts.begin(), __end = std::prev(_M_cmpts.end());
+ __it != __end; ++__it)
{
__ret /= *__it;
}
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
index 2c21f6f..41df1bf 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/decompose/parent_path.cc
@@ -44,6 +44,8 @@ test02()
{
for (const path& p : __gnu_test::test_paths)
{
+ if (p.begin() == p.end())
+ continue;
path pp;
for (auto i = p.begin(), end = --p.end(); i != end; ++i)
{
-------------- next part --------------
commit e132913c9b82a9d57c4af3df2560dc89279a78a5
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Fri May 1 12:13:06 2015 +0100
* acinclude.m4 (GLIBCXX_ENABLE_FILESYSTEM_TS): Disable when <dirent.h>
is not available.
(GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for fchmodat.
* configure: Regenerate.
* config.h.in: Regenerate.
* configure.ac: Check for utime.h
* include/experimental/fs_path.h (path::string<>)
[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Remove stray typename keyword.
* src/filesystem/dir.cc [!_GLIBCXX_HAVE_DIRENT_H] (DIR, opendir,
closedir, dirent, readdir_r): Replace dummy functions with #error.
(native_readdir, _Dir::advance): Use readdir when readdir_r is missing.
* src/filesystem/ops.cc (do_stat, is_set): Make inline.
(last_write_time) [!_GLIBCXX_USE_UTIMENSAT]: Use utime.
(permissions) [!_GLIBCXX_USE_FCHMODAT]: Use chmod.
(space, temp_directory_path) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Set
error_code.
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 9d8d96d..07b5bd7 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -3914,6 +3914,9 @@ AC_DEFUN([GLIBCXX_ENABLE_FILESYSTEM_TS], [
[permit yes|no|auto])
AC_MSG_CHECKING([whether to build Filesystem TS support])
+ if test x"$ac_cv_header_dirent_h" != x"yes"; then
+ enable_libstdcxx_filesystem_ts=no
+ fi
if test x"$enable_libstdcxx_filesystem_ts" = x"auto"; then
case "${target_os}" in
freebsd*|netbsd*|openbsd*|dragonfly*|darwin*)
@@ -3993,6 +3996,22 @@ dnl
fi
AC_MSG_RESULT($glibcxx_cv_st_mtim)
dnl
+ AC_MSG_CHECKING([for fchmodat])
+ AC_CACHE_VAL(glibcxx_cv_fchmodat, [dnl
+ GCC_TRY_COMPILE_OR_LINK(
+ [
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ ],
+ [fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW);],
+ [glibcxx_cv_fchmodat=yes],
+ [glibcxx_cv_fchmodat=no])
+ ])
+ if test $glibcxx_cv_fchmodat = yes; then
+ AC_DEFINE(_GLIBCXX_USE_FCHMODAT, 1, [Define if fchmodat is available in <sys/stat.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_fchmodat)
+dnl
CXXFLAGS="$ac_save_CXXFLAGS"
AC_LANG_RESTORE
])
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 4b39bfa..311baa5 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -403,7 +403,7 @@ GLIBCXX_CONFIGURE_TESTSUITE
GLIBCXX_CHECK_GTHREADS
# For Filesystem TS.
-AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h])
+AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
AC_STRUCT_DIRENT_D_TYPE
GLIBCXX_ENABLE_FILESYSTEM_TS
GLIBCXX_CHECK_FILESYSTEM_DEPS
diff --git a/libstdc++-v3/include/experimental/fs_path.h b/libstdc++-v3/include/experimental/fs_path.h
index e57a08b..33a16db 100644
--- a/libstdc++-v3/include/experimental/fs_path.h
+++ b/libstdc++-v3/include/experimental/fs_path.h
@@ -781,7 +781,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
const value_type* __last = __first + _M_pathname.size();
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- using _CharAlloc = typename __alloc_rebind<_Allocator, char>;
+ using _CharAlloc = __alloc_rebind<_Allocator, char>;
using _String = basic_string<char, char_traits<char>, _CharAlloc>;
using _WString = basic_string<_CharT, _Traits, _Allocator>;
diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc
index 4ed869e..016a78d 100644
--- a/libstdc++-v3/src/filesystem/dir.cc
+++ b/libstdc++-v3/src/filesystem/dir.cc
@@ -25,7 +25,6 @@
#include <experimental/filesystem>
#include <utility>
#include <stack>
-#include <tuple>
#include <string.h>
#include <errno.h>
#ifdef _GLIBCXX_HAVE_DIRENT_H
@@ -34,17 +33,12 @@
# endif
# include <dirent.h>
#else
-// TODO: replace dummy definitions with suitable Win32 code
-#ifndef EACCES
-# define EACCES static_cast<int>(std::errc::permission_denied)
+# error "the <dirent.h> header is needed to build the Filesystem TS"
#endif
-using DIR = void;
-using P = std::experimental::filesystem::path;
-static DIR* opendir(const P::value_type*) { return nullptr; }
-static void closedir(DIR*) { }
-struct dirent { const char* d_name; };
-static inline int readdir_r(DIR*, dirent*, dirent**)
-{ return static_cast<int>(std::errc::not_supported); }
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef opendir
+# define opendir _wopendir
#endif
namespace fs = std::experimental::filesystem;
@@ -97,7 +91,7 @@ struct fs::_Dir
namespace
{
template<typename Bitmask>
- bool is_set(Bitmask obj, Bitmask bits)
+ inline bool is_set(Bitmask obj, Bitmask bits)
{
return (obj & bits) != Bitmask::none;
}
@@ -159,14 +153,27 @@ namespace
return fs::file_type::none;
#endif
}
+
+ int
+ native_readdir(DIR* dirp, ::dirent*& entryp)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ errno = 0;
+ if ((entryp = ::readdir(dirp)))
+ return 0;
+ return errno;
+#else
+ return ::readdir_r(dirp, entryp, &entryp);
+#endif
+ }
}
bool
fs::_Dir::advance(ErrorCode ec)
{
::dirent ent;
- ::dirent* result;
- if (int err = readdir_r(dirp, &ent, &result))
+ ::dirent* result = &ent;
+ if (int err = native_readdir(dirp, result))
{
if (!ec)
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index 091ca72..c7e3960 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -47,6 +47,16 @@
# include <ext/stdio_filebuf.h>
# include <ostream>
#endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef utime
+# define utime _wutime
+# undef chmod
+# define chmod _wchmod
+#endif
namespace fs = std::experimental::filesystem;
@@ -131,7 +141,7 @@ fs::copy(const path& from, const path& to, copy_options options)
namespace
{
template<typename Bitmask>
- bool is_set(Bitmask obj, Bitmask bits)
+ inline bool is_set(Bitmask obj, Bitmask bits)
{
return (obj & bits) != Bitmask::none;
}
@@ -767,7 +777,7 @@ fs::file_size(const path& p)
namespace
{
template<typename Accessor, typename T>
- T
+ inline T
do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
@@ -871,6 +881,14 @@ fs::last_write_time(const path& p __attribute__((__unused__)),
ec.assign(errno, std::generic_category());
else
ec.clear();
+#elif _GLIBCXX_HAVE_UTIME_H
+ ::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, std::mem_fn(&stat::st_atime), times.modtime);
+ if (::utime(p.c_str(), ×))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
#else
ec = std::make_error_code(std::errc::not_supported);
#endif
@@ -887,7 +905,11 @@ fs::permissions(const path& p, perms prms)
void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
{
+#if _GLIBCXX_USE_FCHMODAT
if (int err = ::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0))
+#else
+ if (int err = ::chmod(p.c_str(), static_cast<mode_t>(prms)))
+#endif
ec.assign(err, std::generic_category());
else
ec.clear();
@@ -1051,6 +1073,8 @@ fs::space(const path& p, error_code& ec) noexcept
};
ec.clear();
}
+#else
+ ec = std::make_error_code(std::errc::not_supported);
#endif
return info;
}
@@ -1157,6 +1181,7 @@ fs::path fs::temp_directory_path()
fs::path fs::temp_directory_path(error_code& ec)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(std::errc::not_supported);
return {}; // TODO
#else
const char* tmpdir = ::getenv("TMPDIR");
More information about the Gcc-patches
mailing list