diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d22a9b93da5..6bb72144746 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,131 @@ 2017-10-23 Jonathan Wakely + * include/Makefile.am: Add new headers for C++17 filesystem library. + * include/Makefile.in: Regenerate. + * include/bits/fs_dir.h: New header, based on Filesystem TS code in + include/experimental/bits directory. + * include/bits/fs_fwd.h: Likewise. + * include/bits/fs_ops.h: Likewise. + * include/bits/fs_path.h: Likewise. + * include/experimental/bits/fs_dir.h: Rename Doxygen group. + * include/experimental/bits/fs_fwd.h: Likewise. + * include/experimental/bits/fs_ops.h: Likewise. + * include/experimental/bits/fs_path.h: Likewise. + * include/experimental/filesystem (filesystem_error::_M_gen_what): + Remove inline definition. + * include/precompiled/stdc++.h: Add to precompiled + header. + * include/std/filesystem: New header. + * python/libstdcxx/v6/printers.py: Enable printer for std::filesystem + paths. + * src/filesystem/Makefile.am: Add new files. Compile as C++17. + * src/filesystem/Makefile.in: Regenerate. + * src/filesystem/cow-dir.cc: Update comment. + * src/filesystem/cow-ops.cc: Likewise. + * src/filesystem/cow-path.cc: Likewise. + * src/filesystem/cow-std-dir.cc: New file. + * src/filesystem/cow-std-ops.cc: New file. + * src/filesystem/cow-std-path.cc: New file. + * src/filesystem/dir-common.h (_Dir_base, get_file_type): New header + for common code. + * src/filesystem/dir.cc (_Dir): Derive from _Dir_base. + (open_dir): Move to _Dir_base constructor. + (get_file_type): Move to dir-common.h. + (recurse): Move to _Dir_base::should_recurse. + * src/filesystem/ops-common.h: New header for common code. + * src/filesystem/ops.cc (is_set, make_file_type, make_file_status) + (is_not_found_errno, file_time, do_copy_file): Move to ops-common.h. + * src/filesystem/path.cc (filesystem_error::_M_gen_what): Define. + * src/filesystem/std-dir.cc: New file, based on Filesystem TS code. + * src/filesystem/std-ops.cc: Likewise. + * src/filesystem/std-dir.cc: Likewise. + * testsuite/27_io/filesystem/iterators/directory_iterator.cc: New + test. + * testsuite/27_io/filesystem/iterators/pop.cc: New test. + * testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc: + New test. + * testsuite/27_io/filesystem/operations/absolute.cc: New test. + * testsuite/27_io/filesystem/operations/canonical.cc: New test. + * testsuite/27_io/filesystem/operations/copy.cc: New test. + * testsuite/27_io/filesystem/operations/copy_file.cc: New test. + * testsuite/27_io/filesystem/operations/create_directories.cc: New + test. + * testsuite/27_io/filesystem/operations/create_directory.cc: New test. + * testsuite/27_io/filesystem/operations/create_symlink.cc: New test. + * testsuite/27_io/filesystem/operations/current_path.cc: New test. + * testsuite/27_io/filesystem/operations/equivalent.cc: New test. + * testsuite/27_io/filesystem/operations/exists.cc: New test. + * testsuite/27_io/filesystem/operations/file_size.cc: New test. + * testsuite/27_io/filesystem/operations/is_empty.cc: New test. + * testsuite/27_io/filesystem/operations/last_write_time.cc: New test. + * testsuite/27_io/filesystem/operations/permissions.cc: New test. + * testsuite/27_io/filesystem/operations/proximate.cc: New test. + * testsuite/27_io/filesystem/operations/read_symlink.cc: New test. + * testsuite/27_io/filesystem/operations/relative.cc: New test. + * testsuite/27_io/filesystem/operations/remove_all.cc: New test. + * testsuite/27_io/filesystem/operations/space.cc: New test. + * testsuite/27_io/filesystem/operations/status.cc: New test. + * testsuite/27_io/filesystem/operations/symlink_status.cc: New test. + * testsuite/27_io/filesystem/operations/temp_directory_path.cc: New + test. + * testsuite/27_io/filesystem/operations/weakly_canonical.cc: New test. + * testsuite/27_io/filesystem/path/append/path.cc: New test. + * testsuite/27_io/filesystem/path/assign/assign.cc: New test. + * testsuite/27_io/filesystem/path/assign/copy.cc: New test. + * testsuite/27_io/filesystem/path/compare/compare.cc: New test. + * testsuite/27_io/filesystem/path/compare/path.cc: New test. + * testsuite/27_io/filesystem/path/compare/strings.cc: New test. + * testsuite/27_io/filesystem/path/concat/path.cc: New test. + * testsuite/27_io/filesystem/path/concat/strings.cc: New test. + * testsuite/27_io/filesystem/path/construct/copy.cc: New test. + * testsuite/27_io/filesystem/path/construct/default.cc: New test. + * testsuite/27_io/filesystem/path/construct/locale.cc: New test. + * testsuite/27_io/filesystem/path/construct/range.cc: New test. + * testsuite/27_io/filesystem/path/construct/string_view.cc: New test. + * testsuite/27_io/filesystem/path/decompose/extension.cc: New test. + * testsuite/27_io/filesystem/path/decompose/filename.cc: New test. + * testsuite/27_io/filesystem/path/decompose/parent_path.cc: New test. + * testsuite/27_io/filesystem/path/decompose/relative_path.cc: New + test. + * testsuite/27_io/filesystem/path/decompose/root_directory.cc: New + test. + * testsuite/27_io/filesystem/path/decompose/root_name.cc: New test. + * testsuite/27_io/filesystem/path/decompose/root_path.cc: New test. + * testsuite/27_io/filesystem/path/decompose/stem.cc: New test. + * testsuite/27_io/filesystem/path/generation/normal.cc: New test. + * testsuite/27_io/filesystem/path/generation/proximate.cc: New test. + * testsuite/27_io/filesystem/path/generation/relative.cc: New test. + * testsuite/27_io/filesystem/path/generic/generic_string.cc: New test. + * testsuite/27_io/filesystem/path/itr/traversal.cc: New test. + * testsuite/27_io/filesystem/path/modifiers/clear.cc: New test. + * testsuite/27_io/filesystem/path/modifiers/make_preferred.cc: New + test. + * testsuite/27_io/filesystem/path/modifiers/remove_filename.cc: New + test. + * testsuite/27_io/filesystem/path/modifiers/replace_extension.cc: New + test. + * testsuite/27_io/filesystem/path/modifiers/replace_filename.cc: New + test. + * testsuite/27_io/filesystem/path/modifiers/swap.cc: New test. + * testsuite/27_io/filesystem/path/native/string.cc: New test. + * testsuite/27_io/filesystem/path/nonmember/hash_value.cc: New test. + * testsuite/27_io/filesystem/path/query/empty.cc: New test. + * testsuite/27_io/filesystem/path/query/has_extension.cc: New test. + * testsuite/27_io/filesystem/path/query/has_filename.cc: New test. + * testsuite/27_io/filesystem/path/query/has_parent_path.cc: New test. + * testsuite/27_io/filesystem/path/query/has_relative_path.cc: New + test. + * testsuite/27_io/filesystem/path/query/has_root_directory.cc: New + test. + * testsuite/27_io/filesystem/path/query/has_root_name.cc: New test. + * testsuite/27_io/filesystem/path/query/has_root_path.cc: New test. + * testsuite/27_io/filesystem/path/query/has_stem.cc: New test. + * testsuite/27_io/filesystem/path/query/is_relative.cc: New test. + * testsuite/experimental/filesystem/path/construct/string_view.cc: + Define USE_FILESYSTEM_TS. + * testsuite/util/testsuite_fs.h: Allow use with C++17 paths as well + as Filesystem TS. + PR libstdc++/82644 * doc/xml/manual/intro.xml: Include new section. * doc/xml/manual/status_cxxis29124.xml: New section on IS 29124 diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 236c2d6059f..2c4d193d0a4 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -37,6 +37,7 @@ std_headers = \ ${std_srcdir}/complex \ ${std_srcdir}/condition_variable \ ${std_srcdir}/deque \ + ${std_srcdir}/filesystem \ ${std_srcdir}/forward_list \ ${std_srcdir}/fstream \ ${std_srcdir}/functional \ @@ -104,6 +105,10 @@ bits_headers = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/forward_list.h \ ${bits_srcdir}/forward_list.tcc \ + ${bits_srcdir}/fs_dir.h \ + ${bits_srcdir}/fs_fwd.h \ + ${bits_srcdir}/fs_ops.h \ + ${bits_srcdir}/fs_path.h \ ${bits_srcdir}/fstream.tcc \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 39dfede549b..bc8556c68d2 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -330,6 +330,7 @@ std_headers = \ ${std_srcdir}/complex \ ${std_srcdir}/condition_variable \ ${std_srcdir}/deque \ + ${std_srcdir}/filesystem \ ${std_srcdir}/forward_list \ ${std_srcdir}/fstream \ ${std_srcdir}/functional \ @@ -397,6 +398,10 @@ bits_headers = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/forward_list.h \ ${bits_srcdir}/forward_list.tcc \ + ${bits_srcdir}/fs_dir.h \ + ${bits_srcdir}/fs_fwd.h \ + ${bits_srcdir}/fs_ops.h \ + ${bits_srcdir}/fs_path.h \ ${bits_srcdir}/fstream.tcc \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h new file mode 100644 index 00000000000..20ce9beb023 --- /dev/null +++ b/libstdc++-v3/include/bits/fs_dir.h @@ -0,0 +1,526 @@ +// Filesystem directory utilities -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/fs_dir.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{filesystem} + */ + +#ifndef _GLIBCXX_FS_DIR_H +#define _GLIBCXX_FS_DIR_H 1 + +#if __cplusplus >= 201703L +# include +# include +# include +# include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +namespace filesystem +{ + /** + * @ingroup filesystem + * @{ + */ + + class file_status + { + public: + // constructors + explicit + file_status(file_type __ft = file_type::none, + perms __prms = perms::unknown) noexcept + : _M_type(__ft), _M_perms(__prms) { } + + file_status(const file_status&) noexcept = default; + file_status(file_status&&) noexcept = default; + ~file_status() = default; + + file_status& operator=(const file_status&) noexcept = default; + file_status& operator=(file_status&&) noexcept = default; + + // observers + file_type type() const noexcept { return _M_type; } + perms permissions() const noexcept { return _M_perms; } + + // modifiers + void type(file_type __ft) noexcept { _M_type = __ft; } + void permissions(perms __prms) noexcept { _M_perms = __prms; } + + private: + file_type _M_type; + perms _M_perms; + }; + +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + + struct _Dir; + class directory_iterator; + class recursive_directory_iterator; + + class directory_entry + { + public: + // constructors and destructor + directory_entry() noexcept = default; + directory_entry(const directory_entry&) = default; + directory_entry(directory_entry&&) noexcept = default; + + explicit + directory_entry(const filesystem::path& __p) + : _M_path(__p) + { refresh(); } + + directory_entry(const filesystem::path& __p, error_code& __ec) + : _M_path(__p) + { + refresh(__ec); + if (__ec) + _M_path.clear(); + } + + ~directory_entry() = default; + + // modifiers + directory_entry& operator=(const directory_entry&) = default; + directory_entry& operator=(directory_entry&&) noexcept = default; + + void + assign(const filesystem::path& __p) + { + _M_path = __p; + refresh(); + } + + void + assign(const filesystem::path& __p, error_code& __ec) + { + _M_path = __p; + refresh(__ec); + } + + void + replace_filename(const filesystem::path& __p) + { + _M_path.replace_filename(__p); + refresh(); + } + + void + replace_filename(const filesystem::path& __p, error_code& __ec) + { + _M_path.replace_filename(__p); + refresh(__ec); + } + + void refresh() { _M_type = symlink_status().type(); } + void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); } + + // observers + const filesystem::path& path() const noexcept { return _M_path; } + operator const filesystem::path& () const noexcept { return _M_path; } + + bool + exists() const + { return filesystem::exists(file_status{_M_file_type()}); } + + bool + exists(error_code& __ec) const noexcept + { return filesystem::exists(file_status{_M_file_type(__ec)}); } + + bool + is_block_file() const + { return _M_file_type() == file_type::block; } + + bool + is_block_file(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::block; } + + bool + is_character_file() const + { return _M_file_type() == file_type::character; } + + bool + is_character_file(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::character; } + + bool + is_directory() const + { return _M_file_type() == file_type::directory; } + + bool + is_directory(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::directory; } + + bool + is_fifo() const + { return _M_file_type() == file_type::fifo; } + + bool + is_fifo(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::fifo; } + + bool + is_other() const + { return filesystem::is_other(file_status{_M_file_type()}); } + + bool + is_other(error_code& __ec) const noexcept + { return filesystem::is_other(file_status{_M_file_type(__ec)}); } + + bool + is_regular_file() const + { return _M_file_type() == file_type::regular; } + + bool + is_regular_file(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::regular; } + + bool + is_socket() const + { return _M_file_type() == file_type::socket; } + + bool + is_socket(error_code& __ec) const noexcept + { return _M_file_type(__ec) == file_type::socket; } + + bool + is_symlink() const + { + if (_M_type != file_type::none) + return _M_type == file_type::symlink; + return symlink_status().type() == file_type::symlink; + } + + bool + is_symlink(error_code& __ec) const noexcept + { + if (_M_type != file_type::none) + return _M_type == file_type::symlink; + return symlink_status(__ec).type() == file_type::symlink; + } + + uintmax_t + file_size() const + { return filesystem::file_size(_M_path); } + + uintmax_t + file_size(error_code& __ec) const noexcept + { return filesystem::file_size(_M_path, __ec); } + + uintmax_t + hard_link_count() const + { return filesystem::hard_link_count(_M_path); } + + uintmax_t + hard_link_count(error_code& __ec) const noexcept + { return filesystem::hard_link_count(_M_path, __ec); } + + file_time_type + last_write_time() const + { return filesystem::last_write_time(_M_path); } + + + file_time_type + last_write_time(error_code& __ec) const noexcept + { return filesystem::last_write_time(_M_path, __ec); } + + file_status + status() const + { return filesystem::status(_M_path); } + + file_status + status(error_code& __ec) const noexcept + { return filesystem::status(_M_path, __ec); } + + file_status + symlink_status() const + { return filesystem::symlink_status(_M_path); } + + file_status + symlink_status(error_code& __ec) const noexcept + { return filesystem::symlink_status(_M_path, __ec); } + + bool + operator< (const directory_entry& __rhs) const noexcept + { return _M_path < __rhs._M_path; } + + bool + operator==(const directory_entry& __rhs) const noexcept + { return _M_path == __rhs._M_path; } + + bool + operator!=(const directory_entry& __rhs) const noexcept + { return _M_path != __rhs._M_path; } + + bool + operator<=(const directory_entry& __rhs) const noexcept + { return _M_path <= __rhs._M_path; } + + bool + operator> (const directory_entry& __rhs) const noexcept + { return _M_path > __rhs._M_path; } + + bool + operator>=(const directory_entry& __rhs) const noexcept + { return _M_path >= __rhs._M_path; } + + private: + friend class _Dir; + friend class directory_iterator; + friend class recursive_directory_iterator; + + directory_entry(const filesystem::path& __p, file_type __t) + : _M_path(__p), _M_type(__t) + { } + + // Equivalent to status().type() but uses cached value, if any. + file_type + _M_file_type() const + { + if (_M_type != file_type::none && _M_type != file_type::symlink) + return _M_type; + return status().type(); + } + + // Equivalent to status(__ec).type() but uses cached value, if any. + file_type + _M_file_type(error_code& __ec) const noexcept + { + if (_M_type != file_type::none && _M_type != file_type::symlink) + return _M_type; + return status(__ec).type(); + } + + filesystem::path _M_path; + file_type _M_type = file_type::none; + }; + + struct __directory_iterator_proxy + { + const directory_entry& operator*() const& noexcept { return _M_entry; } + + directory_entry operator*() && noexcept { return std::move(_M_entry); } + + private: + friend class directory_iterator; + friend class recursive_directory_iterator; + + explicit + __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { } + + directory_entry _M_entry; + }; + + class directory_iterator + { + public: + typedef directory_entry value_type; + typedef ptrdiff_t difference_type; + typedef const directory_entry* pointer; + typedef const directory_entry& reference; + typedef input_iterator_tag iterator_category; + + directory_iterator() = default; + + explicit + directory_iterator(const path& __p) + : directory_iterator(__p, directory_options::none, nullptr) { } + + directory_iterator(const path& __p, directory_options __options) + : directory_iterator(__p, __options, nullptr) { } + + directory_iterator(const path& __p, error_code& __ec) noexcept + : directory_iterator(__p, directory_options::none, __ec) { } + + directory_iterator(const path& __p, + directory_options __options, + error_code& __ec) noexcept + : directory_iterator(__p, __options, &__ec) { } + + directory_iterator(const directory_iterator& __rhs) = default; + + directory_iterator(directory_iterator&& __rhs) noexcept = default; + + ~directory_iterator() = default; + + directory_iterator& + operator=(const directory_iterator& __rhs) = default; + + directory_iterator& + operator=(directory_iterator&& __rhs) noexcept = default; + + const directory_entry& operator*() const; + const directory_entry* operator->() const { return &**this; } + directory_iterator& operator++(); + directory_iterator& increment(error_code& __ec) noexcept; + + __directory_iterator_proxy operator++(int) + { + __directory_iterator_proxy __pr{**this}; + ++*this; + return __pr; + } + + private: + directory_iterator(const path&, directory_options, error_code*); + + friend bool + operator==(const directory_iterator& __lhs, + const directory_iterator& __rhs); + + friend class recursive_directory_iterator; + + std::shared_ptr<_Dir> _M_dir; + }; + + inline directory_iterator + begin(directory_iterator __iter) noexcept + { return __iter; } + + inline directory_iterator + end(directory_iterator) noexcept + { return directory_iterator(); } + + inline bool + operator==(const directory_iterator& __lhs, const directory_iterator& __rhs) + { + return !__rhs._M_dir.owner_before(__lhs._M_dir) + && !__lhs._M_dir.owner_before(__rhs._M_dir); + } + + inline bool + operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs) + { return !(__lhs == __rhs); } + + class recursive_directory_iterator + { + public: + typedef directory_entry value_type; + typedef ptrdiff_t difference_type; + typedef const directory_entry* pointer; + typedef const directory_entry& reference; + typedef input_iterator_tag iterator_category; + + recursive_directory_iterator() = default; + + explicit + recursive_directory_iterator(const path& __p) + : recursive_directory_iterator(__p, directory_options::none, nullptr) { } + + recursive_directory_iterator(const path& __p, directory_options __options) + : recursive_directory_iterator(__p, __options, nullptr) { } + + recursive_directory_iterator(const path& __p, + directory_options __options, + error_code& __ec) noexcept + : recursive_directory_iterator(__p, __options, &__ec) { } + + recursive_directory_iterator(const path& __p, error_code& __ec) noexcept + : recursive_directory_iterator(__p, directory_options::none, &__ec) { } + + recursive_directory_iterator( + const recursive_directory_iterator&) = default; + + recursive_directory_iterator(recursive_directory_iterator&&) = default; + + ~recursive_directory_iterator(); + + // observers + directory_options options() const { return _M_options; } + int depth() const; + bool recursion_pending() const { return _M_pending; } + + const directory_entry& operator*() const; + const directory_entry* operator->() const { return &**this; } + + // modifiers + recursive_directory_iterator& + operator=(const recursive_directory_iterator& __rhs) noexcept; + recursive_directory_iterator& + operator=(recursive_directory_iterator&& __rhs) noexcept; + + recursive_directory_iterator& operator++(); + recursive_directory_iterator& increment(error_code& __ec) noexcept; + + __directory_iterator_proxy operator++(int) + { + __directory_iterator_proxy __pr{**this}; + ++*this; + return __pr; + } + + void pop(); + void pop(error_code&); + + void disable_recursion_pending() { _M_pending = false; } + + private: + recursive_directory_iterator(const path&, directory_options, error_code*); + + friend bool + operator==(const recursive_directory_iterator& __lhs, + const recursive_directory_iterator& __rhs); + + struct _Dir_stack; + std::shared_ptr<_Dir_stack> _M_dirs; + directory_options _M_options = {}; + bool _M_pending = false; + }; + + inline recursive_directory_iterator + begin(recursive_directory_iterator __iter) noexcept + { return __iter; } + + inline recursive_directory_iterator + end(recursive_directory_iterator) noexcept + { return recursive_directory_iterator(); } + + inline bool + operator==(const recursive_directory_iterator& __lhs, + const recursive_directory_iterator& __rhs) + { + return !__rhs._M_dirs.owner_before(__lhs._M_dirs) + && !__lhs._M_dirs.owner_before(__rhs._M_dirs); + } + + inline bool + operator!=(const recursive_directory_iterator& __lhs, + const recursive_directory_iterator& __rhs) + { return !(__lhs == __rhs); } + +_GLIBCXX_END_NAMESPACE_CXX11 + + // @} group filesystem +} // namespace filesystem + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_FS_DIR_H diff --git a/libstdc++-v3/include/bits/fs_fwd.h b/libstdc++-v3/include/bits/fs_fwd.h new file mode 100644 index 00000000000..f408a39b974 --- /dev/null +++ b/libstdc++-v3/include/bits/fs_fwd.h @@ -0,0 +1,348 @@ +// Filesystem declarations -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/fs_fwd.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{filesystem} + */ + +#ifndef _GLIBCXX_FS_FWD_H +#define _GLIBCXX_FS_FWD_H 1 + +#if __cplusplus >= 201703L + +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +namespace filesystem +{ +#if _GLIBCXX_USE_CXX11_ABI +inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } +#endif + + /** + * @defgroup filesystem Filesystem + * + * Utilities for performing operations on file systems and their components, + * such as paths, regular files, and directories. + * + * @{ + */ + + class file_status; +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + class path; + class filesystem_error; + class directory_entry; + class directory_iterator; + class recursive_directory_iterator; +_GLIBCXX_END_NAMESPACE_CXX11 + + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; + + enum class file_type : signed char { + none = 0, not_found = -1, regular = 1, directory = 2, symlink = 3, + block = 4, character = 5, fifo = 6, socket = 7, unknown = 8 + }; + + /// Bitmask type + enum class copy_options : unsigned short { + none = 0, + skip_existing = 1, overwrite_existing = 2, update_existing = 4, + recursive = 8, + copy_symlinks = 16, skip_symlinks = 32, + directories_only = 64, create_symlinks = 128, create_hard_links = 256 + }; + + constexpr copy_options + operator&(copy_options __x, copy_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) & static_cast<__utype>(__y)); + } + + constexpr copy_options + operator|(copy_options __x, copy_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) | static_cast<__utype>(__y)); + } + + constexpr copy_options + operator^(copy_options __x, copy_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) ^ static_cast<__utype>(__y)); + } + + constexpr copy_options + operator~(copy_options __x) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast(~static_cast<__utype>(__x)); + } + + inline copy_options& + operator&=(copy_options& __x, copy_options __y) noexcept + { return __x = __x & __y; } + + inline copy_options& + operator|=(copy_options& __x, copy_options __y) noexcept + { return __x = __x | __y; } + + inline copy_options& + operator^=(copy_options& __x, copy_options __y) noexcept + { return __x = __x ^ __y; } + + + /// Bitmask type + enum class perms : unsigned { + none = 0, + owner_read = 0400, + owner_write = 0200, + owner_exec = 0100, + owner_all = 0700, + group_read = 040, + group_write = 020, + group_exec = 010, + group_all = 070, + others_read = 04, + others_write = 02, + others_exec = 01, + others_all = 07, + all = 0777, + set_uid = 04000, + set_gid = 02000, + sticky_bit = 01000, + mask = 07777, + unknown = 0xFFFF, + }; + + constexpr perms + operator&(perms __x, perms __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) & static_cast<__utype>(__y)); + } + + constexpr perms + operator|(perms __x, perms __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) | static_cast<__utype>(__y)); + } + + constexpr perms + operator^(perms __x, perms __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) ^ static_cast<__utype>(__y)); + } + + constexpr perms + operator~(perms __x) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast(~static_cast<__utype>(__x)); + } + + inline perms& + operator&=(perms& __x, perms __y) noexcept + { return __x = __x & __y; } + + inline perms& + operator|=(perms& __x, perms __y) noexcept + { return __x = __x | __y; } + + inline perms& + operator^=(perms& __x, perms __y) noexcept + { return __x = __x ^ __y; } + + /// Bitmask type + enum class perm_options : unsigned { + replace = 0x1, + add = 0x2, + remove = 0x4, + nofollow = 0x8 + }; + + constexpr perm_options + operator&(perm_options __x, perm_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) & static_cast<__utype>(__y)); + } + + constexpr perm_options + operator|(perm_options __x, perm_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) | static_cast<__utype>(__y)); + } + + constexpr perm_options + operator^(perm_options __x, perm_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) ^ static_cast<__utype>(__y)); + } + + constexpr perm_options + operator~(perm_options __x) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast(~static_cast<__utype>(__x)); + } + + inline perm_options& + operator&=(perm_options& __x, perm_options __y) noexcept + { return __x = __x & __y; } + + inline perm_options& + operator|=(perm_options& __x, perm_options __y) noexcept + { return __x = __x | __y; } + + inline perm_options& + operator^=(perm_options& __x, perm_options __y) noexcept + { return __x = __x ^ __y; } + + // Bitmask type + enum class directory_options : unsigned char { + none = 0, follow_directory_symlink = 1, skip_permission_denied = 2 + }; + + constexpr directory_options + operator&(directory_options __x, directory_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) & static_cast<__utype>(__y)); + } + + constexpr directory_options + operator|(directory_options __x, directory_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) | static_cast<__utype>(__y)); + } + + constexpr directory_options + operator^(directory_options __x, directory_options __y) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast( + static_cast<__utype>(__x) ^ static_cast<__utype>(__y)); + } + + constexpr directory_options + operator~(directory_options __x) noexcept + { + using __utype = typename std::underlying_type::type; + return static_cast(~static_cast<__utype>(__x)); + } + + inline directory_options& + operator&=(directory_options& __x, directory_options __y) noexcept + { return __x = __x & __y; } + + inline directory_options& + operator|=(directory_options& __x, directory_options __y) noexcept + { return __x = __x | __y; } + + inline directory_options& + operator^=(directory_options& __x, directory_options __y) noexcept + { return __x = __x ^ __y; } + + using file_time_type = std::chrono::system_clock::time_point; + + // operational functions + + void copy(const path& __from, const path& __to, copy_options __options); + void copy(const path& __from, const path& __to, copy_options __options, + error_code&) noexcept; + + bool copy_file(const path& __from, const path& __to, copy_options __option); + bool copy_file(const path& __from, const path& __to, copy_options __option, + error_code&) noexcept; + + path current_path(); + + bool exists(file_status) noexcept; + + bool is_other(file_status) noexcept; + + uintmax_t file_size(const path&); + uintmax_t file_size(const path&, error_code&) noexcept; + uintmax_t hard_link_count(const path&); + uintmax_t hard_link_count(const path&, error_code&) noexcept; + file_time_type last_write_time(const path&); + file_time_type last_write_time(const path&, error_code&) noexcept; + + void permissions(const path&, perms, perm_options, error_code&); + + path proximate(const path& __p, const path& __base, error_code& __ec); + path proximate(const path& __p, const path& __base, error_code& __ec); + + path relative(const path& __p, const path& __base, error_code& __ec); + + file_status status(const path&); + file_status status(const path&, error_code&) noexcept; + + bool status_known(file_status) noexcept; + + file_status symlink_status(const path&); + file_status symlink_status(const path&, error_code&) noexcept; + + bool is_regular_file(file_status) noexcept; + bool is_symlink(file_status) noexcept; + + // @} group filesystem +} // namespace filesystem + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_FS_FWD_H diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h new file mode 100644 index 00000000000..563d63de81a --- /dev/null +++ b/libstdc++-v3/include/bits/fs_ops.h @@ -0,0 +1,311 @@ +// Filesystem operational functions -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your __option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/fs_fwd.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{filesystem} + */ + +#ifndef _GLIBCXX_FS_OPS_H +#define _GLIBCXX_FS_OPS_H 1 + +#if __cplusplus >= 201703L + +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +namespace filesystem +{ + /** + * @ingroup filesystem + * @{ + */ + + path absolute(const path& __p); + path absolute(const path& __p, error_code& __ec); + + path canonical(const path& __p); + path canonical(const path& __p, error_code& __ec); + + inline void + copy(const path& __from, const path& __to) + { copy(__from, __to, copy_options::none); } + + inline void + copy(const path& __from, const path& __to, error_code& __ec) noexcept + { copy(__from, __to, copy_options::none, __ec); } + + void copy(const path& __from, const path& __to, copy_options __options); + void copy(const path& __from, const path& __to, copy_options __options, + error_code& __ec) noexcept; + + inline bool + copy_file(const path& __from, const path& __to) + { return copy_file(__from, __to, copy_options::none); } + + inline bool + copy_file(const path& __from, const path& __to, error_code& __ec) noexcept + { return copy_file(__from, __to, copy_options::none, __ec); } + + bool copy_file(const path& __from, const path& __to, copy_options __option); + bool copy_file(const path& __from, const path& __to, copy_options __option, + error_code& __ec) noexcept; + + void copy_symlink(const path& __existing_symlink, const path& __new_symlink); + void copy_symlink(const path& __existing_symlink, const path& __new_symlink, + error_code& __ec) noexcept; + + bool create_directories(const path& __p); + bool create_directories(const path& __p, error_code& __ec) noexcept; + + bool create_directory(const path& __p); + bool create_directory(const path& __p, error_code& __ec) noexcept; + + bool create_directory(const path& __p, const path& attributes); + bool create_directory(const path& __p, const path& attributes, + error_code& __ec) noexcept; + + void create_directory_symlink(const path& __to, const path& __new_symlink); + void create_directory_symlink(const path& __to, const path& __new_symlink, + error_code& __ec) noexcept; + + void create_hard_link(const path& __to, const path& __new_hard_link); + void create_hard_link(const path& __to, const path& __new_hard_link, + error_code& __ec) noexcept; + + void create_symlink(const path& __to, const path& __new_symlink); + void create_symlink(const path& __to, const path& __new_symlink, + error_code& __ec) noexcept; + + path current_path(); + path current_path(error_code& __ec); + void current_path(const path& __p); + void current_path(const path& __p, error_code& __ec) noexcept; + + bool + equivalent(const path& __p1, const path& __p2); + + bool + equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept; + + inline bool + exists(file_status __s) noexcept + { return status_known(__s) && __s.type() != file_type::not_found; } + + inline bool + exists(const path& __p) + { return exists(status(__p)); } + + inline bool + exists(const path& __p, error_code& __ec) noexcept + { + auto __s = status(__p, __ec); + if (status_known(__s)) + __ec.clear(); + return exists(__s); + } + + uintmax_t file_size(const path& __p); + uintmax_t file_size(const path& __p, error_code& __ec) noexcept; + + uintmax_t hard_link_count(const path& __p); + uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept; + + inline bool + is_block_file(file_status __s) noexcept + { return __s.type() == file_type::block; } + + inline bool + is_block_file(const path& __p) + { return is_block_file(status(__p)); } + + inline bool + is_block_file(const path& __p, error_code& __ec) noexcept + { return is_block_file(status(__p, __ec)); } + + inline bool + is_character_file(file_status __s) noexcept + { return __s.type() == file_type::character; } + + inline bool + is_character_file(const path& __p) + { return is_character_file(status(__p)); } + + inline bool + is_character_file(const path& __p, error_code& __ec) noexcept + { return is_character_file(status(__p, __ec)); } + + inline bool + is_directory(file_status __s) noexcept + { return __s.type() == file_type::directory; } + + inline bool + is_directory(const path& __p) + { return is_directory(status(__p)); } + + inline bool + is_directory(const path& __p, error_code& __ec) noexcept + { return is_directory(status(__p, __ec)); } + + bool is_empty(const path& __p); + bool is_empty(const path& __p, error_code& __ec) noexcept; + + inline bool + is_fifo(file_status __s) noexcept + { return __s.type() == file_type::fifo; } + + inline bool + is_fifo(const path& __p) + { return is_fifo(status(__p)); } + + inline bool + is_fifo(const path& __p, error_code& __ec) noexcept + { return is_fifo(status(__p, __ec)); } + + inline bool + is_other(file_status __s) noexcept + { + return exists(__s) && !is_regular_file(__s) && !is_directory(__s) + && !is_symlink(__s); + } + + inline bool + is_other(const path& __p) + { return is_other(status(__p)); } + + inline bool + is_other(const path& __p, error_code& __ec) noexcept + { return is_other(status(__p, __ec)); } + + inline bool + is_regular_file(file_status __s) noexcept + { return __s.type() == file_type::regular; } + + inline bool + is_regular_file(const path& __p) + { return is_regular_file(status(__p)); } + + inline bool + is_regular_file(const path& __p, error_code& __ec) noexcept + { return is_regular_file(status(__p, __ec)); } + + inline bool + is_socket(file_status __s) noexcept + { return __s.type() == file_type::socket; } + + inline bool + is_socket(const path& __p) + { return is_socket(status(__p)); } + + inline bool + is_socket(const path& __p, error_code& __ec) noexcept + { return is_socket(status(__p, __ec)); } + + inline bool + is_symlink(file_status __s) noexcept + { return __s.type() == file_type::symlink; } + + inline bool + is_symlink(const path& __p) + { return is_symlink(symlink_status(__p)); } + + inline bool + is_symlink(const path& __p, error_code& __ec) noexcept + { return is_symlink(symlink_status(__p, __ec)); } + + file_time_type last_write_time(const path& __p); + file_time_type last_write_time(const path& __p, error_code& __ec) noexcept; + void last_write_time(const path& __p, file_time_type __new_time); + void last_write_time(const path& __p, file_time_type __new_time, + error_code& __ec) noexcept; + + void + permissions(const path& __p, perms __prms, + perm_options __opts = perm_options::replace); + + inline void + permissions(const path& __p, perms __prms, error_code& __ec) noexcept + { permissions(__p, __prms, perm_options::replace, __ec); } + + void + permissions(const path& __p, perms __prms, perm_options __opts, + error_code& __ec); + + inline path proximate(const path& __p, error_code& __ec) + { return proximate(__p, current_path(), __ec); } + + path proximate(const path& __p, const path& __base = current_path()); + path proximate(const path& __p, const path& __base, error_code& __ec); + + path read_symlink(const path& __p); + path read_symlink(const path& __p, error_code& __ec); + + inline path relative(const path& __p, error_code& __ec) + { return relative(__p, current_path(), __ec); } + + path relative(const path& __p, const path& __base = current_path()); + path relative(const path& __p, const path& __base, error_code& __ec); + + bool remove(const path& __p); + bool remove(const path& __p, error_code& __ec) noexcept; + + uintmax_t remove_all(const path& __p); + uintmax_t remove_all(const path& __p, error_code& __ec) noexcept; + + void rename(const path& __from, const path& __to); + void rename(const path& __from, const path& __to, error_code& __ec) noexcept; + + void resize_file(const path& __p, uintmax_t __size); + void resize_file(const path& __p, uintmax_t __size, error_code& __ec) noexcept; + + space_info space(const path& __p); + space_info space(const path& __p, error_code& __ec) noexcept; + + file_status status(const path& __p); + file_status status(const path& __p, error_code& __ec) noexcept; + + inline bool status_known(file_status __s) noexcept + { return __s.type() != file_type::none; } + + file_status symlink_status(const path& __p); + file_status symlink_status(const path& __p, error_code& __ec) noexcept; + + path temp_directory_path(); + path temp_directory_path(error_code& __ec); + + path weakly_canonical(const path& __p); + path weakly_canonical(const path& __p, error_code& __ec); + + // @} group filesystem +} // namespace filesystem + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_FS_OPS_H diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h new file mode 100644 index 00000000000..6ba2bd2d43a --- /dev/null +++ b/libstdc++-v3/include/bits/fs_path.h @@ -0,0 +1,1163 @@ +// Class filesystem::path -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/fs_path.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{filesystem} + */ + +#ifndef _GLIBCXX_FS_PATH_H +#define _GLIBCXX_FS_PATH_H 1 + +#if __cplusplus >= 201703L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 +# include +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +namespace filesystem +{ +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + + /** + * @ingroup filesystem + * @{ + */ + + /// A filesystem path. + class path + { + template + struct __is_encoded_char : std::false_type { }; + + template> + using __is_path_iter_src + = __and_<__is_encoded_char, + std::is_base_of>; + + template + static __is_path_iter_src<_Iter> + __is_path_src(_Iter, int); + + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); + + template + static __is_encoded_char<_CharT> + __is_path_src(const basic_string_view<_CharT, _Traits>&, int); + + template + static std::false_type + __is_path_src(const _Unknown&, ...); + + template + struct __constructible_from; + + template + struct __constructible_from<_Iter, _Iter> + : __is_path_iter_src<_Iter> + { }; + + template + struct __constructible_from<_Source, void> + : decltype(__is_path_src(std::declval<_Source>(), 0)) + { }; + + template + using _Path = typename + std::enable_if<__and_<__not_>, + __constructible_from<_Tp1, _Tp2>>::value, + path>::type; + + template + static _Source + _S_range_begin(_Source __begin) { return __begin; } + + struct __null_terminated { }; + + template + static __null_terminated + _S_range_end(_Source) { return {}; } + + template + static const _CharT* + _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) + { return __str.data() + __str.size(); } + + template + static const _CharT* + _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data(); } + + template + static const _CharT* + _S_range_end(const basic_string_view<_CharT, _Traits>& __str) + { return __str.data() + __str.size(); } + + template())), + typename _Val = typename std::iterator_traits<_Iter>::value_type> + using __value_type_is_char + = typename std::enable_if::value>::type; + + public: +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + typedef wchar_t value_type; + static constexpr value_type preferred_separator = L'\\'; +#else + typedef char value_type; + static constexpr value_type preferred_separator = '/'; +#endif + typedef std::basic_string string_type; + + // constructors and destructor + + path() noexcept { } + + path(const path& __p) = default; + + path(path&& __p) noexcept + : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type) + { + _M_split_cmpts(); + __p.clear(); + } + + path(string_type&& __source) + : _M_pathname(std::move(__source)) + { _M_split_cmpts(); } + + template> + path(_Source const& __source) + : _M_pathname(_S_convert(_S_range_begin(__source), + _S_range_end(__source))) + { _M_split_cmpts(); } + + template> + path(_InputIterator __first, _InputIterator __last) + : _M_pathname(_S_convert(__first, __last)) + { _M_split_cmpts(); } + + template, + typename _Require2 = __value_type_is_char<_Source>> + path(_Source const& __source, const locale& __loc) + : _M_pathname(_S_convert_loc(_S_range_begin(__source), + _S_range_end(__source), __loc)) + { _M_split_cmpts(); } + + template, + typename _Require2 = __value_type_is_char<_InputIterator>> + path(_InputIterator __first, _InputIterator __last, const locale& __loc) + : _M_pathname(_S_convert_loc(__first, __last, __loc)) + { _M_split_cmpts(); } + + ~path() = default; + + // assignments + + path& operator=(const path& __p) = default; + path& operator=(path&& __p) noexcept; + path& operator=(string_type&& __source); + path& assign(string_type&& __source); + + template + _Path<_Source>& + operator=(_Source const& __source) + { return *this = path(__source); } + + template + _Path<_Source>& + assign(_Source const& __source) + { return *this = path(__source); } + + template + _Path<_InputIterator, _InputIterator>& + assign(_InputIterator __first, _InputIterator __last) + { return *this = path(__first, __last); } + + // appends + + 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 + _Path<_Source>& + operator/=(_Source const& __source) + { return append(__source); } + + template + _Path<_Source>& + append(_Source const& __source) + { + return _M_append(_S_convert(_S_range_begin(__source), + _S_range_end(__source))); + } + + template + _Path<_InputIterator, _InputIterator>& + append(_InputIterator __first, _InputIterator __last) + { return _M_append(_S_convert(__first, __last)); } + + // concatenation + + path& operator+=(const path& __x); + path& operator+=(const string_type& __x); + path& operator+=(const value_type* __x); + path& operator+=(value_type __x); + path& operator+=(basic_string_view __x); + + template + _Path<_Source>& + operator+=(_Source const& __x) { return concat(__x); } + + template + _Path<_CharT*, _CharT*>& + operator+=(_CharT __x); + + template + _Path<_Source>& + concat(_Source const& __x) + { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); } + + template + _Path<_InputIterator, _InputIterator>& + concat(_InputIterator __first, _InputIterator __last) + { return *this += _S_convert(__first, __last); } + + // modifiers + + void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } + + path& make_preferred(); + path& remove_filename(); + path& replace_filename(const path& __replacement); + path& replace_extension(const path& __replacement = path()); + + void swap(path& __rhs) noexcept; + + // native format observers + + const string_type& native() const noexcept { return _M_pathname; } + const value_type* c_str() const noexcept { return _M_pathname.c_str(); } + operator string_type() const { return _M_pathname; } + + template, + typename _Allocator = std::allocator<_CharT>> + std::basic_string<_CharT, _Traits, _Allocator> + string(const _Allocator& __a = _Allocator()) const; + + std::string string() const; +#if _GLIBCXX_USE_WCHAR_T + std::wstring wstring() const; +#endif + std::string u8string() const; + std::u16string u16string() const; + std::u32string u32string() const; + + // generic format observers + template, + typename _Allocator = std::allocator<_CharT>> + std::basic_string<_CharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const; + + std::string generic_string() const; +#if _GLIBCXX_USE_WCHAR_T + std::wstring generic_wstring() const; +#endif + std::string generic_u8string() const; + std::u16string generic_u16string() const; + std::u32string generic_u32string() const; + + // compare + + int compare(const path& __p) const noexcept; + int compare(const string_type& __s) const; + int compare(const value_type* __s) const; + int compare(const basic_string_view __s) const; + + // decomposition + + path root_name() const; + path root_directory() const; + path root_path() const; + path relative_path() const; + path parent_path() const; + path filename() const; + path stem() const; + path extension() const; + + // query + + bool empty() const noexcept { return _M_pathname.empty(); } + bool has_root_name() const; + bool has_root_directory() const; + bool has_root_path() const; + bool has_relative_path() const; + bool has_parent_path() const; + bool has_filename() const; + bool has_stem() const; + bool has_extension() const; + bool is_absolute() const; + bool is_relative() const { return !is_absolute(); } + + // generation + path lexically_normal() const; + path lexically_relative(const path& base) const; + path lexically_proximate(const path& base) const; + + // iterators + class iterator; + typedef iterator const_iterator; + + iterator begin() const; + iterator end() const; + + private: + enum class _Type : unsigned char { + _Multi, _Root_name, _Root_dir, _Filename + }; + + path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type) + { + __glibcxx_assert(_M_type != _Type::_Multi); + } + + enum class _Split { _Stem, _Extension }; + + path& _M_append(string_type&& __str) + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + operator/=(path(std::move(__str))); +#else + if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back()) + && (__str.empty() || !_S_is_dir_sep(__str.front()))) + _M_pathname += preferred_separator; + _M_pathname += __str; + _M_split_cmpts(); +#endif + return *this; + } + + pair _M_find_extension() const; + + template + struct _Cvt; + + static string_type + _S_convert(value_type* __src, __null_terminated) + { return string_type(__src); } + + static string_type + _S_convert(const value_type* __src, __null_terminated) + { return string_type(__src); } + + template + static string_type + _S_convert(_Iter __first, _Iter __last) + { + using __value_type = typename std::iterator_traits<_Iter>::value_type; + return _Cvt::type>:: + _S_convert(__first, __last); + } + + template + static string_type + _S_convert(_InputIterator __src, __null_terminated) + { + using _Tp = typename std::iterator_traits<_InputIterator>::value_type; + std::basic_string::type> __tmp; + for (; *__src != _Tp{}; ++__src) + __tmp.push_back(*__src); + return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size()); + } + + static string_type + _S_convert_loc(const char* __first, const char* __last, + const std::locale& __loc); + + template + static string_type + _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) + { + const std::string __str(__first, __last); + return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc); + } + + template + static string_type + _S_convert_loc(_InputIterator __src, __null_terminated, + const std::locale& __loc) + { + std::string __tmp; + while (*__src != '\0') + __tmp.push_back(*__src++); + return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc); + } + + template + static basic_string<_CharT, _Traits, _Allocator> + _S_str_convert(const string_type&, const _Allocator& __a); + + bool _S_is_dir_sep(value_type __ch) + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + return __ch == L'/' || __ch == preferred_separator; +#else + return __ch == '/'; +#endif + } + + void _M_split_cmpts(); + void _M_trim(); + void _M_add_root_name(size_t __n); + void _M_add_root_dir(size_t __pos); + void _M_add_filename(size_t __pos, size_t __n); + + string_type _M_pathname; + + struct _Cmpt; + using _List = _GLIBCXX_STD_C::vector<_Cmpt>; + _List _M_cmpts; // empty unless _M_type == _Type::_Multi + _Type _M_type = _Type::_Multi; + }; + + template<> + struct path::__is_encoded_char : std::true_type + { using value_type = char; }; + + template<> + struct path::__is_encoded_char : std::true_type + { using value_type = wchar_t; }; + + template<> + struct path::__is_encoded_char : std::true_type + { using value_type = char16_t; }; + + template<> + struct path::__is_encoded_char : std::true_type + { using value_type = char32_t; }; + + template + struct path::__is_encoded_char : __is_encoded_char<_Tp> { }; + + inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } + + size_t hash_value(const path& __p) noexcept; + + /// Compare paths + inline bool operator<(const path& __lhs, const path& __rhs) noexcept + { return __lhs.compare(__rhs) < 0; } + + /// Compare paths + inline bool operator<=(const path& __lhs, const path& __rhs) noexcept + { return !(__rhs < __lhs); } + + /// Compare paths + inline bool operator>(const path& __lhs, const path& __rhs) noexcept + { return __rhs < __lhs; } + + /// Compare paths + inline bool operator>=(const path& __lhs, const path& __rhs) noexcept + { return !(__lhs < __rhs); } + + /// Compare paths + inline bool operator==(const path& __lhs, const path& __rhs) noexcept + { return __lhs.compare(__rhs) == 0; } + + /// Compare paths + inline bool operator!=(const path& __lhs, const path& __rhs) noexcept + { return !(__lhs == __rhs); } + + /// Append one path to another + inline path operator/(const path& __lhs, const path& __rhs) + { return path(__lhs) /= __rhs; } + + /// Write a path to a stream + template + basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) + { + auto __tmp = __p.string<_CharT, _Traits>(); + using __quoted_string + = std::__detail::_Quoted_string; + __os << __quoted_string{__tmp, '"', '\\'}; + return __os; + } + + /// Read a path from a stream + template + basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) + { + basic_string<_CharT, _Traits> __tmp; + using __quoted_string + = std::__detail::_Quoted_string; + if (__is >> __quoted_string{ __tmp, '"', '\\' }) + __p = std::move(__tmp); + return __is; + } + + template + inline auto + u8path(const _Source& __source) + -> decltype(filesystem::path(__source, std::locale::classic())) + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + const std::string __u8str{__source}; + return std::filesystem::u8path(__u8str.begin(), __u8str.end()); +#else + return path{ __source }; +#endif + } + + template + inline auto + u8path(_InputIterator __first, _InputIterator __last) + -> decltype(filesystem::path(__first, __last, std::locale::classic())) + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + codecvt_utf8 __cvt; + string_type __tmp; + if (__str_codecvt_in(__first, __last, __tmp, __cvt)) + return path{ __tmp }; + else + return {}; +#else + return path{ __first, __last }; +#endif + } + + class filesystem_error : public std::system_error + { + public: + filesystem_error(const string& __what_arg, error_code __ec) + : system_error(__ec, __what_arg) { } + + filesystem_error(const string& __what_arg, const path& __p1, + error_code __ec) + : system_error(__ec, __what_arg), _M_path1(__p1) { } + + filesystem_error(const string& __what_arg, const path& __p1, + const path& __p2, error_code __ec) + : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2) + { } + + ~filesystem_error(); + + const path& path1() const noexcept { return _M_path1; } + const path& path2() const noexcept { return _M_path2; } + const char* what() const noexcept { return _M_what.c_str(); } + + private: + std::string _M_gen_what(); + + path _M_path1; + path _M_path2; + std::string _M_what = _M_gen_what(); + }; + + struct path::_Cmpt : path + { + _Cmpt(string_type __s, _Type __t, size_t __pos) + : path(std::move(__s), __t), _M_pos(__pos) { } + + _Cmpt() : _M_pos(-1) { } + + size_t _M_pos; + }; + + // specialize _Cvt for degenerate 'noconv' case + template<> + struct path::_Cvt + { + template + static string_type + _S_convert(_Iter __first, _Iter __last) + { return string_type{__first, __last}; } + }; + + template + struct path::_Cvt + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + static string_type + _S_wconvert(const char* __f, const char* __l, true_type) + { + using _Cvt = std::codecvt; + const auto& __cvt = std::use_facet<_Cvt>(std::locale{}); + std::wstring __wstr; + if (__str_codecvt_in(__f, __l, __wstr, __cvt)) + return __wstr; + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); + } + + static string_type + _S_wconvert(const _CharT* __f, const _CharT* __l, false_type) + { + std::codecvt_utf8<_CharT> __cvt; + std::string __str; + if (__str_codecvt_out(__f, __l, __str, __cvt)) + { + const char* __f2 = __str.data(); + const char* __l2 = __f2 + __str.size(); + std::codecvt_utf8 __wcvt; + std::wstring __wstr; + if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt)) + return __wstr; + } + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); + } + + static string_type + _S_convert(const _CharT* __f, const _CharT* __l) + { + return _S_wconvert(__f, __l, is_same<_CharT, char>{}); + } +#else + static string_type + _S_convert(const _CharT* __f, const _CharT* __l) + { + std::codecvt_utf8<_CharT> __cvt; + std::string __str; + if (__str_codecvt_out(__f, __l, __str, __cvt)) + return __str; + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); + } +#endif + + static string_type + _S_convert(_CharT* __f, _CharT* __l) + { + return _S_convert(const_cast(__f), + const_cast(__l)); + } + + template + static string_type + _S_convert(_Iter __first, _Iter __last) + { + const std::basic_string<_CharT> __str(__first, __last); + return _S_convert(__str.data(), __str.data() + __str.size()); + } + + template + static string_type + _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first, + __gnu_cxx::__normal_iterator<_Iter, _Cont> __last) + { return _S_convert(__first.base(), __last.base()); } + }; + + /// An iterator for the components of a path + class path::iterator + { + public: + using difference_type = std::ptrdiff_t; + using value_type = path; + using reference = const path&; + using pointer = const path*; + using iterator_category = std::bidirectional_iterator_tag; + + iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { } + + iterator(const iterator&) = default; + iterator& operator=(const iterator&) = default; + + reference operator*() const; + pointer operator->() const { return std::__addressof(**this); } + + iterator& operator++(); + iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } + + iterator& operator--(); + iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; } + + friend bool operator==(const iterator& __lhs, const iterator& __rhs) + { return __lhs._M_equals(__rhs); } + + friend bool operator!=(const iterator& __lhs, const iterator& __rhs) + { return !__lhs._M_equals(__rhs); } + + private: + friend class path; + + iterator(const path* __path, path::_List::const_iterator __iter) + : _M_path(__path), _M_cur(__iter), _M_at_end() + { } + + iterator(const path* __path, bool __at_end) + : _M_path(__path), _M_cur(), _M_at_end(__at_end) + { } + + bool _M_equals(iterator) const; + + const path* _M_path; + path::_List::const_iterator _M_cur; + bool _M_at_end; // only used when type != _Multi + }; + + + inline path& + path::operator=(path&& __p) noexcept + { + _M_pathname = std::move(__p._M_pathname); + _M_cmpts = std::move(__p._M_cmpts); + _M_type = __p._M_type; + __p.clear(); + return *this; + } + + inline path& + path::operator=(string_type&& __source) + { return *this = path(std::move(__source)); } + + inline path& + path::assign(string_type&& __source) + { return *this = path(std::move(__source)); } + + inline path& + path::operator+=(const path& __p) + { + return operator+=(__p.native()); + } + + inline path& + path::operator+=(const string_type& __x) + { + _M_pathname += __x; + _M_split_cmpts(); + return *this; + } + + inline path& + path::operator+=(const value_type* __x) + { + _M_pathname += __x; + _M_split_cmpts(); + return *this; + } + + inline path& + path::operator+=(value_type __x) + { + _M_pathname += __x; + _M_split_cmpts(); + return *this; + } + + inline path& + path::operator+=(basic_string_view __x) + { + _M_pathname.append(__x.data(), __x.size()); + _M_split_cmpts(); + return *this; + } + + template + inline path::_Path<_CharT*, _CharT*>& + path::operator+=(_CharT __x) + { + auto* __addr = std::__addressof(__x); + return concat(__addr, __addr + 1); + } + + inline path& + path::make_preferred() + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + std::replace(_M_pathname.begin(), _M_pathname.end(), L'/', + preferred_separator); +#endif + return *this; + } + + inline void path::swap(path& __rhs) noexcept + { + _M_pathname.swap(__rhs._M_pathname); + _M_cmpts.swap(__rhs._M_cmpts); + std::swap(_M_type, __rhs._M_type); + } + + template + std::basic_string<_CharT, _Traits, _Allocator> + path::_S_str_convert(const string_type& __str, const _Allocator& __a) + { + if (__str.size() == 0) + return std::basic_string<_CharT, _Traits, _Allocator>(__a); + + const value_type* __first = __str.data(); + const value_type* __last = __first + __str.size(); + +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + using _CharAlloc = __alloc_rebind<_Allocator, char>; + using _String = basic_string, _CharAlloc>; + using _WString = basic_string<_CharT, _Traits, _Allocator>; + + // use codecvt_utf8 to convert native string to UTF-8 + codecvt_utf8 __cvt; + _String __u8str{_CharAlloc{__a}}; + if (__str_codecvt_out(__first, __last, __u8str, __cvt)) + { + if constexpr (is_same_v<_CharT, char>) + return __u8str; + else + { + _WString __wstr; + // use codecvt_utf8<_CharT> to convert UTF-8 to wide string + codecvt_utf8<_CharT> __cvt; + const char* __f = __u8str.data(); + const char* __l = __f + __u8str.size(); + if (__str_codecvt_in(__f, __l, __wstr, __cvt)) + return __wstr; + } + } +#else + codecvt_utf8<_CharT> __cvt; + basic_string<_CharT, _Traits, _Allocator> __wstr{__a}; + if (__str_codecvt_in(__first, __last, __wstr, __cvt)) + return __wstr; +#endif + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); + } + + template + inline basic_string<_CharT, _Traits, _Allocator> + path::string(const _Allocator& __a) const + { + if constexpr (is_same_v<_CharT, value_type>) +#if _GLIBCXX_USE_CXX11_ABI + return { _M_pathname, __a }; +#else + return { _M_pathname, string_type::size_type(0), __a }; +#endif + else + return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); + } + + inline std::string + path::string() const { return string(); } + +#if _GLIBCXX_USE_WCHAR_T + inline std::wstring + path::wstring() const { return string(); } +#endif + + inline std::string + path::u8string() const + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + std::string __str; + // convert from native encoding to UTF-8 + codecvt_utf8 __cvt; + const value_type* __first = _M_pathname.data(); + const value_type* __last = __first + _M_pathname.size(); + if (__str_codecvt_out(__first, __last, __str, __cvt)) + return __str; + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); +#else + return _M_pathname; +#endif + } + + inline std::u16string + path::u16string() const { return string(); } + + inline std::u32string + path::u32string() const { return string(); } + + template + inline std::basic_string<_CharT, _Traits, _Allocator> + path::generic_string(const _Allocator& __a) const + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + const value_type __slash = L'/'; +#else + const value_type __slash = '/'; +#endif + string_type __str(__a); + + if (_M_type == _Type::_Root_dir) + __str.assign(1, __slash); + else + { + __str.reserve(_M_pathname.size()); + bool __add_slash = false; + for (auto& __elem : *this) + { + if (__add_slash) + __str += __slash; + __str += __elem._M_pathname; + __add_slash = __elem._M_type == _Type::_Filename; + } + } + + if constexpr (is_same_v<_CharT, value_type>) + return __str; + else + return _S_str_convert<_CharT, _Traits>(__str, __a); + } + + inline std::string + path::generic_string() const + { return generic_string(); } + +#if _GLIBCXX_USE_WCHAR_T + inline std::wstring + path::generic_wstring() const + { return generic_string(); } +#endif + + inline std::string + path::generic_u8string() const + { return generic_string(); } + + inline std::u16string + path::generic_u16string() const + { return generic_string(); } + + inline std::u32string + path::generic_u32string() const + { return generic_string(); } + + inline int + path::compare(const string_type& __s) const { return compare(path(__s)); } + + inline int + path::compare(const value_type* __s) const { return compare(path(__s)); } + + inline int + path::compare(basic_string_view __s) const + { return compare(path(__s)); } + + inline path + path::filename() const + { + if (empty()) + return {}; + else if (_M_type == _Type::_Filename) + return *this; + else if (_M_type == _Type::_Multi) + { + if (_M_pathname.back() == preferred_separator) + return {}; + auto& __last = *--end(); + if (__last._M_type == _Type::_Filename) + return __last; + } + return {}; + } + + inline path + path::stem() const + { + auto ext = _M_find_extension(); + if (ext.first && ext.second != 0) + return path{ext.first->substr(0, ext.second)}; + return {}; + } + + inline path + path::extension() const + { + auto ext = _M_find_extension(); + if (ext.first && ext.second != string_type::npos) + return path{ext.first->substr(ext.second)}; + return {}; + } + + inline bool + path::has_stem() const + { + auto ext = _M_find_extension(); + return ext.first && ext.second != 0; + } + + inline bool + path::has_extension() const + { + auto ext = _M_find_extension(); + return ext.first && ext.second != string_type::npos; + } + + inline bool + path::is_absolute() const + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + return has_root_name(); +#else + return has_root_directory(); +#endif + } + + inline path::iterator + path::begin() const + { + if (_M_type == _Type::_Multi) + return iterator(this, _M_cmpts.begin()); + return iterator(this, false); + } + + inline path::iterator + path::end() const + { + if (_M_type == _Type::_Multi) + return iterator(this, _M_cmpts.end()); + return iterator(this, true); + } + + inline path::iterator& + path::iterator::operator++() + { + __glibcxx_assert(_M_path != nullptr); + if (_M_path->_M_type == _Type::_Multi) + { + __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); + ++_M_cur; + } + else + { + __glibcxx_assert(!_M_at_end); + _M_at_end = true; + } + return *this; + } + + inline path::iterator& + path::iterator::operator--() + { + __glibcxx_assert(_M_path != nullptr); + if (_M_path->_M_type == _Type::_Multi) + { + __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); + --_M_cur; + } + else + { + __glibcxx_assert(_M_at_end); + _M_at_end = false; + } + return *this; + } + + inline path::iterator::reference + path::iterator::operator*() const + { + __glibcxx_assert(_M_path != nullptr); + if (_M_path->_M_type == _Type::_Multi) + { + __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); + return *_M_cur; + } + return *_M_path; + } + + inline bool + path::iterator::_M_equals(iterator __rhs) const + { + if (_M_path != __rhs._M_path) + return false; + if (_M_path == nullptr) + return true; + if (_M_path->_M_type == path::_Type::_Multi) + return _M_cur == __rhs._M_cur; + return _M_at_end == __rhs._M_at_end; + } + + // @} group filesystem +_GLIBCXX_END_NAMESPACE_CXX11 +} // namespace filesystem + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_FS_PATH_H diff --git a/libstdc++-v3/include/experimental/bits/fs_dir.h b/libstdc++-v3/include/experimental/bits/fs_dir.h index 1ff0d9b6def..ecadf37a9cd 100644 --- a/libstdc++-v3/include/experimental/bits/fs_dir.h +++ b/libstdc++-v3/include/experimental/bits/fs_dir.h @@ -49,7 +49,7 @@ namespace filesystem inline namespace v1 { /** - * @ingroup filesystem + * @ingroup filesystem-ts * @{ */ @@ -351,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_CXX11 - // @} group filesystem + // @} group filesystem-ts } // namespace v1 } // namespace filesystem } // namespace experimental diff --git a/libstdc++-v3/include/experimental/bits/fs_fwd.h b/libstdc++-v3/include/experimental/bits/fs_fwd.h index 7b851a3d4a8..ac43c5f44f5 100644 --- a/libstdc++-v3/include/experimental/bits/fs_fwd.h +++ b/libstdc++-v3/include/experimental/bits/fs_fwd.h @@ -53,7 +53,7 @@ inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } #endif /** - * @defgroup filesystem Filesystem + * @defgroup filesystem-ts Filesystem TS * @ingroup experimental * * Utilities for performing operations on file systems and their components, @@ -278,7 +278,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 bool is_regular_file(file_status) noexcept; bool is_symlink(file_status) noexcept; - // @} group filesystem + // @} group filesystem-ts } // namespace v1 } // namespace filesystem } // namespace experimental diff --git a/libstdc++-v3/include/experimental/bits/fs_ops.h b/libstdc++-v3/include/experimental/bits/fs_ops.h index 387537260e0..fa7f1de6bc4 100644 --- a/libstdc++-v3/include/experimental/bits/fs_ops.h +++ b/libstdc++-v3/include/experimental/bits/fs_ops.h @@ -47,7 +47,7 @@ namespace filesystem inline namespace v1 { /** - * @ingroup filesystem + * @ingroup filesystem-ts * @{ */ @@ -285,7 +285,7 @@ inline namespace v1 path temp_directory_path(); path temp_directory_path(error_code& __ec); - // @} group filesystem + // @} group filesystem-ts } // namespace v1 } // namespace filesystem } // namespace experimental diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h index 9121439b7f2..3e9bc6357af 100644 --- a/libstdc++-v3/include/experimental/bits/fs_path.h +++ b/libstdc++-v3/include/experimental/bits/fs_path.h @@ -72,7 +72,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif /** - * @ingroup filesystem + * @ingroup filesystem-ts * @{ */ @@ -1079,7 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 return _M_at_end == __rhs._M_at_end; } - // @} group filesystem + // @} group filesystem-ts _GLIBCXX_END_NAMESPACE_CXX11 } // namespace v1 } // namespace filesystem diff --git a/libstdc++-v3/include/experimental/filesystem b/libstdc++-v3/include/experimental/filesystem index f0b19dd2910..90f6f9eabfe 100644 --- a/libstdc++-v3/include/experimental/filesystem +++ b/libstdc++-v3/include/experimental/filesystem @@ -40,36 +40,6 @@ #define __cpp_lib_experimental_filesystem 201406 -namespace std _GLIBCXX_VISIBILITY(default) -{ -_GLIBCXX_BEGIN_NAMESPACE_VERSION - -namespace experimental -{ -namespace filesystem -{ -inline namespace v1 -{ - /** - * @ingroup filesystem - */ - inline std::string filesystem_error::_M_gen_what() - { - std::string __what = "filesystem error: "; - __what += system_error::what(); - if (!_M_path1.empty()) - __what += " [" + _M_path1.string() + ']'; - if (!_M_path2.empty()) - __what += " [" + _M_path2.string() + ']'; - return __what; - } -} // namespace v1 -} // namespace filesystem -} // namespace experimental - -_GLIBCXX_END_NAMESPACE_VERSION -} // namespace std - #endif // C++11 #endif // _GLIBCXX_EXPERIMENTAL_FILESYSTEM diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h index b2993cd379f..4e1a71afeb0 100644 --- a/libstdc++-v3/include/precompiled/stdc++.h +++ b/libstdc++-v3/include/precompiled/stdc++.h @@ -122,6 +122,7 @@ #include #endif -#if __cplusplus > 201402L +#if __cplusplus >= 201703L #include +#include #endif diff --git a/libstdc++-v3/include/std/filesystem b/libstdc++-v3/include/std/filesystem new file mode 100644 index 00000000000..b09997704c1 --- /dev/null +++ b/libstdc++-v3/include/std/filesystem @@ -0,0 +1,45 @@ +// -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file filesystem + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_FILESYSTEM +#define _GLIBCXX_FILESYSTEM 1 + +#pragma GCC system_header + +#if __cplusplus >= 201703L + +#include +#include +#include +#include + +#define __cpp_lib_filesystem 201703 + +#endif // C++17 + +#endif // _GLIBCXX_FILESYSTEM diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 04f413adf04..9d2119632ba 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -1592,6 +1592,10 @@ def build_libstdcxx_dictionary (): 'path', StdExpPathPrinter) libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::', 'path', StdExpPathPrinter) + libstdcxx_printer.add_version('std::filesystem::', + 'path', StdExpPathPrinter) + libstdcxx_printer.add_version('std::filesystem::__cxx11::', + 'path', StdExpPathPrinter) # C++17 components libstdcxx_printer.add_version('std::', diff --git a/libstdc++-v3/src/filesystem/Makefile.am b/libstdc++-v3/src/filesystem/Makefile.am index 836bdd390a7..19de2a324fa 100644 --- a/libstdc++-v3/src/filesystem/Makefile.am +++ b/libstdc++-v3/src/filesystem/Makefile.am @@ -30,7 +30,10 @@ if ENABLE_DUAL_ABI cxx11_abi_sources = \ cow-dir.cc \ cow-ops.cc \ - cow-path.cc + cow-path.cc \ + cow-std-dir.cc \ + cow-std-ops.cc \ + cow-std-path.cc else cxx11_abi_sources = endif @@ -39,6 +42,9 @@ sources = \ dir.cc \ ops.cc \ path.cc \ + std-dir.cc \ + std-ops.cc \ + std-path.cc \ ${cxx11_abi_sources} # vpath % $(top_srcdir)/src/filesystem @@ -52,7 +58,7 @@ libstdc__fs_la_SOURCES = $(sources) # as the occasion call for it. AM_CXXFLAGS = \ $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \ - -std=gnu++14 \ + -std=gnu++17 \ $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) AM_MAKEFLAGS = \ diff --git a/libstdc++-v3/src/filesystem/Makefile.in b/libstdc++-v3/src/filesystem/Makefile.in index a4fdf790ae2..847b19b6982 100644 --- a/libstdc++-v3/src/filesystem/Makefile.in +++ b/libstdc++-v3/src/filesystem/Makefile.in @@ -114,8 +114,10 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" LTLIBRARIES = $(toolexeclib_LTLIBRARIES) libstdc__fs_la_LIBADD = @ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-dir.lo cow-ops.lo \ -@ENABLE_DUAL_ABI_TRUE@ cow-path.lo -am__objects_2 = dir.lo ops.lo path.lo $(am__objects_1) +@ENABLE_DUAL_ABI_TRUE@ cow-path.lo cow-std-dir.lo \ +@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.lo cow-std-path.lo +am__objects_2 = dir.lo ops.lo path.lo std-dir.lo std-ops.lo \ + std-path.lo $(am__objects_1) am_libstdc__fs_la_OBJECTS = $(am__objects_2) libstdc__fs_la_OBJECTS = $(am_libstdc__fs_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) @@ -362,12 +364,18 @@ headers = @ENABLE_DUAL_ABI_TRUE@cxx11_abi_sources = \ @ENABLE_DUAL_ABI_TRUE@ cow-dir.cc \ @ENABLE_DUAL_ABI_TRUE@ cow-ops.cc \ -@ENABLE_DUAL_ABI_TRUE@ cow-path.cc +@ENABLE_DUAL_ABI_TRUE@ cow-path.cc \ +@ENABLE_DUAL_ABI_TRUE@ cow-std-dir.cc \ +@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.cc \ +@ENABLE_DUAL_ABI_TRUE@ cow-std-path.cc sources = \ dir.cc \ ops.cc \ path.cc \ + std-dir.cc \ + std-ops.cc \ + std-path.cc \ ${cxx11_abi_sources} @@ -381,7 +389,7 @@ libstdc__fs_la_SOURCES = $(sources) # as the occasion call for it. AM_CXXFLAGS = \ $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \ - -std=gnu++14 \ + -std=gnu++17 \ $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) AM_MAKEFLAGS = \ diff --git a/libstdc++-v3/src/filesystem/cow-dir.cc b/libstdc++-v3/src/filesystem/cow-dir.cc index 4e47bbdd7c8..96907abd712 100644 --- a/libstdc++-v3/src/filesystem/cow-dir.cc +++ b/libstdc++-v3/src/filesystem/cow-dir.cc @@ -1,4 +1,4 @@ -// Class filesystem::directory_entry etc. -*- C++ -*- +// Class experimental::filesystem::directory_entry etc. -*- C++ -*- // Copyright (C) 2015-2017 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/src/filesystem/cow-ops.cc b/libstdc++-v3/src/filesystem/cow-ops.cc index 9ad91f0f11a..3b41d7c98ac 100644 --- a/libstdc++-v3/src/filesystem/cow-ops.cc +++ b/libstdc++-v3/src/filesystem/cow-ops.cc @@ -1,4 +1,4 @@ -// Filesystem operations -*- C++ -*- +// Filesystem TS operations -*- C++ -*- // Copyright (C) 2015-2017 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/src/filesystem/cow-path.cc b/libstdc++-v3/src/filesystem/cow-path.cc index b216088ca32..0817b0ae491 100644 --- a/libstdc++-v3/src/filesystem/cow-path.cc +++ b/libstdc++-v3/src/filesystem/cow-path.cc @@ -1,4 +1,4 @@ -// Class filesystem::path -*- C++ -*- +// Class experimental::filesystem::path -*- C++ -*- // Copyright (C) 2015-2017 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/src/filesystem/cow-std-dir.cc b/libstdc++-v3/src/filesystem/cow-std-dir.cc new file mode 100644 index 00000000000..edcf24506bb --- /dev/null +++ b/libstdc++-v3/src/filesystem/cow-std-dir.cc @@ -0,0 +1,26 @@ +// Class filesystem::directory_entry etc. -*- C++ -*- + +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#define _GLIBCXX_USE_CXX11_ABI 0 +#include "std-dir.cc" diff --git a/libstdc++-v3/src/filesystem/cow-std-ops.cc b/libstdc++-v3/src/filesystem/cow-std-ops.cc new file mode 100644 index 00000000000..bea5470a890 --- /dev/null +++ b/libstdc++-v3/src/filesystem/cow-std-ops.cc @@ -0,0 +1,26 @@ +// Filesystem operations -*- C++ -*- + +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#define _GLIBCXX_USE_CXX11_ABI 0 +#include "std-ops.cc" diff --git a/libstdc++-v3/src/filesystem/cow-std-path.cc b/libstdc++-v3/src/filesystem/cow-std-path.cc new file mode 100644 index 00000000000..718ff952864 --- /dev/null +++ b/libstdc++-v3/src/filesystem/cow-std-path.cc @@ -0,0 +1,26 @@ +// Class filesystem::path -*- C++ -*- + +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#define _GLIBCXX_USE_CXX11_ABI 0 +#include "std-path.cc" diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h new file mode 100644 index 00000000000..e8036321b20 --- /dev/null +++ b/libstdc++-v3/src/filesystem/dir-common.h @@ -0,0 +1,149 @@ +// Filesystem directory iterator utilities -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_DIR_COMMON_H +#define _GLIBCXX_DIR_COMMON_H 1 + +#include // strcmp +#ifdef _GLIBCXX_HAVE_DIRENT_H +# ifdef _GLIBCXX_HAVE_SYS_TYPES_H +# include +# endif +# include +#else +# error "the header is needed to build the Filesystem TS" +#endif + +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +# undef opendir +# define opendir _wopendir +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace filesystem +{ + +struct _Dir_base +{ + _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { } + + // If no error occurs then dirp is non-null, + // otherwise null (whether error ignored or not). + _Dir_base(const char* p, bool skip_permission_denied, + error_code& ec) noexcept + : dirp(::opendir(p)) + { + if (dirp) + ec.clear(); + else + { + const int err = errno; + if (err == EACCES && skip_permission_denied) + ec.clear(); + else + ec.assign(err, std::generic_category()); + } + } + + _Dir_base(_Dir_base&& d) : dirp(std::exchange(d.dirp, nullptr)) { } + + _Dir_base& operator=(_Dir_base&&) = delete; + + ~_Dir_base() { if (dirp) ::closedir(dirp); } + + const struct ::dirent* + advance(bool skip_permission_denied, error_code& ec) noexcept + { + ec.clear(); + + int err = std::exchange(errno, 0); + const struct ::dirent* entp = readdir(dirp); + // std::swap cannot be used with Bionic's errno + err = std::exchange(errno, err); + + if (entp) + { + // skip past dot and dot-dot + if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) + return advance(skip_permission_denied, ec); + return entp; + } + else if (err) + { + if (err == EACCES && skip_permission_denied) + return nullptr; + ec.assign(err, std::generic_category()); + return nullptr; + } + else + { + // reached the end + return nullptr; + } + } + + DIR* dirp; +}; + +} // namespace filesystem + +// BEGIN/END macros must be defined before including this file. +_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM +inline file_type +get_file_type(const ::dirent& d __attribute__((__unused__))) +{ +#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE + switch (d.d_type) + { + case DT_BLK: + return file_type::block; + case DT_CHR: + return file_type::character; + case DT_DIR: + return file_type::directory; + case DT_FIFO: + return file_type::fifo; + case DT_LNK: + return file_type::symlink; + case DT_REG: + return file_type::regular; + case DT_SOCK: + return file_type::socket; + case DT_UNKNOWN: + return file_type::unknown; + default: + return file_type::none; + } +#else + return file_type::none; +#endif +} +_GLIBCXX_END_NAMESPACE_FILESYSTEM + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // _GLIBCXX_DIR_COMMON_H diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc index 9aecd8042a5..42f63e73984 100644 --- a/libstdc++-v3/src/filesystem/dir.cc +++ b/libstdc++-v3/src/filesystem/dir.cc @@ -31,40 +31,76 @@ #include #include #include -#ifdef _GLIBCXX_HAVE_DIRENT_H -# ifdef _GLIBCXX_HAVE_SYS_TYPES_H -# include -# endif -# include -#else -# error "the header is needed to build the Filesystem TS" -#endif - -#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS -# undef opendir -# define opendir _wopendir -#endif +#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \ + namespace experimental { namespace filesystem { +#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } } +#include "dir-common.h" namespace fs = std::experimental::filesystem; -struct fs::_Dir +struct fs::_Dir : std::filesystem::_Dir_base { - _Dir() : dirp(nullptr) { } + _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec) + : _Dir_base(p.c_str(), skip_permission_denied, ec) + { + if (!ec) + path = p; + } - _Dir(DIR* dirp, const fs::path& path) : dirp(dirp), path(path) { } + _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } - _Dir(_Dir&& d) - : dirp(std::exchange(d.dirp, nullptr)), path(std::move(d.path)), - entry(std::move(d.entry)), type(d.type) - { } + _Dir(_Dir&&) = default; - _Dir& operator=(_Dir&&) = delete; + // Returns false when the end of the directory entries is reached. + // Reports errors by setting ec. + bool advance(bool skip_permission_denied, error_code& ec) noexcept + { + if (const auto entp = _Dir_base::advance(skip_permission_denied, ec)) + { + entry = fs::directory_entry{path / entp->d_name}; + type = get_file_type(*entp); + return true; + } + else if (!ec) + { + // reached the end + entry = {}; + type = file_type::none; + } + return false; + } - ~_Dir() { if (dirp) ::closedir(dirp); } + bool advance(error_code& ec) noexcept { return advance(false, ec); } - bool advance(std::error_code*, directory_options = directory_options::none); + // Returns false when the end of the directory entries is reached. + // Reports errors by throwing. + bool advance(bool skip_permission_denied = false) + { + error_code ec; + const bool ok = advance(skip_permission_denied, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "directory iterator cannot advance", ec)); + return ok; + } + + bool should_recurse(bool follow_symlink, error_code& ec) const + { + file_type type = this->type; + if (type == file_type::none || type == file_type::unknown) + { + type = entry.symlink_status(ec).type(); + if (ec) + return false; + } + + if (type == file_type::directory) + return true; + if (type == file_type::symlink) + return follow_symlink && is_directory(entry.status(ec)); + return false; + } - DIR* dirp; fs::path path; directory_entry entry; file_type type = file_type::none; @@ -78,119 +114,28 @@ namespace { return (obj & bits) != Bitmask::none; } - - // Returns {dirp, p} on success, {} on error (whether ignored or not). - inline fs::_Dir - open_dir(const fs::path& p, fs::directory_options options, - std::error_code* ec) - { - if (ec) - ec->clear(); - - if (DIR* dirp = ::opendir(p.c_str())) - return {dirp, p}; - - const int err = errno; - if (err == EACCES - && is_set(options, fs::directory_options::skip_permission_denied)) - return {}; - - if (!ec) - _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error( - "directory iterator cannot open directory", p, - std::error_code(err, std::generic_category()))); - - ec->assign(err, std::generic_category()); - return {}; - } - - inline fs::file_type - get_file_type(const ::dirent& d __attribute__((__unused__))) - { -#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE - switch (d.d_type) - { - case DT_BLK: - return fs::file_type::block; - case DT_CHR: - return fs::file_type::character; - case DT_DIR: - return fs::file_type::directory; - case DT_FIFO: - return fs::file_type::fifo; - case DT_LNK: - return fs::file_type::symlink; - case DT_REG: - return fs::file_type::regular; - case DT_SOCK: - return fs::file_type::socket; - case DT_UNKNOWN: - return fs::file_type::unknown; - default: - return fs::file_type::none; - } -#else - return fs::file_type::none; -#endif - } -} - - -// Returns false when the end of the directory entries is reached. -// Reports errors by setting ec or throwing. -bool -fs::_Dir::advance(error_code* ec, directory_options options) -{ - if (ec) - ec->clear(); - - int err = std::exchange(errno, 0); - const auto entp = readdir(dirp); - // std::swap cannot be used with Bionic's errno - err = std::exchange(errno, err); - - if (entp) - { - // skip past dot and dot-dot - if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) - return advance(ec, options); - entry = fs::directory_entry{path / entp->d_name}; - type = get_file_type(*entp); - return true; - } - else if (err) - { - if (err == EACCES - && is_set(options, directory_options::skip_permission_denied)) - return false; - - if (!ec) - _GLIBCXX_THROW_OR_ABORT(filesystem_error( - "directory iterator cannot advance", - std::error_code(err, std::generic_category()))); - ec->assign(err, std::generic_category()); - return false; - } - else - { - // reached the end - entry = {}; - type = fs::file_type::none; - return false; - } } fs::directory_iterator:: -directory_iterator(const path& p, directory_options options, error_code* ec) +directory_iterator(const path& p, directory_options options, error_code* ecptr) { - _Dir dir = open_dir(p, options, ec); + const bool skip_permission_denied + = is_set(options, directory_options::skip_permission_denied); + + error_code ec; + _Dir dir(p, skip_permission_denied, ec); if (dir.dirp) { auto sp = std::make_shared(std::move(dir)); - if (sp->advance(ec, options)) + if (sp->advance(skip_permission_denied, ec)) _M_dir.swap(sp); } + if (ecptr) + *ecptr = ec; + else if (ec) + _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error( + "directory iterator cannot open directory", p, ec)); } const fs::directory_entry& @@ -210,7 +155,7 @@ fs::directory_iterator::operator++() _GLIBCXX_THROW_OR_ABORT(filesystem_error( "cannot advance non-dereferenceable directory iterator", std::make_error_code(errc::invalid_argument))); - if (!_M_dir->advance(nullptr)) + if (!_M_dir->advance()) _M_dir.reset(); return *this; } @@ -223,13 +168,11 @@ fs::directory_iterator::increment(error_code& ec) noexcept ec = std::make_error_code(errc::invalid_argument); return *this; } - if (!_M_dir->advance(&ec)) + if (!_M_dir->advance(ec)) _M_dir.reset(); return *this; } -using Dir_iter_pair = std::pair; - struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir> { void clear() { c.clear(); } @@ -240,6 +183,8 @@ recursive_directory_iterator(const path& p, directory_options options, error_code* ec) : _M_options(options), _M_pending(true) { + if (ec) + ec->clear(); if (DIR* dirp = ::opendir(p.c_str())) { auto sp = std::make_shared<_Dir_stack>(); @@ -252,11 +197,7 @@ recursive_directory_iterator(const path& p, directory_options options, const int err = errno; if (err == EACCES && is_set(options, fs::directory_options::skip_permission_denied)) - { - if (ec) - ec->clear(); - return; - } + return; if (!ec) _GLIBCXX_THROW_OR_ABORT(filesystem_error( @@ -300,35 +241,6 @@ fs::recursive_directory_iterator::operator++() return *this; } -namespace -{ - bool - recurse(const fs::_Dir& d, fs::directory_options options, std::error_code& ec) - { - bool follow_symlink - = is_set(options, fs::directory_options::follow_directory_symlink); -#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE - if (d.type == fs::file_type::directory) - return true; - if (d.type == fs::file_type::symlink && follow_symlink) - return d.entry.status().type() == fs::file_type::directory; - if (d.type != fs::file_type::none && d.type != fs::file_type::unknown) - return false; -#endif - const fs::path& path = d.entry.path(); - auto type = fs::symlink_status(path, ec).type(); - if (ec.value()) - return false; - if (type == fs::file_type::symlink) - { - if (!follow_symlink) - return false; - type = fs::status(path, ec).type(); - } - return type == fs::file_type::directory; - } -} - fs::recursive_directory_iterator& fs::recursive_directory_iterator::increment(error_code& ec) noexcept { @@ -338,11 +250,16 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept return *this; } + const bool follow + = is_set(_M_options, directory_options::follow_directory_symlink); + const bool skip_permission_denied + = is_set(_M_options, directory_options::skip_permission_denied); + auto& top = _M_dirs->top(); - if (std::exchange(_M_pending, true) && recurse(top, _M_options, ec)) + if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec)) { - _Dir dir = open_dir(top.entry.path(), _M_options, &ec); + _Dir dir(top.entry.path(), skip_permission_denied, ec); if (ec) { _M_dirs.reset(); @@ -352,7 +269,7 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept _M_dirs->push(std::move(dir)); } - while (!_M_dirs->top().advance(&ec, _M_options) && !ec) + while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec) { _M_dirs->pop(); if (_M_dirs->empty()) @@ -373,6 +290,9 @@ fs::recursive_directory_iterator::pop(error_code& ec) return; } + const bool skip_permission_denied + = is_set(_M_options, directory_options::skip_permission_denied); + do { _M_dirs->pop(); if (_M_dirs->empty()) @@ -381,7 +301,7 @@ fs::recursive_directory_iterator::pop(error_code& ec) ec.clear(); return; } - } while (!_M_dirs->top().advance(&ec, _M_options)); + } while (!_M_dirs->top().advance(skip_permission_denied, ec)); } void diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h new file mode 100644 index 00000000000..12c12b08f8c --- /dev/null +++ b/libstdc++-v3/src/filesystem/ops-common.h @@ -0,0 +1,148 @@ +// Filesystem operation utilities -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_OPS_COMMON_H +#define _GLIBCXX_OPS_COMMON_H 1 + +#include + +#ifdef _GLIBCXX_HAVE_UNISTD_H +# include +# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H) +# include +# include +# endif +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace filesystem +{ + template + inline bool is_set(Bitmask obj, Bitmask bits) + { + return (obj & bits) != Bitmask::none; + } + + inline bool + is_not_found_errno(int err) noexcept + { + return err == ENOENT || err == ENOTDIR; + } + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + typedef struct ::stat stat_type; + + inline std::chrono::system_clock::time_point + file_time(const stat_type& st, std::error_code& ec) noexcept + { + using namespace std::chrono; +#ifdef _GLIBCXX_USE_ST_MTIM + time_t s = st.st_mtim.tv_sec; + nanoseconds ns{st.st_mtim.tv_nsec}; +#else + time_t s = st.st_mtime; + nanoseconds ns{}; +#endif + + if (s >= (nanoseconds::max().count() / 1e9)) + { + ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW + return system_clock::time_point::min(); + } + ec.clear(); + return system_clock::time_point{seconds{s} + ns}; + } + + struct copy_options_existing_file + { + bool skip, update, overwrite; + }; + + bool + do_copy_file(const char* from, const char* to, + copy_options_existing_file options, + stat_type* from_st, stat_type* to_st, + std::error_code& ec) noexcept; + +#endif // _GLIBCXX_HAVE_SYS_STAT_H + +} // namespace filesystem + +// BEGIN/END macros must be defined before including this file. +_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + typedef struct ::stat stat_type; + + inline file_type + make_file_type(const stat_type& st) noexcept + { +#ifdef _GLIBCXX_HAVE_S_ISREG + if (S_ISREG(st.st_mode)) + return file_type::regular; + else if (S_ISDIR(st.st_mode)) + return file_type::directory; + else if (S_ISCHR(st.st_mode)) + return file_type::character; + else if (S_ISBLK(st.st_mode)) + return file_type::block; + else if (S_ISFIFO(st.st_mode)) + return file_type::fifo; + else if (S_ISLNK(st.st_mode)) + return file_type::symlink; + else if (S_ISSOCK(st.st_mode)) + return file_type::socket; +#endif + return file_type::unknown; + } + + inline file_status + make_file_status(const stat_type& st) noexcept + { + return file_status{ + make_file_type(st), + static_cast(st.st_mode) & perms::mask + }; + } + + inline std::filesystem::copy_options_existing_file + copy_file_options(copy_options opt) + { + using std::filesystem::is_set; + return { + is_set(opt, copy_options::skip_existing), + is_set(opt, copy_options::update_existing), + is_set(opt, copy_options::overwrite_existing) + }; + } +#endif // _GLIBCXX_HAVE_SYS_STAT_H + +_GLIBCXX_END_NAMESPACE_FILESYSTEM + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // _GLIBCXX_OPS_COMMON_H diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index c711de16f06..61d9c89e616 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -1,4 +1,4 @@ -// Filesystem operations -*- C++ -*- +// Filesystem TS operations -*- C++ -*- // Copyright (C) 2014-2017 Free Software Foundation, Inc. // @@ -35,26 +35,24 @@ #include #include #include // PATH_MAX -#ifdef _GLIBCXX_HAVE_UNISTD_H -# include -# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H) -# include -# include -# endif -#endif #ifdef _GLIBCXX_HAVE_FCNTL_H -# include +# include // AT_FDCWD, AT_SYMLINK_NOFOLLOW +#endif +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +# include // stat, utimensat, fchmodat #endif #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H -# include +# include // statvfs #endif -#ifdef _GLIBCXX_USE_SENDFILE -# include -#endif -#if _GLIBCXX_HAVE_UTIME_H -# include +#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H +# include // utime #endif +#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \ + namespace experimental { namespace filesystem { +#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } } +#include "ops-common.h" + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS # undef utime # define utime _wutime @@ -240,254 +238,16 @@ fs::copy(const path& from, const path& to, copy_options options) namespace { - template - inline bool is_set(Bitmask obj, Bitmask bits) - { - return (obj & bits) != Bitmask::none; - } -} + using std::filesystem::is_set; #ifdef _GLIBCXX_HAVE_SYS_STAT_H -namespace -{ typedef struct ::stat stat_type; - inline fs::file_type - make_file_type(const stat_type& st) noexcept - { - using fs::file_type; -#ifdef _GLIBCXX_HAVE_S_ISREG - if (S_ISREG(st.st_mode)) - return file_type::regular; - else if (S_ISDIR(st.st_mode)) - return file_type::directory; - else if (S_ISCHR(st.st_mode)) - return file_type::character; - else if (S_ISBLK(st.st_mode)) - return file_type::block; - else if (S_ISFIFO(st.st_mode)) - return file_type::fifo; - else if (S_ISLNK(st.st_mode)) - return file_type::symlink; - else if (S_ISSOCK(st.st_mode)) - return file_type::socket; -#endif - return file_type::unknown; - - } - - inline fs::file_status - make_file_status(const stat_type& st) noexcept - { - return fs::file_status{ - make_file_type(st), - static_cast(st.st_mode) & fs::perms::mask - }; - } - - inline bool - is_not_found_errno(int err) noexcept - { - return err == ENOENT || err == ENOTDIR; - } - - inline fs::file_time_type - file_time(const stat_type& st, std::error_code& ec) noexcept - { - using namespace std::chrono; -#ifdef _GLIBCXX_USE_ST_MTIM - time_t s = st.st_mtim.tv_sec; - nanoseconds ns{st.st_mtim.tv_nsec}; -#else - time_t s = st.st_mtime; - nanoseconds ns{}; -#endif - - if (s >= (nanoseconds::max().count() / 1e9)) - { - ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW - return fs::file_time_type::min(); - } - ec.clear(); - return fs::file_time_type{seconds{s} + ns}; - } - - bool - do_copy_file(const fs::path& from, const fs::path& to, - fs::copy_options option, - stat_type* from_st, stat_type* to_st, - std::error_code& ec) noexcept - { - stat_type st1, st2; - fs::file_status t, f; - - if (to_st == nullptr) - { - if (::stat(to.c_str(), &st1)) - { - int err = errno; - if (!is_not_found_errno(err)) - { - ec.assign(err, std::generic_category()); - return false; - } - } - else - to_st = &st1; - } - else if (to_st == from_st) - to_st = nullptr; - - if (to_st == nullptr) - t = fs::file_status{fs::file_type::not_found}; - else - t = make_file_status(*to_st); - - if (from_st == nullptr) - { - if (::stat(from.c_str(), &st2)) - { - ec.assign(errno, std::generic_category()); - return false; - } - else - from_st = &st2; - } - f = make_file_status(*from_st); - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2712. copy_file() has a number of unspecified error conditions - if (!is_regular_file(f)) - { - ec = std::make_error_code(std::errc::not_supported); - return false; - } - - using opts = fs::copy_options; - - if (exists(t)) - { - if (!is_regular_file(t)) - { - ec = std::make_error_code(std::errc::not_supported); - return false; - } - - if (to_st->st_dev == from_st->st_dev - && to_st->st_ino == from_st->st_ino) - { - ec = std::make_error_code(std::errc::file_exists); - return false; - } - - if (is_set(option, opts::skip_existing)) - { - ec.clear(); - return false; - } - else if (is_set(option, opts::update_existing)) - { - const auto from_mtime = file_time(*from_st, ec); - if (ec) - return false; - if ((from_mtime <= file_time(*to_st, ec)) || ec) - return false; - } - else if (!is_set(option, opts::overwrite_existing)) - { - ec = std::make_error_code(std::errc::file_exists); - return false; - } - else if (!is_regular_file(t)) - { - ec = std::make_error_code(std::errc::not_supported); - return false; - } - } - - struct CloseFD { - ~CloseFD() { if (fd != -1) ::close(fd); } - bool close() { return ::close(std::exchange(fd, -1)) == 0; } - int fd; - }; - - CloseFD in = { ::open(from.c_str(), O_RDONLY) }; - if (in.fd == -1) - { - ec.assign(errno, std::generic_category()); - return false; - } - int oflag = O_WRONLY|O_CREAT; - if (is_set(option, opts::overwrite_existing|opts::update_existing)) - oflag |= O_TRUNC; - else - oflag |= O_EXCL; - CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) }; - if (out.fd == -1) - { - if (errno == EEXIST && is_set(option, opts::skip_existing)) - ec.clear(); - else - ec.assign(errno, std::generic_category()); - return false; - } - -#ifdef _GLIBCXX_USE_FCHMOD - if (::fchmod(out.fd, from_st->st_mode)) -#elif defined _GLIBCXX_USE_FCHMODAT - if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0)) -#else - if (::chmod(to.c_str(), from_st->st_mode)) -#endif - { - ec.assign(errno, std::generic_category()); - return false; - } - -#ifdef _GLIBCXX_USE_SENDFILE - off_t offset = 0; - const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size); - if (n < 0 && (errno == ENOSYS || errno == EINVAL)) - { -#endif - __gnu_cxx::stdio_filebuf sbin(in.fd, std::ios::in); - __gnu_cxx::stdio_filebuf sbout(out.fd, std::ios::out); - if (sbin.is_open()) - in.fd = -1; - if (sbout.is_open()) - out.fd = -1; - if (from_st->st_size && !(std::ostream(&sbout) << &sbin)) - { - ec = std::make_error_code(std::errc::io_error); - return false; - } - if (!sbout.close() || !sbin.close()) - { - ec.assign(errno, std::generic_category()); - return false; - } - - ec.clear(); - return true; - -#ifdef _GLIBCXX_USE_SENDFILE - } - if (n != from_st->st_size) - { - ec.assign(errno, std::generic_category()); - return false; - } - if (!out.close() || !in.close()) - { - ec.assign(errno, std::generic_category()); - return false; - } - - ec.clear(); - return true; -#endif - } -} -#endif + using std::filesystem::is_not_found_errno; + using std::filesystem::file_time; + using std::filesystem::do_copy_file; +#endif // _GLIBCXX_HAVE_SYS_STAT_H +} // namespace void fs::copy(const path& from, const path& to, copy_options options, @@ -561,11 +321,13 @@ fs::copy(const path& from, const path& to, copy_options options, else if (is_set(options, copy_options::create_hard_links)) create_hard_link(from, to, ec); else if (is_directory(t)) - do_copy_file(from, to / from.filename(), options, &from_st, 0, ec); + do_copy_file(from.c_str(), (to / from.filename()).c_str(), + copy_file_options(options), &from_st, nullptr, ec); else { auto ptr = exists(t) ? &to_st : &from_st; - do_copy_file(from, to, options, &from_st, ptr, ec); + do_copy_file(from.c_str(), to.c_str(), copy_file_options(options), + &from_st, ptr, ec); } } // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -602,11 +364,12 @@ fs::copy_file(const path& from, const path& to, copy_options option) } bool -fs::copy_file(const path& from, const path& to, copy_options option, +fs::copy_file(const path& from, const path& to, copy_options options, error_code& ec) noexcept { #ifdef _GLIBCXX_HAVE_SYS_STAT_H - return do_copy_file(from, to, option, nullptr, nullptr, ec); + return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options), + nullptr, nullptr, ec); #else ec = std::make_error_code(std::errc::not_supported); return false; diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc index c66d52bf4b0..a5196674883 100644 --- a/libstdc++-v3/src/filesystem/path.cc +++ b/libstdc++-v3/src/filesystem/path.cc @@ -1,4 +1,4 @@ -// Class filesystem::path -*- C++ -*- +// Class experimental::filesystem::path -*- C++ -*- // Copyright (C) 2014-2017 Free Software Foundation, Inc. // @@ -28,9 +28,10 @@ #include -using std::experimental::filesystem::path; +namespace fs = std::experimental::filesystem; +using fs::path; -std::experimental::filesystem::filesystem_error::~filesystem_error() = default; +fs::filesystem_error::~filesystem_error() = default; constexpr path::value_type path::preferred_separator; @@ -461,7 +462,7 @@ path::_S_convert_loc(const char* __first, const char* __last, } std::size_t -std::experimental::filesystem::hash_value(const path& p) noexcept +fs::hash_value(const path& p) noexcept { // [path.non-member] // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)." @@ -477,3 +478,29 @@ std::experimental::filesystem::hash_value(const path& p) noexcept } return seed; } + +namespace std +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace filesystem +{ + extern string + fs_err_concat(const string& __what, const string& __path1, + const string& __path2); +} // namespace filesystem + +namespace experimental::filesystem::v1 { +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + + std::string filesystem_error::_M_gen_what() + { + using std::filesystem::fs_err_concat; + return fs_err_concat(system_error::what(), _M_path1.native(), + _M_path2.native()); + } + +_GLIBCXX_END_NAMESPACE_CXX11 +} // namespace experimental::filesystem::v1 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc new file mode 100644 index 00000000000..8e45890b68e --- /dev/null +++ b/libstdc++-v3/src/filesystem/std-dir.cc @@ -0,0 +1,318 @@ +// Class filesystem::directory_entry etc. -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 1 +#endif + +#include +#include +#include +#include +#include +#include +#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem { +#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } +#include "dir-common.h" + +namespace fs = std::filesystem; + +struct fs::_Dir : _Dir_base +{ + _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec) + : _Dir_base(p.c_str(), skip_permission_denied, ec) + { + if (!ec) + path = p; + } + + _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } + + _Dir(_Dir&&) = default; + + // Returns false when the end of the directory entries is reached. + // Reports errors by setting ec. + bool advance(bool skip_permission_denied, error_code& ec) noexcept + { + if (const auto entp = _Dir_base::advance(skip_permission_denied, ec)) + { + entry = fs::directory_entry{path / entp->d_name, get_file_type(*entp)}; + return true; + } + else if (!ec) + { + // reached the end + entry = {}; + } + return false; + } + + bool advance(error_code& ec) noexcept { return advance(false, ec); } + + // Returns false when the end of the directory entries is reached. + // Reports errors by throwing. + bool advance(bool skip_permission_denied = false) + { + error_code ec; + const bool ok = advance(skip_permission_denied, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "directory iterator cannot advance", ec)); + return ok; + } + + bool should_recurse(bool follow_symlink, error_code& ec) const + { + file_type type = entry._M_type; + if (type == file_type::none || type == file_type::unknown) + { + type = entry.symlink_status(ec).type(); + if (ec) + return false; + } + + if (type == file_type::directory) + return true; + if (type == file_type::symlink) + return follow_symlink && is_directory(entry.status(ec)); + return false; + } + + fs::path path; + directory_entry entry; +}; + +namespace +{ + template + inline bool + is_set(Bitmask obj, Bitmask bits) + { + return (obj & bits) != Bitmask::none; + } +} + +fs::directory_iterator:: +directory_iterator(const path& p, directory_options options, error_code* ecptr) +{ + const bool skip_permission_denied + = is_set(options, directory_options::skip_permission_denied); + + error_code ec; + _Dir dir(p, skip_permission_denied, ec); + + if (dir.dirp) + { + auto sp = std::make_shared(std::move(dir)); + if (sp->advance(skip_permission_denied, ec)) + _M_dir.swap(sp); + } + if (ecptr) + *ecptr = ec; + else if (ec) + _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error( + "directory iterator cannot open directory", p, ec)); +} + +const fs::directory_entry& +fs::directory_iterator::operator*() const +{ + if (!_M_dir) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "non-dereferenceable directory iterator", + std::make_error_code(errc::invalid_argument))); + return _M_dir->entry; +} + +fs::directory_iterator& +fs::directory_iterator::operator++() +{ + if (!_M_dir) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "cannot advance non-dereferenceable directory iterator", + std::make_error_code(errc::invalid_argument))); + if (!_M_dir->advance()) + _M_dir.reset(); + return *this; +} + +fs::directory_iterator& +fs::directory_iterator::increment(error_code& ec) noexcept +{ + if (!_M_dir) + { + ec = std::make_error_code(errc::invalid_argument); + return *this; + } + if (!_M_dir->advance(ec)) + _M_dir.reset(); + return *this; +} + +struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir> +{ + void clear() { c.clear(); } +}; + +fs::recursive_directory_iterator:: +recursive_directory_iterator(const path& p, directory_options options, + error_code* ecptr) +: _M_options(options), _M_pending(true) +{ + if (DIR* dirp = ::opendir(p.c_str())) + { + if (ecptr) + ecptr->clear(); + auto sp = std::make_shared<_Dir_stack>(); + sp->push(_Dir{ dirp, p }); + if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance()) + _M_dirs.swap(sp); + } + else + { + const int err = errno; + if (err == EACCES + && is_set(options, fs::directory_options::skip_permission_denied)) + { + if (ecptr) + ecptr->clear(); + return; + } + + if (!ecptr) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "recursive directory iterator cannot open directory", p, + std::error_code(err, std::generic_category()))); + + ecptr->assign(err, std::generic_category()); + } +} + +fs::recursive_directory_iterator::~recursive_directory_iterator() = default; + +int +fs::recursive_directory_iterator::depth() const +{ + return int(_M_dirs->size()) - 1; +} + +const fs::directory_entry& +fs::recursive_directory_iterator::operator*() const +{ + return _M_dirs->top().entry; +} + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator:: +operator=(const recursive_directory_iterator& other) noexcept = default; + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator:: +operator=(recursive_directory_iterator&& other) noexcept = default; + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator::operator++() +{ + error_code ec; + increment(ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "cannot increment recursive directory iterator", ec)); + return *this; +} + +fs::recursive_directory_iterator& +fs::recursive_directory_iterator::increment(error_code& ec) noexcept +{ + if (!_M_dirs) + { + ec = std::make_error_code(errc::invalid_argument); + return *this; + } + + const bool follow + = is_set(_M_options, directory_options::follow_directory_symlink); + const bool skip_permission_denied + = is_set(_M_options, directory_options::skip_permission_denied); + + auto& top = _M_dirs->top(); + + if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec)) + { + _Dir dir(top.entry.path(), skip_permission_denied, ec); + if (ec) + { + _M_dirs.reset(); + return *this; + } + if (dir.dirp) + _M_dirs->push(std::move(dir)); + } + + while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec) + { + _M_dirs->pop(); + if (_M_dirs->empty()) + { + _M_dirs.reset(); + return *this; + } + } + return *this; +} + +void +fs::recursive_directory_iterator::pop(error_code& ec) +{ + if (!_M_dirs) + { + ec = std::make_error_code(errc::invalid_argument); + return; + } + + const bool skip_permission_denied + = is_set(_M_options, directory_options::skip_permission_denied); + + do { + _M_dirs->pop(); + if (_M_dirs->empty()) + { + _M_dirs.reset(); + ec.clear(); + return; + } + } while (!_M_dirs->top().advance(skip_permission_denied, ec)); +} + +void +fs::recursive_directory_iterator::pop() +{ + error_code ec; + pop(ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs + ? "recursive directory iterator cannot pop" + : "non-dereferenceable recursive directory iterator cannot pop", + ec)); +} diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc new file mode 100644 index 00000000000..ff7acbfc1e7 --- /dev/null +++ b/libstdc++-v3/src/filesystem/std-ops.cc @@ -0,0 +1,1513 @@ +// Filesystem operations -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // PATH_MAX +#ifdef _GLIBCXX_HAVE_FCNTL_H +# include // AT_FDCWD, AT_SYMLINK_NOFOLLOW +#endif +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +# include // stat, utimensat, fchmodat +#endif +#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H +# include // statvfs +#endif +#ifdef _GLIBCXX_USE_SENDFILE +# include // sendfile +#endif +#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H +# include // utime +#endif + +#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem { +#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } +#include "ops-common.h" + +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +# undef utime +# define utime _wutime +# undef chmod +# define chmod _wchmod +#endif + +namespace fs = std::filesystem; + +fs::path +fs::absolute(const path& p) +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + error_code ec; + path ret = absolute(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p, + std::make_error_code(errc::not_supported))); + return ret; +#else + return current_path() / p; +#endif +} + +fs::path +fs::absolute(const path& p, error_code& ec) +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + ec = std::make_error_code(errc::not_supported); + return {}; +#else + ec.clear(); + return current_path() / p; +#endif +} + +namespace +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + 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) + { + const auto& filename = path.native(); + return filename.size() == 1 && is_dot(filename[0]); + } + + inline bool is_dotdot(const fs::path& path) + { + const auto& filename = path.native(); + return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]); + } + + struct free_as_in_malloc + { + void operator()(void* p) const { ::free(p); } + }; + + using char_ptr = std::unique_ptr; +} + +fs::path +fs::canonical(const path& p, error_code& ec) +{ + path result; + const path pa = absolute(p, ec); + if (ec) + return result; + +#ifdef _GLIBCXX_USE_REALPATH + char_ptr buf{ nullptr }; +# if _XOPEN_VERSION < 700 + // Not safe to call realpath(path, NULL) + buf.reset( (char*)::malloc(PATH_MAX) ); +# endif + if (char* rp = ::realpath(pa.c_str(), buf.get())) + { + if (buf == nullptr) + buf.reset(rp); + result.assign(rp); + ec.clear(); + return result; + } + if (errno != ENAMETOOLONG) + { + ec.assign(errno, std::generic_category()); + return result; + } +#endif + + if (!exists(pa, ec)) + { + if (!ec) + ec = make_error_code(std::errc::no_such_file_or_directory); + return result; + } + // else: we know there are (currently) no unresolvable symlink loops + + result = pa.root_path(); + + deque cmpts; + for (auto& f : pa.relative_path()) + cmpts.push_back(f); + + int max_allowed_symlinks = 40; + + while (!cmpts.empty() && !ec) + { + path f = std::move(cmpts.front()); + cmpts.pop_front(); + + if (f.empty()) + { + // ignore empty element + } + else if (is_dot(f)) + { + if (!is_directory(result, ec) && !ec) + ec.assign(ENOTDIR, std::generic_category()); + } + else if (is_dotdot(f)) + { + auto parent = result.parent_path(); + if (parent.empty()) + result = pa.root_path(); + else + result.swap(parent); + } + else + { + result /= f; + + if (is_symlink(result, ec)) + { + path link = read_symlink(result, ec); + if (!ec) + { + if (--max_allowed_symlinks == 0) + ec.assign(ELOOP, std::generic_category()); + else + { + if (link.is_absolute()) + { + result = link.root_path(); + link = link.relative_path(); + } + else + result = result.parent_path(); + + cmpts.insert(cmpts.begin(), link.begin(), link.end()); + } + } + } + } + } + + if (ec || !exists(result, ec)) + result.clear(); + + return result; +} + +fs::path +fs::canonical(const path& p) +{ + error_code ec; + path res = canonical(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path", + p, ec)); + return res; +} + +void +fs::copy(const path& from, const path& to, copy_options options) +{ + error_code ec; + copy(from, to, options, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec)); +} + +namespace std::filesystem +{ + // Need this as there's no 'perm_options::none' enumerator. + inline bool is_set(fs::perm_options obj, fs::perm_options bits) + { + return (obj & bits) != fs::perm_options{}; + } +} + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +bool +fs::do_copy_file(const char* from, const char* to, + copy_options_existing_file options, + stat_type* from_st, stat_type* to_st, + std::error_code& ec) noexcept +{ + stat_type st1, st2; + fs::file_status t, f; + + if (to_st == nullptr) + { + if (::stat(to, &st1)) + { + const int err = errno; + if (!is_not_found_errno(err)) + { + ec.assign(err, std::generic_category()); + return false; + } + } + else + to_st = &st1; + } + else if (to_st == from_st) + to_st = nullptr; + + if (to_st == nullptr) + t = fs::file_status{fs::file_type::not_found}; + else + t = make_file_status(*to_st); + + if (from_st == nullptr) + { + if (::stat(from, &st2)) + { + ec.assign(errno, std::generic_category()); + return false; + } + else + from_st = &st2; + } + f = make_file_status(*from_st); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2712. copy_file() has a number of unspecified error conditions + if (!is_regular_file(f)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } + + if (exists(t)) + { + if (!is_regular_file(t)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } + + if (to_st->st_dev == from_st->st_dev + && to_st->st_ino == from_st->st_ino) + { + ec = std::make_error_code(std::errc::file_exists); + return false; + } + + if (options.skip) + { + ec.clear(); + return false; + } + else if (options.update) + { + const auto from_mtime = file_time(*from_st, ec); + if (ec) + return false; + if ((from_mtime <= file_time(*to_st, ec)) || ec) + return false; + } + else if (!options.overwrite) + { + ec = std::make_error_code(std::errc::file_exists); + return false; + } + else if (!is_regular_file(t)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } + } + + struct CloseFD { + ~CloseFD() { if (fd != -1) ::close(fd); } + bool close() { return ::close(std::exchange(fd, -1)) == 0; } + int fd; + }; + + CloseFD in = { ::open(from, O_RDONLY) }; + if (in.fd == -1) + { + ec.assign(errno, std::generic_category()); + return false; + } + int oflag = O_WRONLY|O_CREAT; + if (options.overwrite || options.update) + oflag |= O_TRUNC; + else + oflag |= O_EXCL; + CloseFD out = { ::open(to, oflag, S_IWUSR) }; + if (out.fd == -1) + { + if (errno == EEXIST && options.skip) + ec.clear(); + else + ec.assign(errno, std::generic_category()); + return false; + } + +#ifdef _GLIBCXX_USE_FCHMOD + if (::fchmod(out.fd, from_st->st_mode)) +#elif defined _GLIBCXX_USE_FCHMODAT + if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0)) +#else + if (::chmod(to, from_st->st_mode)) +#endif + { + ec.assign(errno, std::generic_category()); + return false; + } + +#ifdef _GLIBCXX_USE_SENDFILE + off_t offset = 0; + const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size); + if (n < 0 && (errno == ENOSYS || errno == EINVAL)) + { +#endif // _GLIBCXX_USE_SENDFILE + __gnu_cxx::stdio_filebuf sbin(in.fd, std::ios::in); + __gnu_cxx::stdio_filebuf sbout(out.fd, std::ios::out); + if (sbin.is_open()) + in.fd = -1; + if (sbout.is_open()) + out.fd = -1; + if (from_st->st_size && !(std::ostream(&sbout) << &sbin)) + { + ec = std::make_error_code(std::errc::io_error); + return false; + } + if (!sbout.close() || !sbin.close()) + { + ec.assign(errno, std::generic_category()); + return false; + } + + ec.clear(); + return true; + +#ifdef _GLIBCXX_USE_SENDFILE + } + if (n != from_st->st_size) + { + ec.assign(errno, std::generic_category()); + return false; + } + if (!out.close() || !in.close()) + { + ec.assign(errno, std::generic_category()); + return false; + } + + ec.clear(); + return true; +#endif // _GLIBCXX_USE_SENDFILE +} +#endif // _GLIBCXX_HAVE_SYS_STAT_H + +void +fs::copy(const path& from, const path& to, copy_options options, + error_code& ec) noexcept +{ + const bool skip_symlinks = is_set(options, copy_options::skip_symlinks); + const bool create_symlinks = is_set(options, copy_options::create_symlinks); + const bool copy_symlinks = is_set(options, copy_options::copy_symlinks); + const bool use_lstat = create_symlinks || skip_symlinks; + + file_status f, t; + stat_type from_st, to_st; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2681. filesystem::copy() cannot copy symlinks + if (use_lstat || copy_symlinks + ? ::lstat(from.c_str(), &from_st) + : ::stat(from.c_str(), &from_st)) + { + ec.assign(errno, std::generic_category()); + return; + } + if (use_lstat + ? ::lstat(to.c_str(), &to_st) + : ::stat(to.c_str(), &to_st)) + { + if (!is_not_found_errno(errno)) + { + ec.assign(errno, std::generic_category()); + return; + } + t = file_status{file_type::not_found}; + } + else + t = make_file_status(to_st); + f = make_file_status(from_st); + + if (exists(t) && !is_other(t) && !is_other(f) + && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino) + { + ec = std::make_error_code(std::errc::file_exists); + return; + } + if (is_other(f) || is_other(t)) + { + ec = std::make_error_code(std::errc::not_supported); + return; + } + if (is_directory(f) && is_regular_file(t)) + { + ec = std::make_error_code(std::errc::is_a_directory); + return; + } + + if (is_symlink(f)) + { + if (skip_symlinks) + ec.clear(); + else if (!exists(t) && copy_symlinks) + copy_symlink(from, to, ec); + else + // Not clear what should be done here. + // "Otherwise report an error as specified in Error reporting (7)." + ec = std::make_error_code(std::errc::invalid_argument); + } + else if (is_regular_file(f)) + { + if (is_set(options, copy_options::directories_only)) + ec.clear(); + else if (create_symlinks) + create_symlink(from, to, ec); + else if (is_set(options, copy_options::create_hard_links)) + create_hard_link(from, to, ec); + else if (is_directory(t)) + do_copy_file(from.c_str(), (to / from.filename()).c_str(), + copy_file_options(options), &from_st, nullptr, ec); + else + { + auto ptr = exists(t) ? &to_st : &from_st; + do_copy_file(from.c_str(), to.c_str(), copy_file_options(options), + &from_st, ptr, ec); + } + } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2682. filesystem::copy() won't create a symlink to a directory + else if (is_directory(f) && create_symlinks) + ec = std::make_error_code(errc::is_a_directory); + else if (is_directory(f) && (is_set(options, copy_options::recursive) + || options == copy_options::none)) + { + if (!exists(t)) + if (!create_directory(to, from, ec)) + return; + // set an unused bit in options to disable further recursion + if (!is_set(options, copy_options::recursive)) + options |= static_cast(4096); + for (const directory_entry& x : directory_iterator(from)) + copy(x.path(), to/x.path().filename(), options, ec); + } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2683. filesystem::copy() says "no effects" + else + ec.clear(); +} + +bool +fs::copy_file(const path& from, const path& to, copy_options option) +{ + error_code ec; + bool result = copy_file(from, to, option, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to, + ec)); + return result; +} + +bool +fs::copy_file(const path& from, const path& to, copy_options options, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options), + nullptr, nullptr, ec); +#else + ec = std::make_error_code(std::errc::not_supported); + return false; +#endif +} + + +void +fs::copy_symlink(const path& existing_symlink, const path& new_symlink) +{ + error_code ec; + copy_symlink(existing_symlink, new_symlink, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink", + existing_symlink, new_symlink, ec)); +} + +void +fs::copy_symlink(const path& existing_symlink, const path& new_symlink, + error_code& ec) noexcept +{ + auto p = read_symlink(existing_symlink, ec); + if (ec) + return; +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + if (is_directory(p)) + { + create_directory_symlink(p, new_symlink, ec); + return; + } +#endif + create_symlink(p, new_symlink, ec); +} + + +bool +fs::create_directories(const path& p) +{ + error_code ec; + bool result = create_directories(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p, + ec)); + return result; +} + +bool +fs::create_directories(const path& p, error_code& ec) noexcept +{ + if (p.empty()) + { + ec = std::make_error_code(errc::invalid_argument); + return false; + } + std::stack missing; + path pp = p; + + while (pp.has_filename() && status(pp, ec).type() == file_type::not_found) + { + ec.clear(); + const auto& filename = pp.filename(); + if (!is_dot(filename) && !is_dotdot(filename)) + missing.push(pp); + pp = pp.parent_path(); + + if (missing.size() > 1000) // sanity check + { + ec = std::make_error_code(std::errc::filename_too_long); + return false; + } + } + + if (ec || missing.empty()) + return false; + + do + { + const path& top = missing.top(); + create_directory(top, ec); + if (ec && is_directory(top)) + ec.clear(); + missing.pop(); + } + while (!missing.empty() && !ec); + + return missing.empty(); +} + +namespace +{ + bool + create_dir(const fs::path& p, fs::perms perm, std::error_code& ec) + { + bool created = false; +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + ::mode_t mode = static_cast>(perm); + if (::mkdir(p.c_str(), mode)) + { + const int err = errno; + if (err != EEXIST || !is_directory(p)) + ec.assign(err, std::generic_category()); + else + ec.clear(); + } + else + { + ec.clear(); + created = true; + } +#else + ec = std::make_error_code(std::errc::not_supported); +#endif + return created; + } +} // namespace + +bool +fs::create_directory(const path& p) +{ + error_code ec; + bool result = create_directory(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, + ec)); + return result; +} + +bool +fs::create_directory(const path& p, error_code& ec) noexcept +{ + return create_dir(p, perms::all, ec); +} + + +bool +fs::create_directory(const path& p, const path& attributes) +{ + error_code ec; + bool result = create_directory(p, attributes, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p, + ec)); + return result; +} + +bool +fs::create_directory(const path& p, const path& attributes, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + stat_type st; + if (::stat(attributes.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return false; + } + return create_dir(p, static_cast(st.st_mode), ec); +#else + ec = std::make_error_code(std::errc::not_supported); + return false; +#endif +} + + +void +fs::create_directory_symlink(const path& to, const path& new_symlink) +{ + error_code ec; + create_directory_symlink(to, new_symlink, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink", + to, new_symlink, ec)); +} + +void +fs::create_directory_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + ec = std::make_error_code(std::errc::not_supported); +#else + create_symlink(to, new_symlink, ec); +#endif +} + + +void +fs::create_hard_link(const path& to, const path& new_hard_link) +{ + error_code ec; + create_hard_link(to, new_hard_link, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link", + to, new_hard_link, ec)); +} + +void +fs::create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (::link(to.c_str(), new_hard_link.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + +void +fs::create_symlink(const path& to, const path& new_symlink) +{ + error_code ec; + create_symlink(to, new_symlink, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink", + to, new_symlink, ec)); +} + +void +fs::create_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (::symlink(to.c_str(), new_symlink.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + + +fs::path +fs::current_path() +{ + error_code ec; + path p = current_path(ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec)); + return p; +} + +fs::path +fs::current_path(error_code& ec) +{ + path p; +#ifdef _GLIBCXX_HAVE_UNISTD_H +#ifdef __GLIBC__ + if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) + { + p.assign(cwd.get()); + ec.clear(); + } + else + ec.assign(errno, std::generic_category()); +#else + long path_max = pathconf(".", _PC_PATH_MAX); + size_t size; + if (path_max == -1) + size = 1024; + else if (path_max > 10240) + size = 10240; + else + size = path_max; + for (char_ptr buf; p.empty(); size *= 2) + { + buf.reset((char*)malloc(size)); + if (buf) + { + if (getcwd(buf.get(), size)) + { + p.assign(buf.get()); + ec.clear(); + } + else if (errno != ERANGE) + { + ec.assign(errno, std::generic_category()); + return {}; + } + } + else + { + ec = std::make_error_code(std::errc::not_enough_memory); + return {}; + } + } +#endif // __GLIBC__ +#else // _GLIBCXX_HAVE_UNISTD_H + ec = std::make_error_code(std::errc::not_supported); +#endif + return p; +} + +void +fs::current_path(const path& p) +{ + error_code ec; + current_path(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec)); +} + +void +fs::current_path(const path& p, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (::chdir(p.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + +bool +fs::equivalent(const path& p1, const path& p2) +{ + error_code ec; + auto result = equivalent(p1, p2, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence", + p1, p2, ec)); + return result; +} + +bool +fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + int err = 0; + file_status s1, s2; + stat_type st1, st2; + if (::stat(p1.c_str(), &st1) == 0) + s1 = make_file_status(st1); + else if (is_not_found_errno(errno)) + s1.type(file_type::not_found); + else + err = errno; + + if (::stat(p2.c_str(), &st2) == 0) + s2 = make_file_status(st2); + else if (is_not_found_errno(errno)) + s2.type(file_type::not_found); + else + err = errno; + + if (exists(s1) && exists(s2)) + { + if (is_other(s1) && is_other(s2)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } + ec.clear(); + if (is_other(s1) || is_other(s2)) + return false; + return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; + } + else if (!exists(s1) && !exists(s2)) + ec = std::make_error_code(std::errc::no_such_file_or_directory); + else if (err) + ec.assign(err, std::generic_category()); + else + ec.clear(); + return false; +#else + ec = std::make_error_code(std::errc::not_supported); +#endif + return false; +} + +std::uintmax_t +fs::file_size(const path& p) +{ + error_code ec; + auto sz = file_size(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec)); + return sz; +} + +namespace +{ + template + inline T + do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt) + { +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + fs::stat_type st; + if (::stat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return deflt; + } + ec.clear(); + return f(st); +#else + ec = std::make_error_code(std::errc::not_supported); + return deflt; +#endif + } +} + +std::uintmax_t +fs::file_size(const path& p, error_code& ec) noexcept +{ + struct S + { + S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { } + S() : type(file_type::not_found) { } + file_type type; + size_t size; + }; + auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{}); + if (s.type == file_type::regular) + return s.size; + if (!ec) + { + if (s.type == file_type::directory) + ec = std::make_error_code(std::errc::is_a_directory); + else + ec = std::make_error_code(std::errc::not_supported); + } + return -1; +} + +std::uintmax_t +fs::hard_link_count(const path& p) +{ + error_code ec; + auto count = hard_link_count(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec)); + return count; +} + +std::uintmax_t +fs::hard_link_count(const path& p, error_code& ec) noexcept +{ + return do_stat(p, ec, std::mem_fn(&stat::st_nlink), + static_cast(-1)); +} + +bool +fs::is_empty(const path& p) +{ + error_code ec; + bool e = is_empty(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty", + p, ec)); + return e; +} + +bool +fs::is_empty(const path& p, error_code& ec) noexcept +{ + auto s = status(p, ec); + if (ec) + return false; + bool empty = fs::is_directory(s) + ? fs::directory_iterator(p, ec) == fs::directory_iterator() + : fs::file_size(p, ec) == 0; + return ec ? false : empty; +} + +fs::file_time_type +fs::last_write_time(const path& p) +{ + error_code ec; + auto t = last_write_time(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec)); + return t; +} + +fs::file_time_type +fs::last_write_time(const path& p, error_code& ec) noexcept +{ + return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); }, + file_time_type::min()); +} + +void +fs::last_write_time(const path& p, file_time_type new_time) +{ + error_code ec; + last_write_time(p, new_time, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec)); +} + +void +fs::last_write_time(const path& p __attribute__((__unused__)), + file_time_type new_time, error_code& ec) noexcept +{ + auto d = new_time.time_since_epoch(); + auto s = chrono::duration_cast(d); +#if _GLIBCXX_USE_UTIMENSAT + auto ns = chrono::duration_cast(d - s); + if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9. + { + --s; + ns += chrono::seconds(1); + } + struct ::timespec ts[2]; + ts[0].tv_sec = 0; + ts[0].tv_nsec = UTIME_OMIT; + ts[1].tv_sec = static_cast(s.count()); + ts[1].tv_nsec = static_cast(ns.count()); + if (::utimensat(AT_FDCWD, p.c_str(), ts, 0)) + 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, [](const auto& st) { return st.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 +} + +void +fs::permissions(const path& p, perms prms, perm_options opts) +{ + error_code ec; + permissions(p, prms, opts, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec)); +} + +void +fs::permissions(const path& p, perms prms, perm_options opts, + error_code& ec) noexcept +{ + const bool replace = is_set(opts, perm_options::replace); + const bool add = is_set(opts, perm_options::add); + const bool remove = is_set(opts, perm_options::remove); + const bool nofollow = is_set(opts, perm_options::nofollow); + if (((int)replace + (int)add + (int)remove) != 1) + { + ec = std::make_error_code(std::errc::invalid_argument); + return; + } + + prms &= perms::mask; + + file_status st; + if (add || remove || nofollow) + { + st = nofollow ? symlink_status(p, ec) : status(p, ec); + if (ec) + return; + auto curr = st.permissions(); + if (add) + prms |= curr; + else if (remove) + prms = curr & ~prms; + } + + int err = 0; +#if _GLIBCXX_USE_FCHMODAT + const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0; + if (::fchmodat(AT_FDCWD, p.c_str(), static_cast(prms), flag)) + err = errno; +#else + if (nofollow && is_symlink(st)) + ec = std::make_error_code(std::errc::operation_not_supported); + else if (::chmod(p.c_str(), static_cast(prms))) + err = errno; +#endif + + if (err) + ec.assign(err, std::generic_category()); + else + ec.clear(); +} + +fs::path +fs::proximate(const path& p, const path& base) +{ + return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); +} + +fs::path +fs::proximate(const path& p, const path& base, error_code& ec) +{ + path result; + const auto p2 = weakly_canonical(p, ec); + if (!ec) + { + const auto base2 = weakly_canonical(base, ec); + if (!ec) + result = p2.lexically_proximate(base2); + } + return result; +} + +fs::path +fs::read_symlink(const path& p) +{ + error_code ec; + path tgt = read_symlink(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec)); + return tgt; +} + +fs::path fs::read_symlink(const path& p, error_code& ec) +{ +#ifdef _GLIBCXX_HAVE_SYS_STAT_H + stat_type st; + if (::lstat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return {}; + } + std::string buf(st.st_size, '\0'); + ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); + if (len == -1) + { + ec.assign(errno, std::generic_category()); + return {}; + } + ec.clear(); + return path{buf.data(), buf.data()+len}; +#else + ec = std::make_error_code(std::errc::not_supported); + return {}; +#endif +} + +fs::path +fs::relative(const path& p, const path& base) +{ + return weakly_canonical(p).lexically_relative(weakly_canonical(base)); +} + +fs::path +fs::relative(const path& p, const path& base, error_code& ec) +{ + auto result = weakly_canonical(p, ec); + fs::path cbase; + if (!ec) + cbase = weakly_canonical(base, ec); + if (!ec) + result = result.lexically_relative(cbase); + if (ec) + result.clear(); + return result; +} + +bool +fs::remove(const path& p) +{ + error_code ec; + bool result = fs::remove(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec)); + return result; +} + +bool +fs::remove(const path& p, error_code& ec) noexcept +{ + if (exists(symlink_status(p, ec))) + { + if (::remove(p.c_str()) == 0) + { + ec.clear(); + return true; + } + else + ec.assign(errno, std::generic_category()); + } + return false; +} + + +std::uintmax_t +fs::remove_all(const path& p) +{ + error_code ec; + bool result = remove_all(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); + return result; +} + +std::uintmax_t +fs::remove_all(const path& p, error_code& ec) noexcept +{ + auto fs = symlink_status(p, ec); + uintmax_t count = 0; + if (!ec && fs.type() == file_type::directory) + for (directory_iterator d(p, ec), end; !ec && d != end; ++d) + count += fs::remove_all(d->path(), ec); + if (ec) + return -1; + return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear() +} + +void +fs::rename(const path& from, const path& to) +{ + error_code ec; + rename(from, to, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec)); +} + +void +fs::rename(const path& from, const path& to, error_code& ec) noexcept +{ + if (::rename(from.c_str(), to.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +} + +void +fs::resize_file(const path& p, uintmax_t size) +{ + error_code ec; + resize_file(p, size, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec)); +} + +void +fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept +{ +#ifdef _GLIBCXX_HAVE_UNISTD_H + if (size > static_cast(std::numeric_limits::max())) + ec.assign(EINVAL, std::generic_category()); + else if (::truncate(p.c_str(), size)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +#else + ec = std::make_error_code(std::errc::not_supported); +#endif +} + + +fs::space_info +fs::space(const path& p) +{ + error_code ec; + space_info s = space(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec)); + return s; +} + +fs::space_info +fs::space(const path& p, error_code& ec) noexcept +{ + space_info info = { + static_cast(-1), + static_cast(-1), + static_cast(-1) + }; +#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H + struct ::statvfs f; + if (::statvfs(p.c_str(), &f)) + ec.assign(errno, std::generic_category()); + else + { + info = space_info{ + f.f_blocks * f.f_frsize, + f.f_bfree * f.f_frsize, + f.f_bavail * f.f_frsize + }; + ec.clear(); + } +#else + ec = std::make_error_code(std::errc::not_supported); +#endif + return info; +} + +#ifdef _GLIBCXX_HAVE_SYS_STAT_H +fs::file_status +fs::status(const fs::path& p, error_code& ec) noexcept +{ + file_status status; + stat_type st; + if (::stat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); + if (is_not_found_errno(err)) + status.type(file_type::not_found); +#ifdef EOVERFLOW + else if (err == EOVERFLOW) + status.type(file_type::unknown); +#endif + } + else + { + status = make_file_status(st); + ec.clear(); + } + return status; +} + +fs::file_status +fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept +{ + file_status status; + stat_type st; + if (::lstat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); + if (is_not_found_errno(err)) + status.type(file_type::not_found); + } + else + { + status = make_file_status(st); + ec.clear(); + } + return status; +} +#endif + +fs::file_status +fs::status(const fs::path& p) +{ + std::error_code ec; + auto result = status(p, ec); + if (result.type() == file_type::none) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec)); + return result; +} + +fs::file_status +fs::symlink_status(const fs::path& p) +{ + std::error_code ec; + auto result = symlink_status(p, ec); + if (result.type() == file_type::none) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec)); + return result; +} + +fs::path fs::temp_directory_path() +{ + error_code ec; + path tmp = temp_directory_path(ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec)); + return tmp; +} + +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 = nullptr; + const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr }; + for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e) + tmpdir = ::getenv(*e); + path p = tmpdir ? tmpdir : "/tmp"; + auto st = status(p, ec); + if (!ec) + { + if (is_directory(st)) + { + ec.clear(); + return p; + } + else + ec = std::make_error_code(std::errc::not_a_directory); + } + return {}; +#endif +} + +fs::path +fs::weakly_canonical(const path& p) +{ + path result; + if (exists(status(p))) + return canonical(p); + + path tmp; + auto iter = p.begin(), end = p.end(); + // find leading elements of p that exist: + while (iter != end) + { + tmp = result / *iter; + if (exists(status(tmp))) + swap(result, tmp); + else + break; + ++iter; + } + // canonicalize: + result = canonical(result); + // append the non-existing elements: + while (iter != end) + result /= *iter++; + // normalize: + return result.lexically_normal(); +} + +fs::path +fs::weakly_canonical(const path& p, error_code& ec) +{ + path result; + file_status st = status(p, ec); + if (exists(st)) + return canonical(p, ec); + else if (status_known(st)) + ec.clear(); + else + return result; + + path tmp; + auto iter = p.begin(), end = p.end(); + // find leading elements of p that exist: + while (iter != end) + { + tmp = result / *iter; + st = status(tmp, ec); + if (exists(st)) + swap(result, tmp); + else + { + if (status_known(st)) + ec.clear(); + break; + } + ++iter; + } + // canonicalize: + if (!ec) + result = canonical(result, ec); + if (ec) + result.clear(); + else + { + // append the non-existing elements: + while (iter != end) + result /= *iter++; + // normalize: + result = result.lexically_normal(); + } + return result; +} diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc new file mode 100644 index 00000000000..b5dd36d6ad1 --- /dev/null +++ b/libstdc++-v3/src/filesystem/std-path.cc @@ -0,0 +1,688 @@ +// Class filesystem::path -*- C++ -*- + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 1 +#endif + +#include +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +# include +#endif + +namespace fs = std::filesystem; +using fs::path; + +fs::filesystem_error::~filesystem_error() = default; + +constexpr path::value_type path::preferred_separator; + +path& +path::remove_filename() +{ + if (_M_type == _Type::_Multi) + { + if (!_M_cmpts.empty()) + { + auto cmpt = std::prev(_M_cmpts.end()); + if (cmpt->_M_type == _Type::_Filename && !cmpt->empty()) + { + _M_pathname.erase(cmpt->_M_pos); + auto prev = std::prev(cmpt); + if (prev->_M_type == _Type::_Root_dir + || prev->_M_type == _Type::_Root_name) + { + _M_cmpts.erase(cmpt); + _M_trim(); + } + else + cmpt->clear(); + } + } + } + else if (_M_type == _Type::_Filename) + clear(); + if (!empty() && _M_pathname.back() != '/') + throw 1; + return *this; +} + +path& +path::replace_filename(const path& replacement) +{ + remove_filename(); + operator/=(replacement); + return *this; +} + +path& +path::replace_extension(const path& replacement) +{ + auto ext = _M_find_extension(); + // Any existing extension() is removed + if (ext.first && ext.second != string_type::npos) + { + if (ext.first == &_M_pathname) + _M_pathname.erase(ext.second); + else + { + const auto& back = _M_cmpts.back(); + if (ext.first != &back._M_pathname) + _GLIBCXX_THROW_OR_ABORT( + std::logic_error("path::replace_extension failed")); + _M_pathname.erase(back._M_pos + ext.second); + } + } + // If replacement is not empty and does not begin with a dot character, + // a dot character is appended + if (!replacement.empty() && replacement.native()[0] != '.') + _M_pathname += '.'; + operator+=(replacement); + return *this; +} + +namespace +{ + template + int do_compare(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) + { + int cmpt = 1; + while (begin1 != end1 && begin2 != end2) + { + if (begin1->native() < begin2->native()) + return -cmpt; + if (begin1->native() > begin2->native()) + return +cmpt; + ++begin1; + ++begin2; + ++cmpt; + } + if (begin1 == end1) + { + if (begin2 == end2) + return 0; + return -cmpt; + } + return +cmpt; + } +} + +int +path::compare(const path& p) const noexcept +{ + struct CmptRef + { + const path* ptr; + const string_type& native() const noexcept { return ptr->native(); } + }; + + if (empty() && p.empty()) + return 0; + else 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()); + else if (_M_type == _Type::_Multi) + { + CmptRef c[1] = { { &p } }; + return do_compare(_M_cmpts.begin(), _M_cmpts.end(), c, c+1); + } + else if (p._M_type == _Type::_Multi) + { + CmptRef c[1] = { { this } }; + return do_compare(c, c+1, p._M_cmpts.begin(), p._M_cmpts.end()); + } + else + return _M_pathname.compare(p._M_pathname); +} + +path +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) + __ret = *_M_cmpts.begin(); + return __ret; +} + +path +path::root_directory() const +{ + path __ret; + if (_M_type == _Type::_Root_dir) + { + __ret._M_type = _Type::_Root_dir; + __ret._M_pathname.assign(1, preferred_separator); + } + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + __ret = *__it; + } + return __ret; +} + +path +path::root_path() const +{ + path __ret; + if (_M_type == _Type::_Root_name) + __ret = *this; + else if (_M_type == _Type::_Root_dir) + { + __ret._M_pathname.assign(1, preferred_separator); + __ret._M_type = _Type::_Root_dir; + } + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + { + __ret = *__it++; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + __ret /= *__it; + } + else if (__it->_M_type == _Type::_Root_dir) + __ret = *__it; + } + return __ret; +} + +path +path::relative_path() const +{ + path __ret; + if (_M_type == _Type::_Filename) + __ret = *this; + else if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + ++__it; + if (__it != _M_cmpts.end()) + __ret.assign(_M_pathname.substr(__it->_M_pos)); + } + return __ret; +} + +path +path::parent_path() const +{ + path __ret; + if (!has_relative_path()) + __ret = *this; + else if (_M_cmpts.size() >= 2) + { + for (auto __it = _M_cmpts.begin(), __end = std::prev(_M_cmpts.end()); + __it != __end; ++__it) + { + __ret /= *__it; + } + } + return __ret; +} + +bool +path::has_root_name() const +{ + if (_M_type == _Type::_Root_name) + return true; + if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type == _Type::_Root_name) + return true; + return false; +} + +bool +path::has_root_directory() const +{ + if (_M_type == _Type::_Root_dir) + return true; + if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + return true; + } + return false; +} + +bool +path::has_root_path() const +{ + if (_M_type == _Type::_Root_name || _M_type == _Type::_Root_dir) + return true; + if (!_M_cmpts.empty()) + { + auto __type = _M_cmpts.front()._M_type; + if (__type == _Type::_Root_name || __type == _Type::_Root_dir) + return true; + } + return false; +} + +bool +path::has_relative_path() const +{ + if (_M_type == _Type::_Filename) + return true; + if (!_M_cmpts.empty()) + { + auto __it = _M_cmpts.begin(); + if (__it->_M_type == _Type::_Root_name) + ++__it; + if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir) + ++__it; + if (__it != _M_cmpts.end()) + return true; + } + return false; +} + + +bool +path::has_parent_path() const +{ + if (!has_relative_path()) + return !empty(); + return _M_cmpts.size() >= 2; +} + +bool +path::has_filename() const +{ + if (empty()) + return false; + if (_M_type == _Type::_Filename) + return !_M_pathname.empty(); + if (_M_type == _Type::_Multi) + { + if (_M_pathname.back() == preferred_separator) + return false; + return _M_cmpts.back().has_filename(); + } + return false; +} + +namespace +{ +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + 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) + { + const auto& filename = path.native(); + return filename.size() == 1 && is_dot(filename[0]); + } + + inline bool is_dotdot(const fs::path& path) + { + const auto& filename = path.native(); + return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]); + } +} // namespace + +path +path::lexically_normal() const +{ + /* + C++17 [fs.path.generic] p6 + - If the path is empty, stop. + - Replace each slash character in the root-name with a preferred-separator. + - Replace each directory-separator with a preferred-separator. + - Remove each dot filename and any immediately following directory-separator. + - As long as any appear, remove a non-dot-dot filename immediately followed + by a directory-separator and a dot-dot filename, along with any immediately + following directory-separator. + - If the last filename is dot-dot, remove any trailing directory-separator. + - If the path is empty, add a dot. + */ + path ret; + // If the path is empty, stop. + if (empty()) + return ret; + for (auto& p : *this) + { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + // Replace each slash character in the root-name + if (p.is_root_name()) + { + string_type s = p.native(); + std::replace(s.begin(), s.end(), L'/', L'\\'); + ret /= s; + continue; + } +#endif + if (is_dotdot(p)) + { + if (ret.has_filename() && !is_dotdot(ret.filename())) + ret.remove_filename(); + else + ret /= p; + } + else if (is_dot(p)) + ret /= path(); + else + ret /= p; + } + + if (ret._M_cmpts.size() >= 2) + { + auto back = std::prev(ret.end()); + // If the last filename is dot-dot, ... + if (back->empty() && is_dotdot(*std::prev(back))) + // ... remove any trailing directory-separator. + ret = ret.parent_path(); + } + // If the path is empty, add a dot. + else if (ret.empty()) + ret = "."; + + return ret; +} + +path +path::lexically_relative(const path& base) const +{ + path ret; + if (root_name() != base.root_name()) + return ret; + if (is_absolute() != base.is_absolute()) + return ret; + if (!has_root_directory() && base.has_root_directory()) + return ret; + auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end()); + if (a == end() && b == base.end()) + ret = "."; + else + { + int n = 0; + for (; b != base.end(); ++b) + { + const path& p = *b; + if (is_dotdot(p)) + --n; + else if (!is_dot(p)) + ++n; + } + if (n >= 0) + { + const path dotdot(".."); + while (n--) + ret /= dotdot; + for (; a != end(); ++a) + ret /= *a; + } + } + return ret; +} + +path +path::lexically_proximate(const path& base) const +{ + path rel = lexically_relative(base); + if (rel.empty()) + rel = *this; + return rel; +} + +std::pair +path::_M_find_extension() const +{ + const std::string* s = nullptr; + + if (_M_type == _Type::_Filename) + s = &_M_pathname; + else if (_M_type == _Type::_Multi && !_M_cmpts.empty()) + { + const auto& c = _M_cmpts.back(); + if (c._M_type == _Type::_Filename) + s = &c._M_pathname; + } + + if (s) + { + if (auto sz = s->size()) + { + if (sz <= 2 && (*s)[0] == '.') + return { s, string_type::npos }; + const auto pos = s->rfind('.'); + return { s, pos ? pos : string_type::npos }; + } + } + return {}; +} + +void +path::_M_split_cmpts() +{ + _M_type = _Type::_Multi; + _M_cmpts.clear(); + + if (_M_pathname.empty()) + return; + + size_t pos = 0; + const size_t len = _M_pathname.size(); + + // look for root name or root directory + if (_S_is_dir_sep(_M_pathname[0])) + { +#ifdef __CYGWIN__ + // look for root name, such as "//foo" + if (len > 2 && _M_pathname[1] == _M_pathname[0]) + { + if (!_S_is_dir_sep(_M_pathname[2])) + { + // got root name, find its end + pos = 3; + while (pos < len && !_S_is_dir_sep(_M_pathname[pos])) + ++pos; + _M_add_root_name(pos); + if (pos < len) // also got root directory + _M_add_root_dir(pos); + } + else + { + // got something like "///foo" which is just a root directory + // composed of multiple redundant directory separators + _M_add_root_dir(0); + } + } + else +#endif + { + // got root directory + if (_M_pathname.find_first_not_of('/') == string_type::npos) + { + // entire path is just slashes + _M_type = _Type::_Root_dir; + return; + } + _M_add_root_dir(0); + ++pos; + } + } +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + else if (len > 1 && _M_pathname[1] == L':') + { + // got disk designator + _M_add_root_name(2); + if (len > 2 && _S_is_dir_sep(_M_pathname[2])) + _M_add_root_dir(2); + pos = 2; + } +#endif + + size_t back = pos; + while (pos < len) + { + if (_S_is_dir_sep(_M_pathname[pos])) + { + if (back != pos) + _M_add_filename(back, pos - back); + back = ++pos; + } + else + ++pos; + } + + if (back != pos) + _M_add_filename(back, pos - back); + else if (_S_is_dir_sep(_M_pathname.back())) + { + // [fs.path.itr]/4 + // An empty element, if trailing non-root directory-separator present. + if (_M_cmpts.back()._M_type == _Type::_Filename) + { + const auto& last = _M_cmpts.back(); + pos = last._M_pos + last._M_pathname.size(); + _M_cmpts.emplace_back(string_type(), _Type::_Filename, pos); + } + } + + _M_trim(); +} + +void +path::_M_add_root_name(size_t n) +{ + _M_cmpts.emplace_back(_M_pathname.substr(0, n), _Type::_Root_name, 0); +} + +void +path::_M_add_root_dir(size_t pos) +{ + _M_cmpts.emplace_back(_M_pathname.substr(pos, 1), _Type::_Root_dir, pos); +} + +void +path::_M_add_filename(size_t pos, size_t n) +{ + _M_cmpts.emplace_back(_M_pathname.substr(pos, n), _Type::_Filename, pos); +} + +void +path::_M_trim() +{ + if (_M_cmpts.size() == 1) + { + _M_type = _M_cmpts.front()._M_type; + _M_cmpts.clear(); + } +} + +path::string_type +path::_S_convert_loc(const char* __first, const char* __last, + const std::locale& __loc) +{ +#if _GLIBCXX_USE_WCHAR_T + auto& __cvt = std::use_facet>(__loc); + basic_string __ws; + if (!__str_codecvt_in(__first, __last, __ws, __cvt)) + _GLIBCXX_THROW_OR_ABORT(filesystem_error( + "Cannot convert character sequence", + std::make_error_code(errc::illegal_byte_sequence))); +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + return __ws; +#else + return _Cvt::_S_convert(__ws.data(), __ws.data() + __ws.size()); +#endif +#else + return {__first, __last}; +#endif +} + +std::size_t +fs::hash_value(const path& p) noexcept +{ + // [path.non-member] + // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)." + // Equality works as if by traversing the range [begin(), end()), meaning + // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname + // but need to iterate over individual elements. Use the hash_combine from + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf + size_t seed = 0; + for (const auto& x : p) + { + seed ^= std::hash()(x.native()) + 0x9e3779b9 + + (seed<<6) + (seed>>2); + } + return seed; +} + +namespace std +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace filesystem +{ + string + fs_err_concat(const string& __what, const string& __path1, + const string& __path2) + { + const size_t __len = 18 + __what.length() + + (__path1.length() ? __path1.length() + 3 : 0) + + (__path2.length() ? __path2.length() + 3 : 0); + string __ret; + __ret.reserve(__len); + __ret = "filesystem error: "; + __ret += __what; + if (!__path1.empty()) + { + __ret += " ["; + __ret += __path1; + __ret += ']'; + } + if (!__path2.empty()) + { + __ret += " ["; + __ret += __path2; + __ret += ']'; + } + return __ret; + } + +_GLIBCXX_BEGIN_NAMESPACE_CXX11 + + std::string filesystem_error::_M_gen_what() + { + return fs_err_concat(system_error::what(), _M_path1.native(), + _M_path2.native()); + } + +_GLIBCXX_END_NAMESPACE_CXX11 + +} // filesystem +_GLIBCXX_END_NAMESPACE_VERSION +} // std diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc new file mode 100644 index 00000000000..c3e6f01670a --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc @@ -0,0 +1,150 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + // Test non-existent path. + const auto p = __gnu_test::nonexistent_path(); + fs::directory_iterator iter(p, ec); + VERIFY( ec ); + VERIFY( iter == end(iter) ); + + // Test empty directory. + create_directory(p, fs::current_path(), ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter == end(iter) ); + + // Test non-empty directory. + ec = bad_ec; + create_directory_symlink(p, p / "l", ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter != fs::directory_iterator() ); + VERIFY( iter->path() == p/"l" ); + ++iter; + VERIFY( iter == end(iter) ); + + // Test inaccessible directory. + ec = bad_ec; + permissions(p, fs::perms::none, ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::directory_iterator(p, ec); + VERIFY( ec ); + VERIFY( iter == end(iter) ); + + // Test inaccessible directory, skipping permission denied. + const auto opts = fs::directory_options::skip_permission_denied; + ec = bad_ec; + iter = fs::directory_iterator(p, opts, ec); + VERIFY( !ec ); + VERIFY( iter == end(iter) ); + + permissions(p, fs::perms::owner_all, ec); + remove_all(p, ec); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + const auto p = __gnu_test::nonexistent_path(); + ec = bad_ec; + create_directory(p, fs::current_path(), ec); + create_directory_symlink(p, p / "l", ec); + VERIFY( !ec ); + + // Test post-increment (libstdc++/71005) + ec = bad_ec; + auto iter = fs::directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter != end(iter) ); + const auto entry1 = *iter; + const auto entry2 = *iter++; + VERIFY( entry1 == entry2 ); + VERIFY( entry1.path() == p/"l" ); + VERIFY( iter == end(iter) ); + + remove_all(p, ec); +} + +void +test03() +{ + std::error_code ec = make_error_code(std::errc::invalid_argument); + const auto p = __gnu_test::nonexistent_path(); + create_directories(p / "longer_than_small_string_buffer", ec); + VERIFY( !ec ); + + // Test for no reallocation on each dereference (this is a GNU extension) + auto iter = fs::directory_iterator(p, ec); + const auto* s1 = iter->path().c_str(); + const auto* s2 = iter->path().c_str(); + VERIFY( s1 == s2 ); + + remove_all(p, ec); +} + +void +test04() +{ + const fs::directory_iterator it; + VERIFY( it == fs::directory_iterator() ); +} + +void +test05() +{ + auto p = __gnu_test::nonexistent_path(); + create_directory(p); + create_directory_symlink(p, p / "l"); + fs::directory_iterator it(p), endit; + VERIFY( begin(it) == it ); + static_assert( noexcept(begin(it)), "begin is noexcept" ); + VERIFY( end(it) == endit ); + static_assert( noexcept(end(it)), "end is noexcept" ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc new file mode 100644 index 00000000000..02dc04f2ba9 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc @@ -0,0 +1,117 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + std::error_code ec; + fs::recursive_directory_iterator dir; + dir.pop(ec); // This is undefined, but our implementation + VERIFY( ec ); // checks and returns an error. + VERIFY( dir == end(dir) ); + + std::error_code ec2; + try + { + dir.pop(); + } + catch (const fs::filesystem_error& ex) + { + ec2 = ex.code(); + } + VERIFY( ec2 == ec ); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + const auto p = __gnu_test::nonexistent_path(); + create_directories(p / "d1/d2/d3"); + for (int i = 0; i < 3; ++i) + { + fs::recursive_directory_iterator dir(p); + VERIFY( dir != end(dir) ); + std::advance(dir, i); + VERIFY( dir != end(dir) ); + VERIFY( dir.depth() == i ); + ec = bad_ec; + dir.pop(ec); + VERIFY( !ec ); + VERIFY( dir == end(dir) ); + + dir = fs::recursive_directory_iterator(p); + std::advance(dir, i); + VERIFY( dir != end(dir) ); + VERIFY( dir.depth() == i ); + dir.pop(); + VERIFY( dir == end(dir) ); + } + remove_all(p, ec); +} + +void +test03() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + const auto p = __gnu_test::nonexistent_path(); + create_directories(p / "d1/d2/d3"); + create_directories(p / "d1/d2/e3"); + create_directories(p / "d1/e2/d3"); + for (int i = 0; i < 3; ++i) + { + fs::recursive_directory_iterator dir(p); + std::advance(dir, i); + VERIFY( dir != end(dir) ); + int expected_depth = i; + VERIFY( dir.depth() == expected_depth ); + ec = bad_ec; + dir.pop(ec); + VERIFY( !ec ); + if (dir != end(dir)) + VERIFY( dir.depth() == (expected_depth - 1) ); + + dir = fs::recursive_directory_iterator(p); + std::advance(dir, i); + VERIFY( dir != end(dir) ); + VERIFY( dir.depth() == i ); + dir.pop(); + if (dir != end(dir)) + VERIFY( dir.depth() == (i -1) ); + } + remove_all(p, ec); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc new file mode 100644 index 00000000000..1ef450fc907 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc @@ -0,0 +1,188 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + // Test non-existent path. + const auto p = __gnu_test::nonexistent_path(); + fs::recursive_directory_iterator iter(p, ec); + VERIFY( ec ); + VERIFY( iter == end(iter) ); + + // Test empty directory. + ec = bad_ec; + create_directory(p, fs::current_path(), ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::recursive_directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter == end(iter) ); + + // Test non-empty directory. + ec = bad_ec; + create_directories(p / "d1/d2", ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::recursive_directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter != end(iter) ); + VERIFY( iter->path() == p/"d1" ); + ++iter; + VERIFY( iter->path() == p/"d1/d2" ); + ++iter; + VERIFY( iter == end(iter) ); + + // Test inaccessible directory. + ec = bad_ec; + permissions(p, fs::perms::none, ec); + VERIFY( !ec ); + iter = fs::recursive_directory_iterator(p, ec); + VERIFY( ec ); + VERIFY( iter == end(iter) ); + + // Test inaccessible directory, skipping permission denied. + const auto opts = fs::directory_options::skip_permission_denied; + iter = fs::recursive_directory_iterator(p, opts, ec); + VERIFY( !ec ); + VERIFY( iter == end(iter) ); + + // Test inaccessible sub-directory. + ec = bad_ec; + permissions(p, fs::perms::owner_all, ec); + VERIFY( !ec ); + ec = bad_ec; + permissions(p/"d1/d2", fs::perms::none, ec); + VERIFY( !ec ); + ec = bad_ec; + iter = fs::recursive_directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter != end(iter) ); + VERIFY( iter->path() == p/"d1" ); + ++iter; // should recurse into d1 + VERIFY( iter->path() == p/"d1/d2" ); + iter.increment(ec); // should fail to recurse into p/d1/d2 + VERIFY( ec ); + VERIFY( iter == end(iter) ); + + // Test inaccessible sub-directory, skipping permission denied. + ec = bad_ec; + iter = fs::recursive_directory_iterator(p, opts, ec); + VERIFY( !ec ); + VERIFY( iter != end(iter) ); + VERIFY( iter->path() == p/"d1" ); + ++iter; // should recurse into d1 + VERIFY( iter->path() == p/"d1/d2" ); + ec = bad_ec; + iter.increment(ec); // should fail to recurse into p/d1/d2, so skip it + VERIFY( !ec ); + VERIFY( iter == end(iter) ); + + permissions(p/"d1/d2", fs::perms::owner_all, ec); + remove_all(p, ec); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + const auto p = __gnu_test::nonexistent_path(); + ec = bad_ec; + create_directories(p / "d1/d2", ec); + VERIFY( !ec ); + + // Test post-increment (libstdc++/71005) + ec = bad_ec; + auto iter = fs::recursive_directory_iterator(p, ec); + VERIFY( !ec ); + VERIFY( iter != end(iter) ); + const auto entry1 = *iter; + const auto entry2 = *iter++; + VERIFY( entry1 == entry2 ); + VERIFY( entry1.path() == p/"d1" ); + const auto entry3 = *iter; + const auto entry4 = *iter++; + VERIFY( entry3 == entry4 ); + VERIFY( entry3.path() == p/"d1/d2" ); + VERIFY( iter == end(iter) ); + + remove_all(p, ec); +} + +void +test03() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + const auto p = __gnu_test::nonexistent_path(); + ec = bad_ec; + create_directories(p / "longer_than_small_string_buffer", ec); + VERIFY( !ec ); + + // Test for no reallocation on each dereference (this is a GNU extension) + auto iter = fs::recursive_directory_iterator(p, ec); + const auto* s1 = iter->path().c_str(); + const auto* s2 = iter->path().c_str(); + VERIFY( s1 == s2 ); + + remove_all(p, ec); +} + +void +test04() +{ + // libstdc++/71004 + const fs::recursive_directory_iterator it; + VERIFY( it == end(it) ); +} + +void +test05() +{ + auto p = __gnu_test::nonexistent_path(); + create_directory(p); + create_directory_symlink(p, p / "l"); + fs::recursive_directory_iterator it(p), endit; + VERIFY( begin(it) == it ); + static_assert( noexcept(begin(it)), "begin is noexcept" ); + VERIFY( end(it) == endit ); + static_assert( noexcept(end(it)), "end is noexcept" ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc new file mode 100644 index 00000000000..de1cd318f96 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc @@ -0,0 +1,54 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.14.1 Absolute [fs.op.absolute] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + VERIFY( absolute(p).is_absolute() ); +} + +void +test02() +{ + path p1("/"); + VERIFY( absolute(p1) == p1 ); + path p2("/foo"); + VERIFY( absolute(p2) == p2 ); + path p3("foo"); + VERIFY( absolute(p3) != p3 ); + VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc new file mode 100644 index 00000000000..646c37c4c3c --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc @@ -0,0 +1,139 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + auto p = __gnu_test::nonexistent_path(); + canonical( p, ec ); + VERIFY( ec ); + + create_directory(p); + auto p2 = canonical( p, ec ); + VERIFY( p2 == fs::current_path()/p ); + VERIFY( !ec ); + + ec = bad_ec; + p2 = canonical( fs::current_path() / "." / (p.native() + "////././."), ec ); + VERIFY( p2 == fs::current_path()/p ); + VERIFY( !ec ); + + ec = bad_ec; + p = fs::current_path(); + p2 = canonical( p, ec ); + VERIFY( p2 == p ); + VERIFY( !ec ); + + ec = bad_ec; + p = "/"; + p = canonical( p, ec ); + VERIFY( p == "/" ); + VERIFY( !ec ); + + ec = bad_ec; + p = "/."; + p = canonical( p, ec ); + VERIFY( p == "/" ); + VERIFY( !ec ); + + ec = bad_ec; + p = "/.."; + p = canonical( p, ec ); + VERIFY( p == "/" ); + VERIFY( !ec ); + + ec = bad_ec; + p = "/../.././."; + p = canonical( p, ec ); + VERIFY( p == "/" ); + VERIFY( !ec ); +} + +void +test02() +{ + const fs::path p = __gnu_test::nonexistent_path(); + std::error_code ec, ec2; + const fs::path res = canonical(p, ec); + VERIFY( ec ); + VERIFY( res.empty() ); + +#if __cpp_exceptions + fs::path e1, e2; + try { + canonical(p); + } catch (const fs::filesystem_error& e) { + e1 = e.path1(); + e2 = e.path2(); + ec2 = e.code(); + } + VERIFY( e1 == p ); + VERIFY( e2.empty() ); + VERIFY( ec == ec2 ); +#endif +} + + +void +test03() +{ + std::error_code ec; + auto dir = __gnu_test::nonexistent_path(); + fs::create_directory(dir); + fs::path foo = dir/"foo", bar = dir/"bar"; + fs::create_directory(foo); + fs::create_directory(bar); + fs::create_symlink("../bar", foo/"baz"); + + auto dirc = canonical(dir); + auto barc = canonical(bar); + + auto p1 = fs::canonical(dir/"foo//.///..//./"); + VERIFY( p1 == dirc ); + auto p2 = fs::canonical(dir/"foo//./baz///..//./"); + VERIFY( p2 == dirc ); + auto p3 = fs::canonical(dir/"foo//./baz////./"); + VERIFY( p3 == barc ); + auto p4 = fs::canonical(dir/"foo//./baz///..//./bar"); + VERIFY( p4 == barc ); + auto p5 = fs::canonical(dir/"foo//./baz///..//./bar/"); + VERIFY( p5 == p4 ); + auto p6 = fs::canonical(dir/"foo//./baz///..//./bar/."); + VERIFY( p6 == p4 ); + + remove_all(dir); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc new file mode 100644 index 00000000000..7825a4ef5dd --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc @@ -0,0 +1,200 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 15.3 Copy [fs.op.copy] + +#include +#include +#include + +namespace fs = std::filesystem; + +// Test error conditions. +void +test01() +{ + auto p = __gnu_test::nonexistent_path(); + std::error_code ec; + + VERIFY( !fs::exists(p) ); + fs::copy(p, ".", fs::copy_options::none, ec); + VERIFY( ec ); + + ec.clear(); + fs::copy(".", ".", fs::copy_options::none, ec); + VERIFY( ec ); + + __gnu_test::scoped_file f(p); + VERIFY( fs::is_directory(".") ); + VERIFY( fs::is_regular_file(p) ); + ec.clear(); + fs::copy(".", p, fs::copy_options::none, ec); + VERIFY( ec ); + + auto to = __gnu_test::nonexistent_path(); + ec.clear(); + auto opts = fs::copy_options::create_symlinks; + fs::copy("/", to, opts, ec); + VERIFY( ec == std::make_error_code(std::errc::is_a_directory) ); + VERIFY( !exists(to) ); + + ec.clear(); + opts != fs::copy_options::recursive; + fs::copy("/", to, opts, ec); + VERIFY( ec == std::make_error_code(std::errc::is_a_directory) ); + VERIFY( !exists(to) ); +} + +// Test is_symlink(f) case. +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + auto from = __gnu_test::nonexistent_path(); + auto to = __gnu_test::nonexistent_path(); + std::error_code ec; + + ec = bad_ec; + fs::create_symlink(".", from, ec); + VERIFY( !ec ); + VERIFY( fs::exists(from) ); + + ec = bad_ec; + fs::copy(from, to, fs::copy_options::skip_symlinks, ec); + VERIFY( !ec ); + VERIFY( !fs::exists(to) ); + + ec = bad_ec; + fs::copy(from, to, fs::copy_options::skip_symlinks, ec); + VERIFY( !ec ); + VERIFY( !fs::exists(to) ); + + ec = bad_ec; + fs::copy(from, to, + fs::copy_options::skip_symlinks|fs::copy_options::copy_symlinks, + ec); + VERIFY( !ec ); + VERIFY( !fs::exists(to) ); + + ec = bad_ec; + fs::copy(from, to, fs::copy_options::copy_symlinks, ec); + VERIFY( !ec ); + VERIFY( fs::exists(to) ); + VERIFY( is_symlink(to) ); + + ec.clear(); + fs::copy(from, to, fs::copy_options::copy_symlinks, ec); + VERIFY( ec ); + + remove(from, ec); + remove(to, ec); +} + +// Test is_regular_file(f) case. +void +test03() +{ + auto from = __gnu_test::nonexistent_path(); + auto to = __gnu_test::nonexistent_path(); + + // test empty file + std::ofstream{from.native()}; + VERIFY( fs::exists(from) ); + VERIFY( fs::file_size(from) == 0 ); + fs::copy(from, to); + VERIFY( fs::exists(to) ); + VERIFY( fs::file_size(to) == 0 ); + + remove(to); + VERIFY( !fs::exists(to) ); + std::ofstream{from.native()} << "Hello, filesystem!"; + VERIFY( fs::file_size(from) != 0 ); + fs::copy(from, to); + VERIFY( fs::exists(to) ); + VERIFY( fs::file_size(to) == fs::file_size(from) ); + + remove(from); + remove(to); +} + +// Test is_directory(f) case. +void +test04() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + auto from = __gnu_test::nonexistent_path(); + auto to = __gnu_test::nonexistent_path(); + std::error_code ec; + + create_directories(from/"a/b/c"); + + { + __gnu_test::scoped_file f(to); + copy(from, to, ec); + VERIFY( ec ); + } + + __gnu_test::scoped_file f1(from/"a/f1"); + std::ofstream{f1.path} << "file one"; + __gnu_test::scoped_file f2(from/"a/b/f2"); + std::ofstream{f2.path} << "file two"; + + copy(from, to, ec); + VERIFY( !ec ); + VERIFY( exists(to) && is_empty(to) ); + remove(to); + + ec = bad_ec; + copy(from, to, fs::copy_options::recursive, ec); + VERIFY( !ec ); + VERIFY( exists(to) && !is_empty(to) ); + VERIFY( is_regular_file(to/"a/f1") && !is_empty(to/"a/f1") ); + VERIFY( file_size(from/"a/f1") == file_size(to/"a/f1") ); + VERIFY( is_regular_file(to/"a/b/f2") && !is_empty(to/"a/b/f2") ); + VERIFY( file_size(from/"a/b/f2") == file_size(to/"a/b/f2") ); + VERIFY( is_directory(to/"a/b/c") && is_empty(to/"a/b/c") ); + + f1.path.clear(); + f2.path.clear(); + remove_all(from, ec); + remove_all(to, ec); +} + +// Test no-op cases. +void +test05() +{ + auto to = __gnu_test::nonexistent_path(); + std::error_code ec = std::make_error_code(std::errc::invalid_argument); + + fs::copy("/", to, fs::copy_options::copy_symlinks, ec); + VERIFY( !ec ); // Previous value should be cleared (LWG 2683) +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc new file mode 100644 index 00000000000..69ab7fbab8d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc @@ -0,0 +1,84 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// 15.4 Copy [fs.op.copy_file] + +#include +#include +#include +#include + +void +test01() +{ + using std::filesystem::copy_options; + std::error_code ec; + + auto from = __gnu_test::nonexistent_path(); + auto to = __gnu_test::nonexistent_path(); + + // test non-existent file + bool b = copy_file(from, to, ec); + VERIFY( !b ); + VERIFY( ec ); + VERIFY( !exists(to) ); + + // test empty file + std::ofstream{from.native()}; + VERIFY( exists(from) ); + VERIFY( file_size(from) == 0 ); + + b = copy_file(from, to); + VERIFY( b ); + VERIFY( exists(to) ); + VERIFY( file_size(to) == 0 ); + remove(to); + VERIFY( !exists(to) ); + b = copy_file(from, to, copy_options::none, ec); + VERIFY( b ); + VERIFY( !ec ); + VERIFY( exists(to) ); + VERIFY( file_size(to) == 0 ); + + std::ofstream{from.native()} << "Hello, filesystem!"; + VERIFY( file_size(from) != 0 ); + remove(to); + VERIFY( !exists(to) ); + b = copy_file(from, to); + VERIFY( b ); + VERIFY( exists(to) ); + VERIFY( file_size(to) == file_size(from) ); + remove(to); + VERIFY( !exists(to) ); + b = copy_file(from, to); + VERIFY( b ); + VERIFY( exists(to) ); + VERIFY( file_size(to) == file_size(from) ); + + remove(from); + remove(to); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc new file mode 100644 index 00000000000..94596787196 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + // Test empty path. + bool b = fs::create_directories( "", ec ); + VERIFY( ec ); + VERIFY( !b ); + + // Test existing path. + ec = bad_ec; + b = fs::create_directories( fs::current_path(), ec ); + VERIFY( !ec ); + VERIFY( !b ); + + // Test non-existent path. + const auto p = __gnu_test::nonexistent_path(); + ec = bad_ec; + b = fs::create_directories( p, ec ); + VERIFY( !ec ); + VERIFY( b ); + VERIFY( is_directory(p) ); + + ec = bad_ec; + b = fs::create_directories( p/".", ec ); + VERIFY( !ec ); + VERIFY( !b ); + + ec = bad_ec; + b = fs::create_directories( p/"..", ec ); + VERIFY( !ec ); + VERIFY( !b ); + + ec = bad_ec; + b = fs::create_directories( p/"d1/d2/d3", ec ); + VERIFY( !ec ); + VERIFY( b ); + VERIFY( is_directory(p/"d1/d2/d3") ); + + ec = bad_ec; + b = fs::create_directories( p/"./d4/../d5", ec ); + VERIFY( !ec ); + VERIFY( b ); + VERIFY( is_directory(p/"./d4/../d5") ); + + std::uintmax_t count = remove_all(p, ec); + VERIFY( count == 6 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc new file mode 100644 index 00000000000..927a97c7a84 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc @@ -0,0 +1,65 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + // Test empty path. + fs::path p; + bool b = create_directory( p, ec ); + VERIFY( ec ); + VERIFY( !b ); + + // Test non-existent path + p = __gnu_test::nonexistent_path(); + VERIFY( !exists(p) ); + + ec = bad_ec; + b = create_directory(p, ec); // create the directory once + VERIFY( !ec ); + VERIFY( b ); + VERIFY( exists(p) ); + + // Test existing path (libstdc++/71036). + ec = bad_ec; + b = create_directory(p, ec); + VERIFY( !ec ); + VERIFY( !b ); + b = create_directory(p); + VERIFY( !b ); + + remove_all(p, ec); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc new file mode 100644 index 00000000000..7eff356b883 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc @@ -0,0 +1,96 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + std::error_code ec, ec2; + __gnu_test::scoped_file f; + auto tgt = f.path; + + // Test empty path. + fs::path p; + create_symlink(tgt, p, ec ); + VERIFY( ec ); + try + { + create_symlink(tgt, p); + } + catch (const std::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == tgt ); + VERIFY( ex.path2() == p ); + } + VERIFY( ec2 == ec ); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec, ec2; + __gnu_test::scoped_file f; + auto tgt = f.path; + + // Test non-existent path + auto p = __gnu_test::nonexistent_path(); + VERIFY( !exists(p) ); + + ec = bad_ec; + create_symlink(tgt, p, ec); // create the symlink once + VERIFY( !ec ); + VERIFY( exists(p) ); + VERIFY( is_symlink(p) ); + remove(p); + create_symlink(tgt, p); // create the symlink again + VERIFY( exists(p) ); + VERIFY( is_symlink(p) ); + + ec.clear(); + create_symlink(tgt, p, ec); // Try to create existing symlink + VERIFY( ec ); + try + { + create_symlink(tgt, p); + } + catch (const std::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == tgt ); + VERIFY( ex.path2() == p ); + } + VERIFY( ec2 == ec ); + + remove(p); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc new file mode 100644 index 00000000000..2ba3ff9fc53 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc @@ -0,0 +1,58 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 15.11 Current path [fs.op.current_path] + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + fs::path dot("."); + fs::path cwd = fs::current_path(); + std::error_code ec; + fs::path cwd2 = fs::current_path(ec); + VERIFY( cwd == cwd2 ); +} + +void +test02() +{ + auto oldwd = fs::current_path(); + auto tmpdir = fs::temp_directory_path(); + current_path(tmpdir); + VERIFY( canonical(fs::current_path()) == canonical(tmpdir) ); + std::error_code ec; + current_path(oldwd, ec); + VERIFY( canonical(fs::current_path()) == canonical(oldwd) ); + VERIFY( canonical(fs::current_path(ec)) == canonical(oldwd) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc new file mode 100644 index 00000000000..92d69c604ac --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + auto p1 = __gnu_test::nonexistent_path(); + auto p2 = __gnu_test::nonexistent_path(); + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + bool result; + + result = equivalent(p1, p2, ec); + VERIFY( ec ); + VERIFY( !result ); + + __gnu_test::scoped_file f1(p1); + ec = bad_ec; + result = equivalent(p1, p2, ec); + VERIFY( !ec ); + VERIFY( !result ); + + __gnu_test::scoped_file f2(p2); + ec = bad_ec; + result = equivalent(p1, p2, ec); + VERIFY( !ec ); + VERIFY( !result ); + + auto p3 = __gnu_test::nonexistent_path(); + create_hard_link(p1, p3, ec); + if (ec) + return; // hard links not supported + __gnu_test::scoped_file f3(p3, __gnu_test::scoped_file::adopt_file); + + ec = bad_ec; + result = equivalent(p1, p3, ec); + VERIFY( !ec ); + VERIFY( result ); + + ec = bad_ec; + result = equivalent(p2, p3, ec); + VERIFY( !ec ); + VERIFY( !result ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc new file mode 100644 index 00000000000..0775eff4d9b --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc @@ -0,0 +1,115 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + + VERIFY( exists(path{"/"}) ); + VERIFY( exists(path{"/."}) ); + VERIFY( exists(path{"."}) ); + VERIFY( exists(path{".."}) ); + VERIFY( exists(std::filesystem::current_path()) ); + + std::error_code ec; + ec = bad_ec; + VERIFY( exists(path{"/"}, ec) ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( exists(path{"/."}, ec) ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( exists(path{"."}, ec) ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( exists(path{".."}, ec) ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( exists(std::filesystem::current_path(), ec) ); + VERIFY( !ec ); +} + +void +test02() +{ + path rel = __gnu_test::nonexistent_path(); + VERIFY( !exists(rel) ); + + std::error_code ec = std::make_error_code(std::errc::invalid_argument); + VERIFY( !exists(rel, ec) ); + VERIFY( !ec ); // DR 2725 +} + +void +test03() +{ + path abs = absolute(__gnu_test::nonexistent_path()); + VERIFY( !exists(abs) ); + + std::error_code ec = std::make_error_code(std::errc::invalid_argument); + VERIFY( !exists(abs, ec) ); + VERIFY( !ec ); // DR 2725 +} + +void +test04() +{ + using std::filesystem::perms; + using std::filesystem::perm_options; + path p = __gnu_test::nonexistent_path(); + create_directory(p); + permissions(p, perms::all, perm_options::remove); + + auto unr = p / "unreachable"; + std::error_code ec; + VERIFY( !exists(unr, ec) ); + VERIFY( ec == std::errc::permission_denied ); + ec.clear(); + try + { + exists(unr); + } + catch(const std::filesystem::filesystem_error& ex) + { + ec = ex.code(); + VERIFY( ex.path1() == unr ); + } + VERIFY( ec == std::errc::permission_denied ); + + permissions(p, perms::owner_all); + remove(p); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc new file mode 100644 index 00000000000..250d31891a0 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + std::error_code ec; + size_t size = fs::file_size(".", ec); + VERIFY( ec == std::errc::is_a_directory ); + VERIFY( size == -1 ); + + try { + size = fs::file_size("."); + ec.clear(); + } catch (const fs::filesystem_error& e) { + ec = e.code(); + } + VERIFY( ec == std::errc::is_a_directory ); + VERIFY( size == -1 ); +} + +void +test02() +{ + fs::path p = __gnu_test::nonexistent_path(); + + std::error_code ec; + size_t size = fs::file_size(p, ec); + VERIFY( ec ); + VERIFY( size == -1 ); + + try { + size = fs::file_size(p); + ec.clear(); + } catch (const fs::filesystem_error& e) { + ec = e.code(); + } + VERIFY( ec ); + VERIFY( size == -1 ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc new file mode 100644 index 00000000000..6d79a9139cf --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc @@ -0,0 +1,109 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + auto p = __gnu_test::nonexistent_path(); + create_directory(p); + permissions(p, fs::perms::none); + std::error_code ec, ec2; + + bool result = fs::is_empty(p, ec); + VERIFY( ec == std::make_error_code(std::errc::permission_denied) ); + VERIFY( !result ); + + try { + fs::is_empty(p); + } catch (const fs::filesystem_error& e) { + ec2 = e.code(); + } + VERIFY( ec2 == ec ); + + result = fs::is_empty(p/"f", ec); + VERIFY( ec == std::make_error_code(std::errc::permission_denied) ); + VERIFY( !result ); + + try { + fs::is_empty(p/"f"); + } catch (const fs::filesystem_error& e) { + ec2 = e.code(); + } + VERIFY( ec2 == ec ); + + permissions(p, fs::perms::owner_all, ec); + remove_all(p, ec); +} + +void +test02() +{ + auto p = __gnu_test::nonexistent_path(); + create_directory(p); + std::error_code ec, bad_ec = make_error_code(std::errc::invalid_argument); + bool empty; + + ec = bad_ec; + empty = is_empty(p, ec); + VERIFY( !ec ); + VERIFY( empty ); + empty = is_empty(p); + VERIFY( empty ); + + __gnu_test::scoped_file f(p/"f"); + ec = bad_ec; + empty = is_empty(f.path, ec); + VERIFY( !ec ); + VERIFY( empty ); + empty = is_empty(f.path); + VERIFY( empty ); + + std::ofstream{f.path.native()} << "data"; + ec = bad_ec; + empty = is_empty(p, ec); + VERIFY( !ec ); + VERIFY( !empty ); + empty = is_empty(p); + VERIFY( !empty ); + + ec = bad_ec; + empty = is_empty(p, ec); + VERIFY( !ec ); + VERIFY( !empty ); + empty = is_empty(p); + VERIFY( !empty ); + + f.path.clear(); + remove_all(p, ec); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc new file mode 100644 index 00000000000..ecef3f85721 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc @@ -0,0 +1,162 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// 15.25 Permissions [fs.op.last_write_time] + +#include +#include +#include + +#ifdef _GLIBCXX_HAVE_FCNTL_H +# include +#endif +#if _GLIBCXX_HAVE_UTIME_H +# include +#endif + +using time_type = std::filesystem::file_time_type; + +void +test01() +{ + // read times + + auto p = __gnu_test::nonexistent_path(); + std::error_code ec; + time_type mtime = last_write_time(p, ec); + VERIFY( ec ); + VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) ); +#if __cpp_exceptions + bool caught = false; + try { + mtime = last_write_time(p); + } catch (std::system_error const& e) { + caught = true; + ec = e.code(); + } + VERIFY( caught ); + VERIFY( ec ); + VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) ); +#endif + + __gnu_test::scoped_file file(p); + VERIFY( exists(p) ); + mtime = last_write_time(p, ec); + VERIFY( !ec ); + VERIFY( mtime <= time_type::clock::now() ); + VERIFY( mtime == last_write_time(p) ); + + auto end_of_time = time_type::duration::max(); + auto last_second + = std::chrono::duration_cast(end_of_time).count(); + if (last_second > std::numeric_limits::max()) + return; // can't test overflow + +#if _GLIBCXX_USE_UTIMENSAT + struct ::timespec ts[2]; + ts[0].tv_sec = 0; + ts[0].tv_nsec = UTIME_NOW; + ts[1].tv_sec = std::numeric_limits::max() - 1; + ts[1].tv_nsec = 0; + VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) ); +#elif _GLIBCXX_HAVE_UTIME_H + ::utimbuf times; + times.modtime = std::numeric_limits::max() - 1; + times.actime = std::numeric_limits::max() - 1; + VERIFY( !::utime(p.c_str(), ×) ); +#else + return; +#endif + + mtime = last_write_time(p, ec); + VERIFY( ec ); + VERIFY( ec == std::make_error_code(std::errc::value_too_large) ); + VERIFY( mtime == time_type::min() ); + +#if __cpp_exceptions + caught = false; + try { + mtime = last_write_time(p); + } catch (std::system_error const& e) { + caught = true; + ec = e.code(); + } + VERIFY( caught ); + VERIFY( ec ); + VERIFY( ec == std::make_error_code(std::errc::value_too_large) ); +#endif +} + +bool approx_equal(time_type file_time, time_type expected) +{ + auto delta = expected - file_time; + if (delta < delta.zero()) + delta = -delta; + return delta < std::chrono::seconds(1); +} + +void +test02() +{ + // write times + + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + __gnu_test::scoped_file f; + std::error_code ec; + time_type time; + + time = last_write_time(f.path); + ec = bad_ec; + last_write_time(f.path, time, ec); + VERIFY( !ec ); + VERIFY( approx_equal(last_write_time(f.path), time) ); + + ec = bad_ec; + time -= std::chrono::milliseconds(1000 * 60 * 10 + 15); + last_write_time(f.path, time, ec); + VERIFY( !ec ); + VERIFY( approx_equal(last_write_time(f.path), time) ); + + ec = bad_ec; + time += std::chrono::milliseconds(1000 * 60 * 20 + 15); + last_write_time(f.path, time, ec); + VERIFY( !ec ); + VERIFY( approx_equal(last_write_time(f.path), time) ); + + ec = bad_ec; + time = time_type(); + last_write_time(f.path, time, ec); + VERIFY( !ec ); + VERIFY( approx_equal(last_write_time(f.path), time) ); + + ec = bad_ec; + time -= std::chrono::milliseconds(1000 * 60 * 10 + 15); + last_write_time(f.path, time, ec); + VERIFY( !ec ); + VERIFY( approx_equal(last_write_time(f.path), time) ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc new file mode 100644 index 00000000000..97b7a7874f7 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc @@ -0,0 +1,167 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// C++17 30.10.14.26 Permissions [fs.op.permissions] + +#include +#include +#include + +void +test01() +{ + using std::filesystem::perms; + using std::filesystem::perm_options; + + auto p = __gnu_test::nonexistent_path(); + + __gnu_test::scoped_file f(p); + VERIFY( exists(p) ); + permissions(p, perms::owner_all); + VERIFY( status(p).permissions() == perms::owner_all ); + permissions(p, perms::group_read, perm_options::add); + VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) ); + permissions(p, perms::group_read, perm_options::remove); + VERIFY( status(p).permissions() == perms::owner_all ); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + using std::filesystem::perms; + using std::filesystem::perm_options; + + auto p = __gnu_test::nonexistent_path(); + + std::error_code ec; + permissions(p, perms::owner_all, ec); + VERIFY( ec ); + + __gnu_test::scoped_file f(p); + VERIFY( exists(p) ); + + ec = bad_ec; + permissions(p, perms::owner_all, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == perms::owner_all ); + ec = bad_ec; + permissions(p, perms::group_read, perm_options::add, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) ); + ec = bad_ec; + permissions(p, perms::group_read, perm_options::remove, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == perms::owner_all ); +} + +void +test03() +{ + using std::filesystem::perms; + using std::filesystem::perm_options; + + __gnu_test::scoped_file f; + VERIFY( exists(f.path) ); + + auto p = __gnu_test::nonexistent_path(); + create_symlink(f.path, p); + + std::error_code ec = make_error_code(std::errc::no_such_file_or_directory); + std::error_code ec2 = make_error_code(std::errc::invalid_argument); + permissions(p, perms::owner_all, + perm_options::replace|perm_options::nofollow, ec); + try + { + permissions(p, perms::owner_all, + perm_options::replace|perm_options::nofollow); + } + catch (const std::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == p ); + } + // Both calls should succeed, or both should fail with same error: + VERIFY( ec == ec2 ); + + remove(p); +} + +void +test04() +{ + using perms = std::filesystem::perms; + + auto p = __gnu_test::nonexistent_path(); + create_symlink(__gnu_test::nonexistent_path(), p); + + std::error_code ec = make_error_code(std::errc::no_such_file_or_directory); + std::error_code ec2 = make_error_code(std::errc::invalid_argument); + permissions(p, perms::owner_all, ec); + VERIFY( ec ); + try + { + permissions(p, perms::owner_all); + } + catch (const std::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == p ); + } + VERIFY( ec == ec2 ); + + remove(p); +} + +void +test05() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + using std::filesystem::perms; + using std::filesystem::perm_options; + std::error_code ec; + + __gnu_test::scoped_file f; + auto p = perms::owner_write; + + // symlink_nofollow should not give an error for non-symlinks + ec = bad_ec; + permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec); + VERIFY( !ec ); + auto st = status(f.path); + VERIFY( st.permissions() == p ); + p |= perms::owner_read; + ec = bad_ec; + permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec); + VERIFY( !ec ); + st = status(f.path); + VERIFY( st.permissions() == p ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc new file mode 100644 index 00000000000..02da2507d46 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include + +using std::filesystem::proximate; + +void +test01() +{ + VERIFY( proximate("/a/d", "/a/b/c") == "../../d" ); + VERIFY( proximate("/a/b/c", "/a/d") == "../b/c" ); + VERIFY( proximate("a/b/c", "a") == "b/c" ); + VERIFY( proximate("a/b/c", "a/b/c/x/y") == "../.." ); + VERIFY( proximate("a/b/c", "a/b/c") == "." ); + VERIFY( proximate("a/b", "c/d") == "../../a/b" ); +} + +void +test02() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec = bad_ec; + VERIFY( proximate("/a/d", "/a/b/c", ec) == "../../d" ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( proximate("/a/b/c", "/a/d", ec) == "../b/c" ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( proximate("a/b/c", "a", ec) == "b/c" ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( proximate("a/b/c", "a/b/c/x/y", ec) == "../.." ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( proximate("a/b/c", "a/b/c", ec) == "." ); + VERIFY( !ec ); + ec = bad_ec; + VERIFY( proximate("a/b", "c/d", ec) == "../../a/b" ); + VERIFY( !ec ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc new file mode 100644 index 00000000000..067a60950ea --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc @@ -0,0 +1,51 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + auto p = __gnu_test::nonexistent_path(); + std::error_code ec; + + read_symlink(p, ec); + VERIFY( ec ); + + fs::path tgt = "."; + create_symlink(tgt, p); + + auto result = read_symlink(p, ec); + VERIFY( !ec ); + VERIFY( result == tgt ); + + remove(p); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc new file mode 100644 index 00000000000..c9765fa5680 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +void +test01() +{ + auto p = __gnu_test::nonexistent_path(); + auto q = __gnu_test::nonexistent_path(); + + auto r = relative(p, q); + VERIFY( r == ".."/p ); + + r = relative(p, p/q); + VERIFY( r == ".." ); + + r = relative(p/q, p); + VERIFY( r == q ); + + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + ec = bad_ec; + r = relative(p, q, ec); + VERIFY( !ec ); + VERIFY( r == ".."/p ); + + ec = bad_ec; + r = relative(p, p/q, ec); + VERIFY( !ec ); + VERIFY( r == ".." ); + + ec = bad_ec; + r = relative(p/q, p, ec); + VERIFY( !ec ); + VERIFY( r == q ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc new file mode 100644 index 00000000000..3f68f17f992 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc @@ -0,0 +1,92 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + std::error_code ec; + std::uintmax_t n; + + n = fs::remove_all("", ec); + VERIFY( ec ); + VERIFY( n == std::uintmax_t(-1) ); + + auto p = __gnu_test::nonexistent_path(); + ec.clear(); + n = remove_all(p, ec); + VERIFY( ec ); + VERIFY( n == std::uintmax_t(-1) ); + + const auto bad_ec = ec; + auto link = __gnu_test::nonexistent_path(); + create_symlink(p, link); // dangling symlink + ec = bad_ec; + n = remove_all(link, ec); + VERIFY( !ec ); + VERIFY( n == 1 ); + VERIFY( !exists(symlink_status(link)) ); // DR 2721 + + __gnu_test::scoped_file f(p); + create_symlink(p, link); + ec = bad_ec; + n = remove_all(link, ec); + VERIFY( !ec ); + VERIFY( n == 1 ); + VERIFY( !exists(symlink_status(link)) ); // The symlink is removed, but + VERIFY( exists(p) ); // its target is not. + + auto dir = __gnu_test::nonexistent_path(); + create_directories(dir/"a/b/c"); + ec = bad_ec; + n = remove_all(dir/"a", ec); + VERIFY( !ec ); + VERIFY( n == 3 ); + VERIFY( exists(dir) ); + VERIFY( !exists(dir/"a") ); + + create_directories(dir/"a/b/c"); + __gnu_test::scoped_file a1(dir/"a/1"); + __gnu_test::scoped_file a2(dir/"a/2"); + __gnu_test::scoped_file b1(dir/"a/b/1"); + __gnu_test::scoped_file b2(dir/"a/b/2"); + ec = bad_ec; + n = remove_all(dir, ec); + VERIFY( !ec ); + VERIFY( n == 8 ); + VERIFY( !exists(dir) ); + + a1.path.clear(); + a2.path.clear(); + b1.path.clear(); + b2.path.clear(); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc new file mode 100644 index 00000000000..7b611352967 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc @@ -0,0 +1,46 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// 30.10.14.3 Permissions [fs.op.space] + +#include +#include +#include + +void +test01() +{ + std::filesystem::space_info s = std::filesystem::space("/"); + std::error_code ec = make_error_code(std::errc::invalid_argument); + s = std::filesystem::space("/", ec); + VERIFY( !ec ); + s = std::filesystem::space(__gnu_test::nonexistent_path(), ec); + VERIFY( ec ); + VERIFY( s.capacity == static_cast(-1) ); + VERIFY( s.free == static_cast(-1) ); + VERIFY( s.available == static_cast(-1) ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc new file mode 100644 index 00000000000..efe92b26a78 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + std::error_code ec = make_error_code(std::errc::invalid_argument); + fs::path dot = "."; + + fs::file_status st1 = fs::status(dot, ec); + VERIFY( !ec ); + VERIFY( st1.type() == fs::file_type::directory ); + + fs::file_status st2 = fs::status(dot); + VERIFY( st2.type() == fs::file_type::directory ); +} + +void +test02() +{ + fs::path p = __gnu_test::nonexistent_path(); + + std::error_code ec; + fs::file_status st1 = fs::status(p, ec); + VERIFY( ec ); + VERIFY( st1.type() == fs::file_type::not_found ); + + fs::file_status st2 = fs::status(p); + VERIFY( st2.type() == fs::file_type::not_found ); +} + +void +test03() +{ + fs::path dir = __gnu_test::nonexistent_path(); + fs::create_directory(dir); + __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file); + __gnu_test::scoped_file f(dir / "file"); + fs::permissions(dir, fs::perms::none); + + std::error_code ec; + fs::file_status st = fs::status(f.path, ec); + VERIFY( ec.value() == (int)std::errc::permission_denied ); + VERIFY( st.type() == fs::file_type::none ); + +#if __cpp_exceptions + bool caught = false; + std::error_code ec2; + fs::path p, p2; + try { + fs::symlink_status(f.path); + } catch (const fs::filesystem_error& e) { + caught = true; + p = e.path1(); + p2 = e.path2(); + ec2 = e.code(); + } + VERIFY( caught ); + VERIFY( ec2 == ec ); + VERIFY( p == f.path ); + VERIFY( p2.empty() ); +#endif + + fs::permissions(dir, fs::perms::owner_all, ec); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc new file mode 100644 index 00000000000..ae7a76be7c3 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec = bad_ec; + fs::path dot = "."; + + fs::file_status st1 = fs::symlink_status(dot, ec); + VERIFY( !ec ); + VERIFY( st1.type() == fs::file_type::directory ); + + fs::file_status st2 = fs::symlink_status(dot); + VERIFY( st2.type() == fs::file_type::directory ); + + fs::path link = __gnu_test::nonexistent_path(); + create_directory_symlink(dot, link); + + st1 = fs::symlink_status(link); + VERIFY( st1.type() == fs::file_type::symlink ); + ec = bad_ec; + st2 = fs::symlink_status(link, ec); + VERIFY( !ec ); + VERIFY( st2.type() == fs::file_type::symlink ); +} + +void +test02() +{ + fs::path p = __gnu_test::nonexistent_path(); + + std::error_code ec; + fs::file_status st1 = fs::symlink_status(p, ec); + VERIFY( ec ); + VERIFY( st1.type() == fs::file_type::not_found ); + + fs::file_status st2 = fs::symlink_status(p); + VERIFY( st2.type() == fs::file_type::not_found ); +} + +void +test03() +{ + fs::path dir = __gnu_test::nonexistent_path(); + fs::create_directory(dir); + __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file); + __gnu_test::scoped_file f(dir / "file"); + fs::permissions(dir, fs::perms::none); + auto link = __gnu_test::nonexistent_path(); + fs::create_symlink(f.path, link); + __gnu_test::scoped_file l(link, __gnu_test::scoped_file::adopt_file); + + std::error_code ec; + fs::file_status st = fs::symlink_status(f.path, ec); + VERIFY( ec.value() == (int)std::errc::permission_denied ); + VERIFY( st.type() == fs::file_type::none ); + + st = fs::symlink_status(link, ec); + VERIFY( !ec ); + VERIFY( st.type() == fs::file_type::symlink ); + +#if __cpp_exceptions + bool caught = false; + std::error_code ec2; + fs::path p, p2; + try { + fs::symlink_status(f.path); + } catch (const fs::filesystem_error& e) { + caught = true; + p = e.path1(); + p2 = e.path2(); + ec2 = e.code(); + } + VERIFY( caught ); + VERIFY( ec2.value() == (int)std::errc::permission_denied ); + VERIFY( p == f.path ); + VERIFY( p2.empty() ); +#endif + + fs::file_status st2 = symlink_status(link); + VERIFY( st2.type() == fs::file_type::symlink ); + + fs::permissions(dir, fs::perms::owner_all, ec); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc new file mode 100644 index 00000000000..ee065f0679f --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc @@ -0,0 +1,127 @@ +// Copyright (C) 2015-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include +#include + +void +clean_env() +{ + ::unsetenv("TMPDIR"); + ::unsetenv("TMP"); + ::unsetenv("TEMPDIR"); + ::unsetenv("TEMP"); +} + +namespace fs = std::filesystem; + +void +test01() +{ + clean_env(); + + if (!fs::exists("/tmp")) + return; // just give up + + std::error_code ec = make_error_code(std::errc::invalid_argument); + fs::path p1 = fs::temp_directory_path(ec); + VERIFY( !ec ); + VERIFY( exists(p1) ); + + fs::path p2 = fs::temp_directory_path(); + VERIFY( p1 == p2 ); +} + +void +test02() +{ + clean_env(); + + if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1)) + return; // just give up + + std::error_code ec; + fs::path p = fs::temp_directory_path(ec); + VERIFY( ec ); + VERIFY( p == fs::path() ); + + std::error_code ec2; + try { + p = fs::temp_directory_path(); + } catch (const fs::filesystem_error& e) { + ec2 = e.code(); + } + VERIFY( ec2 == ec ); +} + +void +test03() +{ + auto p = __gnu_test::nonexistent_path(); + create_directories(p/"tmp"); + permissions(p, fs::perms::none); + setenv("TMPDIR", (p/"tmp").c_str(), 1); + std::error_code ec; + auto r = fs::temp_directory_path(ec); // libstdc++/PR71337 + VERIFY( ec == std::make_error_code(std::errc::permission_denied) ); + VERIFY( r == fs::path() ); + + std::error_code ec2; + try { + fs::temp_directory_path(); + } catch (const fs::filesystem_error& e) { + ec2 = e.code(); + } + VERIFY( ec2 == ec ); + + permissions(p, fs::perms::owner_all, ec); + remove_all(p, ec); +} + +void +test04() +{ + __gnu_test::scoped_file f; + setenv("TMPDIR", f.path.c_str(), 1); + std::error_code ec; + auto r = fs::temp_directory_path(ec); + VERIFY( ec == std::make_error_code(std::errc::not_a_directory) ); + VERIFY( r == fs::path() ); + + std::error_code ec2; + try { + fs::temp_directory_path(); + } catch (const fs::filesystem_error& e) { + ec2 = e.code(); + } + VERIFY( ec2 == ec ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc new file mode 100644 index 00000000000..0f285e2bb59 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc @@ -0,0 +1,70 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::filesystem; + +void +test01() +{ + auto dir = __gnu_test::nonexistent_path(); + fs::create_directory(dir); + const auto dirc = canonical(dir); + fs::path foo = dir/"foo", bar = dir/"bar"; + fs::create_directory(foo); + fs::create_directory(bar); + fs::create_directory(bar/"baz"); + fs::create_symlink("../bar", foo/"bar"); + + auto p = fs::weakly_canonical(dir/"foo//./bar///../biz/."); + VERIFY( p == dirc/"biz/" ); + p = fs::weakly_canonical(dir/"foo/.//bar/././baz/."); + VERIFY( p == dirc/"bar/baz" ); + p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz"); + VERIFY( p == dirc/"bar/baz" ); + + const std::error_code bad_ec = make_error_code(std::errc::invalid_argument); + std::error_code ec; + + ec = bad_ec; + p = fs::weakly_canonical(dir/"foo//./bar///../biz/.", ec); + VERIFY( !ec ); + VERIFY( p == dirc/"biz/" ); + ec = bad_ec; + p = fs::weakly_canonical(dir/"foo/.//bar/././baz/.", ec); + VERIFY( !ec ); + VERIFY( p == dirc/"bar/baz" ); + ec = bad_ec; + p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz", ec); + VERIFY( !ec ); + VERIFY( p == dirc/"bar/baz" ); + + fs::remove_all(dir, ec); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc new file mode 100644 index 00000000000..64c638ed1e3 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc @@ -0,0 +1,87 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.3 path appends [path.append] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const path p("/foo/bar"); + + path pp = p; + pp /= p; + VERIFY( pp.native() == p.native() ); + + path q("baz"); + + path qq = q; + qq /= q; + VERIFY( qq.native() == "baz/baz" ); + + q /= p; + VERIFY( q.native() == p.native() ); + + path r = ""; + r /= path(); + VERIFY( r.empty() ); + + r /= path("rel"); + VERIFY( !r.is_absolute() ); + + path s = "dir/"; + s /= path("/file"); + VERIFY( s.native() == "/file" ); + + s = "dir/"; + s /= path("file"); + VERIFY( s.native() == "dir/file" ); +} + +void +test02() +{ + // C++17 [fs.path.append] p4 + + path p = path("//host") / "foo"; + VERIFY( p == "//host/foo" ); + + path pp = path("//host/") / "foo"; + VERIFY( pp == "//host/foo" ); + + path q = path("foo") / ""; + VERIFY( q == "foo/" ); + + path qq = path("foo") / "/bar"; + VERIFY( qq == "/bar" ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc new file mode 100644 index 00000000000..d8797cae168 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc @@ -0,0 +1,94 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include + +using std::filesystem::path; +using __gnu_test::compare_paths; + +void +test01() +{ + for (std::string s : __gnu_test::test_paths) + { + path p0 = s, p1, p2, p3, p4; + + p1 = s; + compare_paths(p0, p1); + + p2 = s.c_str(); + compare_paths(p0, p2); + +#if _GLIBCXX_USE_WCHAR_T + std::wstring ws(s.begin(), s.end()); + + p3 = ws; + compare_paths(p0, p3); + + p4 = ws.c_str(); + compare_paths(p0, p4); +#endif + } +} + +void +test02() +{ + for (std::string s : __gnu_test::test_paths) + { + path p0 = s, p1, p2, p3, p4, p5, p6, p7, p8; + + p1.assign(s); + compare_paths(p0, p1); + + p2.assign( s.begin(), s.end() ); + compare_paths(p0, p2); + + p3.assign( s.c_str() ); + compare_paths(p0, p3); + + p4.assign( s.c_str(), s.c_str() + s.size() ); + compare_paths(p0, p4); + +#if _GLIBCXX_USE_WCHAR_T + std::wstring ws(s.begin(), s.end()); + + p5.assign(ws); + compare_paths(p0, p5); + + p6.assign( ws.begin(), ws.end() ); + compare_paths(p0, p6); + + p7.assign( ws.c_str() ); + compare_paths(p0, p7); + + p8.assign( ws.c_str(), ws.c_str() + ws.size() ); + compare_paths(p0, p8); +#endif + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc new file mode 100644 index 00000000000..27bf00ab126 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc @@ -0,0 +1,56 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include + +using std::filesystem::path; +using __gnu_test::compare_paths; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + path copy; + copy = p; + __gnu_test::compare_paths(p, copy); + } +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path copy = p; + path move; + move = std::move(copy); + __gnu_test::compare_paths(p, move); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc new file mode 100644 index 00000000000..e444220ec25 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc @@ -0,0 +1,51 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.8 path compare [path.compare] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p("/foo/bar"); + VERIFY( p.compare(p) == 0 ); + VERIFY( p.compare("/foo//bar") == 0 ); + + path q("/foo/baz"); + VERIFY( p.compare(q) < 0 ); + VERIFY( q.compare(p) > 0 ); + + path r("/foo/bar/."); + VERIFY( p.compare(r) < 0 ); + + VERIFY( path("a/b/").compare("a/b//") == 0 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc new file mode 100644 index 00000000000..4bed5a23fd5 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc @@ -0,0 +1,51 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.8 path compare [path.compare] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const path p0 = "/a/a/b/b"; + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.compare(p) == 0 ); + int cmp = p.compare(p0); + if (cmp == 0) + VERIFY( p0.compare(p) == 0 ); + else if (cmp < 0) + VERIFY( p0.compare(p) > 0 ); + else if (cmp > 0) + VERIFY( p0.compare(p) < 0 ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc new file mode 100644 index 00000000000..be8f8b0d709 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc @@ -0,0 +1,49 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.8 path compare [path.compare] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const std::string s0 = "/a/a/b/b"; + const path p0 = s0; + for (const std::string& s : __gnu_test::test_paths) + { + path p(s); + VERIFY( p.compare(s) == 0 ); + VERIFY( p.compare(s.c_str()) == 0 ); + VERIFY( p.compare(p0) == p.compare(s0) ); + VERIFY( p.compare(p0) == p.compare(s0.c_str()) ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc new file mode 100644 index 00000000000..46cf09abe16 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc @@ -0,0 +1,69 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.4 path concatenation [path.concat] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const path p("/foo/bar"); + + path pp = p; + pp += p; + VERIFY( pp.native() == "/foo/bar/foo/bar" ); + VERIFY( std::distance(pp.begin(), pp.end()) == 5 ); + + path q("foo/bar"); + + path qq = q; + qq += q; + VERIFY( qq.native() == "foo/barfoo/bar" ); + VERIFY( std::distance(qq.begin(), qq.end()) == 3 ); + + q += p; + VERIFY( q.native() == "foo/bar/foo/bar" ); + VERIFY( std::distance(q.begin(), q.end()) == 4 ); +} + +void +test02() +{ + for (path p : __gnu_test::test_paths) + { + auto prior_native = p.native(); + path x("//blah/di/blah"); + p += x; + VERIFY( p.native() == prior_native + x.native() ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc new file mode 100644 index 00000000000..3eb4d1a3cb1 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc @@ -0,0 +1,56 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.4 path concatenation [path.concat] + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p("/"); + p += path::string_type("foo"); + VERIFY( p.filename() == "foo" ); + p += "bar"; + VERIFY( p.filename() == "foobar" ); + p += '/'; + VERIFY( p.parent_path() == "/foobar" && p.filename() == "" ); +#if _GLIBCXX_USE_WCHAR_T + p += L"baz.txt"; +#else + p += "baz.txt"; +#endif + VERIFY( p.filename() == "baz.txt" ); + p.concat("/dir/"); + VERIFY( p.parent_path() == "/foobar/baz.txt/dir" && p.filename() == "" ); + std::string file = "file"; + p.concat(file.begin(), file.end()); + VERIFY( p.filename() == "file" ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc new file mode 100644 index 00000000000..cb084bdfeda --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc @@ -0,0 +1,55 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.1 path constructors [path.construct] + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + path copy = p; + __gnu_test::compare_paths(p, copy); + } +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path copy = p; + path move = std::move(copy); + __gnu_test::compare_paths(p, move); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc new file mode 100644 index 00000000000..85ce129436d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc @@ -0,0 +1,51 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.1 path constructors [path.construct] + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p; + VERIFY( p.empty() ); + VERIFY( !p.has_root_path() ); + VERIFY( !p.has_root_name() ); + VERIFY( !p.has_root_directory() ); + VERIFY( !p.has_relative_path() ); + VERIFY( !p.has_parent_path() ); + VERIFY( !p.has_filename() ); + VERIFY( !p.has_stem() ); + VERIFY( !p.has_extension() ); + VERIFY( !p.is_absolute() ); + VERIFY( p.is_relative() ); + VERIFY( std::distance(p.begin(), p.end()) == 0 ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc new file mode 100644 index 00000000000..e313412386d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc @@ -0,0 +1,40 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.1 path constructors [path.construct] + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p("/foo/bar", std::locale::classic()); + VERIFY( p.string() == "/foo/bar" ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc new file mode 100644 index 00000000000..ad2cc18e512 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc @@ -0,0 +1,112 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.1 path constructors [path.construct] + +#include +#include +#include +#include + +using std::filesystem::path; +using __gnu_test::compare_paths; + +void +test01() +{ + for (std::string s : __gnu_test::test_paths) + { + path p1 = s; + path p2( s.begin(), s.end() ); + path p3( s.c_str() ); + path p4( s.c_str(), s.c_str() + s.size() ); + + compare_paths(p1, p2); + compare_paths(p1, p3); + compare_paths(p1, p4); + +#if _GLIBCXX_USE_WCHAR_T + std::wstring ws(s.begin(), s.end()); + path p5 = ws; + path p6( ws.begin(), ws.end() ); + path p7( ws.c_str() ); + path p8( ws.c_str(), ws.c_str() + ws.size() ); + + compare_paths(p1, p5); + compare_paths(p1, p6); + compare_paths(p1, p7); + compare_paths(p1, p8); +#endif + + using __gnu_test::test_container; + using __gnu_test::input_iterator_wrapper; + // Test with input iterators and const value_types + + test_container + r1((char*)s.c_str(), (char*)s.c_str() + s.size()); + path p9(r1.begin(), r1.end()); + compare_paths(p1, p9); + + test_container + r2((char*)s.c_str(), (char*)s.c_str() + s.size() + 1); // includes null-terminator + path p10(r2.begin()); + compare_paths(p1, p10); + + test_container + r3(s.c_str(), s.c_str() + s.size()); + path p11(r3.begin(), r3.end()); + compare_paths(p1, p11); + + test_container + r4(s.c_str(), s.c_str() + s.size() + 1); // includes null-terminator + path p12(r4.begin()); + compare_paths(p1, p12); + +#if _GLIBCXX_USE_WCHAR_T + // Test with input iterators and const value_types + test_container + r5((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size()); + path p13(r5.begin(), r5.end()); + compare_paths(p1, p13); + + test_container + r6((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size() + 1); // includes null-terminator + path p14(r6.begin()); + compare_paths(p1, p14); + + test_container + r7(ws.c_str(), ws.c_str() + ws.size()); + path p15(r7.begin(), r7.end()); + compare_paths(p1, p15); + + test_container + r8(ws.c_str(), ws.c_str() + ws.size() + 1); // includes null-terminator + path p16(r8.begin()); + compare_paths(p1, p16); +#endif + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc new file mode 100644 index 00000000000..b9a52058791 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc @@ -0,0 +1,56 @@ +// { dg-options "-lstdc++fs -std=gnu++17" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.1 path constructors [path.construct] + +#include +#include +#include +#include + +using std::filesystem::path; +using __gnu_test::compare_paths; + +void +test01() +{ + for (std::string s : __gnu_test::test_paths) + { + path p1 = s; + std::string_view sv(s); + path p2 = sv; + compare_paths(p1, p2); + +#if _GLIBCXX_USE_WCHAR_T + std::wstring ws(s.begin(), s.end()); + path p3 = ws; + std::wstring_view wsv(ws); + path p4 = wsv; + compare_paths(p1, p4); +#endif + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc new file mode 100644 index 00000000000..13c9db275a0 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc @@ -0,0 +1,70 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path("/foo/bar.txt").extension() == path(".txt") ); + VERIFY( path("/foo/bar.baz.txt").extension() == path(".txt") ); + VERIFY( path(".bar.baz.txt").extension() == path(".txt") ); + + VERIFY( path(".profile").extension() == path("") ); + VERIFY( path(".profile.old").extension() == path(".old") ); + VERIFY( path("..abc").extension() == path(".abc") ); + VERIFY( path("...abc").extension() == path(".abc") ); + VERIFY( path("abc..def").extension() == path(".def") ); + VERIFY( path("abc...def").extension() == path(".def") ); + VERIFY( path("abc.").extension() == path(".") ); + VERIFY( path("abc..").extension() == path(".") ); + VERIFY( path("abc.d.").extension() == path(".") ); + VERIFY( path("..").extension() == path("") ); + VERIFY( path(".").extension() == path("") ); + + VERIFY( path().extension() == path() ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + auto stem = p.stem(); + auto ext = p.extension(); + auto file = p.filename(); + VERIFY( stem.native() + ext.native() == file.native() ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc new file mode 100644 index 00000000000..8ba0fcc8cb9 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc @@ -0,0 +1,70 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.4.9 path decomposition [fs.path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path("/foo/bar.txt").filename() == "bar.txt" ); + VERIFY( path("/foo/bar").filename() == "bar" ); + VERIFY( path("/foo/bar/").filename() == "" ); + VERIFY( path("/").filename() == "" ); +#ifdef __CYGWIN__ + VERIFY( path("//host").filename() == "" ); +#else + VERIFY( path("//host").filename() == "host" ); +#endif + VERIFY( path(".").filename() == "." ); + VERIFY( path("..").filename() == ".." ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path f = p.filename(); + if (p.empty()) + VERIFY( f.empty() ); + else + { + const path back = *--p.end(); + if (back.has_root_path()) + VERIFY( f.empty() ); + else + VERIFY( f == back ); + } + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc new file mode 100644 index 00000000000..c46566dad40 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc @@ -0,0 +1,73 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p0; + VERIFY( p0.parent_path() == p0 ); + path p1 = "foo"; + VERIFY( p1.parent_path() == p0 ); + path p2 = "foo/bar"; + VERIFY( p2.parent_path() == p1 ); + path p3 = "/foo/bar"; + VERIFY( p3.parent_path() == path("/foo") ); + VERIFY( p3.parent_path().parent_path() == path("/") ); + VERIFY( p3.parent_path().parent_path().parent_path() == path("/") ); + path p4 = "/"; + VERIFY( p4.parent_path() == p4 ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + if (p.begin() == p.end()) + continue; + if (p.has_relative_path()) + { + path pp; + for (auto i = p.begin(), end = --p.end(); i != end; ++i) + { + pp /= *i; + } + VERIFY( p.parent_path() == pp ); + } + else + VERIFY( p.parent_path() == p ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc new file mode 100644 index 00000000000..c8649724671 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc @@ -0,0 +1,70 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p1 = "foo"; + VERIFY( p1.relative_path() == p1 ); + path p2 = "foo/bar"; + VERIFY( p2.relative_path() == p2 ); + path p3 = "/foo/bar"; + VERIFY( p3.relative_path() == p2 ); +} + +#include // XXX + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + bool after_root = false; + const path prel = p.relative_path(); + VERIFY( !prel.has_root_name() ); + path rel; + for (const auto& cmpt : p) + { + if (!cmpt.has_root_path()) + after_root = true; + if (after_root) + rel /= cmpt; + } + if (prel != rel) + std::cout << prel << ' ' << rel << '\n'; + VERIFY( prel == rel ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc new file mode 100644 index 00000000000..8220c589efc --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc @@ -0,0 +1,59 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p1 = "foo/bar"; + VERIFY( p1.root_directory() == path() ); + path p2 = "/foo/bar"; + VERIFY( p2.root_directory() == path("/") ); + path p3 = "//foo"; + VERIFY( p3.root_directory() == path("/") ); + path p4 = "///foo"; + VERIFY( p4.root_directory() == path("/") ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path rootdir = p.root_directory(); + VERIFY( !rootdir.has_relative_path() ); + VERIFY( rootdir.empty() || rootdir.native() == "/"); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc new file mode 100644 index 00000000000..5bb2ccd177e --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc @@ -0,0 +1,43 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path("/foo/bar.txt").extension() == ".txt" ); + VERIFY( path("/foo/bar.baz.txt").extension() == ".txt" ); + VERIFY( path(".").extension().empty() ); + VERIFY( path("..").extension().empty() ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc new file mode 100644 index 00000000000..bce0134a447 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc @@ -0,0 +1,61 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.4.9 path decomposition [fs.path.decompose] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p1 = "foo/bar"; + VERIFY( p1.root_path() == path() ); + path p2 = "/foo/bar"; + VERIFY( p2.root_path() == path("/") ); +} + +#undef VERIFY +#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false) +#define DUMP(X, Y, Z) do { if (!(Y == Z)) { __builtin_printf("%s %s %s\n", X.c_str(), Y.c_str(), Z.c_str()); } } while(false) + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path rootp = p.root_path(); + path rootn = p.root_name(); + path rootd = p.root_directory(); + VERIFY( rootp == (rootn / rootd) ); + DUMP(p, rootp , (rootn / rootd) ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc new file mode 100644 index 00000000000..aec64e172ff --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc @@ -0,0 +1,62 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path("/foo/bar.txt").stem() == path("bar") ); + path p = "foo.bar.baz.tar"; + std::vector v; + for (; !p.extension().empty(); p = p.stem()) + v.push_back(p.extension().native()); + VERIFY( v.at(0) == ".tar" ); + VERIFY( v.at(1) == ".baz" ); + VERIFY( v.at(2) == ".bar" ); + + VERIFY( path(".profile").stem() == path(".profile") ); + VERIFY( path(".profile.old").stem() == path(".profile") ); + VERIFY( path("..abc").stem() == path(".") ); + VERIFY( path("...abc").stem() == path("..") ); + VERIFY( path("abc..def").stem() == path("abc.") ); + VERIFY( path("abc...def").stem() == path("abc..") ); + VERIFY( path("abc.").stem() == path("abc") ); + VERIFY( path("abc..").stem() == path("abc.") ); + VERIFY( path("abc.d.").stem() == path("abc.d") ); + VERIFY( path("..").stem() == path("..") ); + VERIFY( path(".").stem() == path(".") ); + + VERIFY( path().stem() == path() ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc new file mode 100644 index 00000000000..2e4ec5bc98e --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + // C++17 [fs.path.gen] p2 + VERIFY( path("foo/./bar/..").lexically_normal() == "foo/" ); + VERIFY( path("foo/.///bar/../").lexically_normal() == "foo/" ); +} + +void +test02() +{ + VERIFY( path("foo/../bar").lexically_normal() == "bar" ); + VERIFY( path("../foo/../bar").lexically_normal() == "../bar" ); + VERIFY( path("foo/../").lexically_normal() == "." ); + VERIFY( path("../../").lexically_normal() == "../.." ); + VERIFY( path("../").lexically_normal() == ".." ); + VERIFY( path("./").lexically_normal() == "." ); + VERIFY( path().lexically_normal() == "" ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc new file mode 100644 index 00000000000..7a25f7b417d --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + // C++17 [fs.path.gen] p5 + VERIFY( path("/a/d").lexically_proximate("/a/b/c") == "../../d" ); + VERIFY( path("/a/b/c").lexically_proximate("/a/d") == "../b/c" ); + VERIFY( path("a/b/c").lexically_proximate("a") == "b/c" ); + VERIFY( path("a/b/c").lexically_proximate("a/b/c/x/y") == "../.." ); + VERIFY( path("a/b/c").lexically_proximate("a/b/c") == "." ); + VERIFY( path("a/b").lexically_proximate("c/d") == "../../a/b" ); +} + +void +test02() +{ + path p = "a/b/c"; + VERIFY( p.lexically_proximate(p) == "." ); + VERIFY( p.lexically_proximate("a/../a/b/../b/c/../c/.") == "../../b/c" ); + VERIFY( p.lexically_proximate("../../../") == p ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc new file mode 100644 index 00000000000..64770fb1fe5 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include + +using std::filesystem::path; + +void +test01() +{ + // C++17 [fs.path.gen] p5 + VERIFY( path("/a/d").lexically_relative("/a/b/c") == "../../d" ); + VERIFY( path("/a/b/c").lexically_relative("/a/d") == "../b/c" ); + VERIFY( path("a/b/c").lexically_relative("a") == "b/c" ); + VERIFY( path("a/b/c").lexically_relative("a/b/c/x/y") == "../.." ); + VERIFY( path("a/b/c").lexically_relative("a/b/c") == "." ); + VERIFY( path("a/b").lexically_relative("c/d") == "../../a/b" ); +} + +void +test02() +{ + path p = "a/b/c"; + VERIFY( p.lexically_relative(p) == "." ); + VERIFY( p.lexically_relative("a/../a/b/../b/c/../c/.") == "../../b/c" ); + VERIFY( p.lexically_relative("../../../") == "" ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc new file mode 100644 index 00000000000..d25d5056c60 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc @@ -0,0 +1,55 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path().generic_string() == "" ); + VERIFY( path("/").generic_string() == "/" ); + VERIFY( path("////").generic_string() == "/" ); +#ifdef __CYGWIN__ + VERIFY( path("//a").generic_string() == "//a" ); + VERIFY( path("//a/").generic_string() == "//a/" ); + VERIFY( path("//a/b").generic_string() == "//a/b" ); +#else + VERIFY( path("//a").generic_string() == "/a" ); + VERIFY( path("//a/").generic_string() == "/a/" ); + VERIFY( path("//a/b").generic_string() == "/a/b" ); +#endif + VERIFY( path("/a//b").generic_string() == "/a/b" ); + VERIFY( path("/a//b/").generic_string() == "/a/b/" ); + VERIFY( path("/a//b//").generic_string() == "/a/b/" ); + VERIFY( path("/a//b//.").generic_string() == "/a/b/." ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc new file mode 100644 index 00000000000..7754140a714 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc @@ -0,0 +1,127 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.5 path iterators [fs.path.itr] + +#include +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + path p; + VERIFY( p.begin() == p.end() ); + + std::vector v, v2; + + p = "/"; + v.assign(p.begin(), p.end()); + v2 = { "/" }; + VERIFY( v == v2 ); + + p = "filename"; + v.assign(p.begin(), p.end()); + v2 = { "filename" }; + VERIFY( v == v2 ); + + p = "dir/."; + v.assign(p.begin(), p.end()); + v2 = { "dir", "." }; + VERIFY( v == v2 ); + + p = "dir/"; + v.assign(p.begin(), p.end()); + v2 = { "dir", "" }; + VERIFY( v == v2 ); + + p = "//rootname/dir/."; + v.assign(p.begin(), p.end()); +#ifdef __CYGWIN__ + v2 = { "//rootname", "/", "dir", "." }; +#else + v2 = { "/", "rootname", "dir", "." }; +#endif + VERIFY( v == v2 ); + + p = "//rootname/dir/"; + v.assign(p.begin(), p.end()); +#ifdef __CYGWIN__ + v2 = { "//rootname", "/", "dir", "" }; +#else + v2 = { "/", "rootname", "dir", "" }; +#endif + VERIFY( v == v2 ); + + p = "//rootname/dir/filename"; + v.assign(p.begin(), p.end()); +#ifdef __CYGWIN__ + v2 = { "//rootname", "/", "dir", "filename" }; +#else + v2 = { "/", "rootname", "dir", "filename" }; +#endif + VERIFY( v == v2 ); +} + +void +test02() +{ + using reverse_iterator = std::reverse_iterator; + std::vector fwd, rev; + + for (const path& p : __gnu_test::test_paths) + { + const auto begin = p.begin(), end = p.end(); + fwd.assign(begin, end); + rev.assign(reverse_iterator(end), reverse_iterator(begin)); + VERIFY( fwd.size() == rev.size() ); + VERIFY( std::equal(fwd.begin(), fwd.end(), rev.rbegin()) ); + } +} + +void +test03() +{ + path paths[] = { "single", "multiple/elements" }; + for (const path& p : paths) + for (auto iter = p.begin(); iter != p.end(); ++iter) + { + auto iter2 = iter; + ++iter; + iter2++; + VERIFY( iter2 == iter ); + --iter; + iter2--; + VERIFY( iter2 == iter ); + } +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc new file mode 100644 index 00000000000..31d984f1aa0 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc @@ -0,0 +1,46 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.5 path modifiers [path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (path p : __gnu_test::test_paths) + { + path empty; + p.clear(); + VERIFY( p.empty() ); + __gnu_test::compare_paths(p, empty); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc new file mode 100644 index 00000000000..1df10093777 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc @@ -0,0 +1,64 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.5 path modifiers [path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +template +struct checker +{ + static void check(const char* s) { } +}; + +template<> +struct checker +{ + static void check() + { + VERIFY( path("foo/bar").make_preferred() == "foo/bar" ); + } +}; + +template<> +struct checker +{ + static void check() + { + VERIFY( path("foo/bar").make_preferred() == L"foo\\bar" ); + } +}; + +void +test01() +{ + checker::check(); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc new file mode 100644 index 00000000000..02e1b05cd41 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc @@ -0,0 +1,62 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + // C++17 [fs.path.modifiers] p8 + VERIFY( path("foo/bar").remove_filename() == "foo/" ); + VERIFY( path("foo/").remove_filename() == "foo/" ); + VERIFY( path("/foo").remove_filename() == "/" ); + VERIFY( path("/").remove_filename() == "/" ); +} + +#undef VERIFY +#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false) +#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false) + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path p2(p); + p2.remove_filename(); + p2 /= p.filename(); + VERIFY( p2 == p ); + DUMP( p2 , p ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc new file mode 100644 index 00000000000..cf7ca094c0f --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc @@ -0,0 +1,53 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.5 path modifiers [path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( path("/foo.txt").replace_extension("cpp") == "/foo.cpp" ); + VERIFY( path("/foo.txt").replace_extension(".cpp") == "/foo.cpp" ); + VERIFY( path("/").replace_extension("bar") == "/.bar" ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path p2 = p; + VERIFY(p2.replace_extension(p2.extension()) == p); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc new file mode 100644 index 00000000000..6d3b9b70d07 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc @@ -0,0 +1,59 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + // C++17 [fs.path.modifiers] p11 + VERIFY( path("/foo").replace_filename("bar") == "/bar" ); + VERIFY( path("/").replace_filename("bar") == "/bar" ); +} + +#undef VERIFY +#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false) +#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false) + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path p2(p); + p2.replace_filename(p.filename()); + VERIFY( p2 == p ); + DUMP( p2 , p ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc new file mode 100644 index 00000000000..f1276042a95 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc @@ -0,0 +1,45 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.5 path modifiers [path.modifiers] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + const path p("/foo/bar"); + path p1; + path p2 = p; + p1.swap(p2); + VERIFY( p2.empty() ); + __gnu_test::compare_paths(p1, p); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc new file mode 100644 index 00000000000..23d79700d97 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc @@ -0,0 +1,70 @@ +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +void +test01() +{ + using namespace std::filesystem; + const std::string s = "abc"; + path p(s); + + VERIFY( p.native() == s ); + VERIFY( p.c_str() == s ); + VERIFY( static_cast(p) == s ); + + std::string s2 = p; // implicit conversion + VERIFY( s2 == p.native() ); +} + +void +test02() +{ + using namespace std::filesystem; + const char* s = "abc"; + path p(s); + + auto str = p.string(); + VERIFY( str == u"abc" ); + VERIFY( str == p.string() ); + + auto strw = p.string(); + VERIFY( strw == L"abc" ); + VERIFY( strw == p.wstring() ); + + auto str16 = p.string(); + VERIFY( str16 == u"abc" ); + VERIFY( str16 == p.u16string() ); + + auto str32 = p.string(); + VERIFY( str32 == U"abc" ); + VERIFY( str32 == p.u32string() ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc new file mode 100644 index 00000000000..20f42ac6ee5 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc @@ -0,0 +1,52 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.6 path non-member functions [path.non-member] + +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + VERIFY( hash_value(path("a//b")) == hash_value(path("a/b")) ); + VERIFY( hash_value(path("a/")) == hash_value(path("a//")) ); +} + +void +test02() +{ + for (const path& p : __gnu_test::test_paths) + { + path pp = p.native(); + VERIFY( hash_value(p) == hash_value(pp) ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc new file mode 100644 index 00000000000..76277a0c9ff --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const std::string& s : __gnu_test::test_paths) + { + VERIFY( s.empty() == path(s).empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc new file mode 100644 index 00000000000..693bd389dcd --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_extension() == !p.extension().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc new file mode 100644 index 00000000000..ce99af3025f --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_filename() == !p.filename().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc new file mode 100644 index 00000000000..4e23b249607 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_parent_path() == !p.parent_path().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc new file mode 100644 index 00000000000..25e2dd5ea29 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_relative_path() == !p.relative_path().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc new file mode 100644 index 00000000000..66c8df20976 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_root_directory() == !p.root_directory().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc new file mode 100644 index 00000000000..f9d7157d646 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_root_name() == !p.root_name().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc new file mode 100644 index 00000000000..f0bdb8156c6 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_root_path() == !p.root_path().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc new file mode 100644 index 00000000000..18bf0159825 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.has_stem() == !p.stem().empty() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc new file mode 100644 index 00000000000..c6f6c7f98b1 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++17 -lstdc++fs" } +// { dg-do run { target c++17 } } +// { dg-require-filesystem-ts "" } + +// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 8.4.9 path decomposition [path.decompose] + +#include +#include +#include +#include + +using std::filesystem::path; + +void +test01() +{ + for (const path& p : __gnu_test::test_paths) + { + VERIFY( p.is_relative() == !p.is_absolute() ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc index fbf8bd4d6d3..6879909c777 100644 --- a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc +++ b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc @@ -24,6 +24,7 @@ #include #include #include +#define USE_FILESYSTEM_TS #include using std::experimental::filesystem::path; diff --git a/libstdc++-v3/testsuite/util/testsuite_fs.h b/libstdc++-v3/testsuite/util/testsuite_fs.h index 38ebd4fb079..e0db46ca156 100644 --- a/libstdc++-v3/testsuite/util/testsuite_fs.h +++ b/libstdc++-v3/testsuite/util/testsuite_fs.h @@ -22,7 +22,14 @@ #ifndef _TESTSUITE_FS_H #define _TESTSUITE_FS_H 1 +// Assume we want std::filesystem in C++17, unless USE_FILESYSTEM_TS defined: +#if __cplusplus >= 201703L && ! defined USE_FILESYSTEM_TS +#include +namespace test_fs = std::filesystem; +#else #include +namespace test_fs = std::experimental::filesystem; +#endif #include #include #include @@ -33,12 +40,12 @@ namespace __gnu_test { #define PATH_CHK(p1, p2, fn) \ if ( p1.fn() != p2.fn() ) \ - throw std::experimental::filesystem::filesystem_error( #fn, p1, p2, \ + throw test_fs::filesystem_error( #fn, p1, p2, \ std::make_error_code(std::errc::invalid_argument) ) void - compare_paths(const std::experimental::filesystem::path& p1, - const std::experimental::filesystem::path& p2) + compare_paths(const test_fs::path& p1, + const test_fs::path& p2) { PATH_CHK( p1, p2, string ); PATH_CHK( p1, p2, empty ); @@ -55,7 +62,7 @@ namespace __gnu_test auto d1 = std::distance(p1.begin(), p1.end()); auto d2 = std::distance(p2.begin(), p2.end()); if( d1 != d2 ) - throw std::experimental::filesystem::filesystem_error( + throw test_fs::filesystem_error( "distance(begin, end)", p1, p2, std::make_error_code(std::errc::invalid_argument) ); } @@ -67,15 +74,15 @@ namespace __gnu_test // 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. - std::experimental::filesystem::path + test_fs::path nonexistent_path() { - std::experimental::filesystem::path p; + test_fs::path p; #if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L - char tmp[] = "filesystem-ts-test.XXXXXX"; + char tmp[] = "filesystem-test.XXXXXX"; int fd = ::mkstemp(tmp); if (fd == -1) - throw std::experimental::filesystem::filesystem_error("mkstemp failed", + throw test_fs::filesystem_error("mkstemp failed", std::error_code(errno, std::generic_category())); ::unlink(tmp); ::close(fd); @@ -88,7 +95,7 @@ namespace __gnu_test #else std::sprintf(buf, #endif - "filesystem-ts-test.%d.%lu", counter++, (unsigned long) ::getpid()); + "filesystem-test.%d.%lu", counter++, (unsigned long) ::getpid()); p = buf; #endif return p; @@ -97,7 +104,7 @@ namespace __gnu_test // RAII helper to remove a file on scope exit. struct scoped_file { - using path_type = std::experimental::filesystem::path; + using path_type = test_fs::path; enum adopt_file_t { adopt_file };