diff options
author | AlexSm <alex@ydb.tech> | 2023-12-27 23:31:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-27 23:31:58 +0100 |
commit | d67bfb4b4b7549081543e87a31bc6cb5c46ac973 (patch) | |
tree | 8674f2f1570877cb653e7ddcff37ba00288de15a /contrib/restricted/boost/filesystem | |
parent | 1f6bef05ed441c3aa2d565ac792b26cded704ac7 (diff) | |
download | ydb-d67bfb4b4b7549081543e87a31bc6cb5c46ac973.tar.gz |
Import libs 4 (#758)
Diffstat (limited to 'contrib/restricted/boost/filesystem')
15 files changed, 3144 insertions, 1829 deletions
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp index 68d0557fb4..cf7584a790 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp @@ -1,7 +1,7 @@ // boost/filesystem/v3/config.hpp ----------------------------------------------------// // Copyright Beman Dawes 2003 -// Copyright Andrey Semashev 2021 +// Copyright Andrey Semashev 2021-2023 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -67,6 +67,15 @@ #error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support #endif +// Deprecated symbols markup -----------------------------------------------------------// + +#if !defined(BOOST_FILESYSTEM_ALLOW_DEPRECATED) +#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg) BOOST_DEPRECATED(msg) +#else +#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg) +#endif + + // This header implements separate compilation features as described in // http://www.boost.org/more/separate_compilation.html @@ -122,4 +131,22 @@ #include <boost/config/auto_link.hpp> #endif // auto-linking disabled +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) ||\ + (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 50000)) ||\ + (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION < 100)) +// Indicates that the standard library fstream types do not support move constructor/assignment. +#define BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS +#endif + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) && \ + (\ + (defined(BOOST_DINKUMWARE_STDLIB) && defined(_HAS_CXX23) && (_HAS_CXX23 != 0) && defined(_MSVC_STL_UPDATE) && (_MSVC_STL_UPDATE < 202208L)) || \ + (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 110400 || (BOOST_LIBSTDCXX_VERSION >= 120000 && BOOST_LIBSTDCXX_VERSION < 120200)) && (BOOST_CXX_VERSION > 202002L))\ + ) +// Indicates that std::string_view has implicit constructor from ranges that was present in an early C++23 draft (N4892). +// This was later rectified by marking the constructor explicit (https://wg21.link/p2499). Unfortunately, some compilers +// were released with the constructor being implicit. +#define BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR +#endif + #endif // BOOST_FILESYSTEM_CONFIG_HPP diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp index 10f49a658e..f98b0aba95 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp @@ -28,6 +28,10 @@ #pragma warning(disable: 4503) // 'X': This function or variable may be unsafe. Consider using Y instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #pragma warning(disable: 4996) +// qualifier applied to function type has no meaning; ignored +#pragma warning(disable: 4180) +// qualifier applied to reference type; ignored +#pragma warning(disable: 4181) #elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) @@ -40,6 +44,11 @@ // unused function 'foo' #pragma GCC diagnostic ignored "-Wunused-function" +#if defined(__clang__) +// template argument uses unnamed type +#pragma clang diagnostic ignored "-Wunnamed-type-template-args" +#endif // defined(__clang__) + #endif #endif // !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS) diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp new file mode 100644 index 0000000000..562b96764e --- /dev/null +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp @@ -0,0 +1,737 @@ +// filesystem path_traits.hpp --------------------------------------------------------// + +// Copyright Beman Dawes 2009 +// Copyright Andrey Semashev 2022 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP +#define BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP + +#include <boost/filesystem/config.hpp> +#include <cstddef> +#include <cstring> // for strlen +#include <cwchar> // for mbstate_t, wcslen +#include <locale> +#include <string> +#include <iterator> +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include <string_view> +#endif +#include <boost/assert.hpp> +#include <boost/system/error_category.hpp> +#include <boost/iterator/is_iterator.hpp> +#include <boost/type_traits/declval.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/integral_constant.hpp> +#include <boost/type_traits/conjunction.hpp> +#if defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) +#include <boost/type_traits/disjunction.hpp> +#include <boost/core/enable_if.hpp> +#endif +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 +#include <vector> +#include <list> +#endif + +#include <boost/filesystem/detail/header.hpp> // must be the last #include + +namespace boost { + +template< typename, typename > class basic_string_view; + +namespace container { +template< typename, typename, typename > class basic_string; +} // namespace container + +namespace filesystem { + +BOOST_FILESYSTEM_DECL system::error_category const& codecvt_error_category() BOOST_NOEXCEPT; + +class directory_entry; + +namespace detail { +namespace path_traits { + +#if defined(BOOST_WINDOWS_API) +typedef wchar_t path_native_char_type; +#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE false +#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE true +#else +typedef char path_native_char_type; +#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE true +#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE false +#endif + +typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type; + +struct unknown_type_tag {}; +struct ntcts_type_tag {}; +struct char_ptr_tag : ntcts_type_tag {}; +struct char_array_tag : ntcts_type_tag {}; +struct string_class_tag {}; +struct std_string_tag : string_class_tag {}; +struct boost_container_string_tag : string_class_tag {}; +struct std_string_view_tag : string_class_tag {}; +struct boost_string_view_tag : string_class_tag {}; +struct range_type_tag {}; +struct directory_entry_tag {}; + +//! The traits define a number of properties of a path source +template< typename T > +struct path_source_traits +{ + //! The kind of the path source. Useful for dispatching. + typedef unknown_type_tag tag_type; + //! Character type that the source contains + typedef void char_type; + //! Indicates whether the source is natively supported by \c path::string_type as arguments for constructors/assignment/appending + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< char* > +{ + typedef char_ptr_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< const char* > +{ + typedef char_ptr_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< wchar_t* > +{ + typedef char_ptr_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< const wchar_t* > +{ + typedef char_ptr_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< char[] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< const char[] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< wchar_t[] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< const wchar_t[] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< char[N] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< const char[N] > +{ + typedef char_array_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< wchar_t[N] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< std::size_t N > +struct path_source_traits< const wchar_t[N] > +{ + typedef char_array_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< std::string > +{ + typedef std_string_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< std::wstring > +{ + typedef std_string_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +template< > +struct path_source_traits< boost::container::basic_string< char, std::char_traits< char >, void > > +{ + typedef boost_container_string_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > > +{ + typedef boost_container_string_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< > +struct path_source_traits< std::string_view > +{ + typedef std_string_view_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; +}; + +template< > +struct path_source_traits< std::wstring_view > +{ + typedef std_string_view_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; +}; + +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< > +struct path_source_traits< boost::basic_string_view< char, std::char_traits< char > > > +{ + typedef boost_string_view_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct path_source_traits< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > > +{ + typedef boost_string_view_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::vector< char > > +{ + // Since C++11 this could be string_class_tag as std::vector gained data() member + typedef range_type_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::vector< wchar_t > > +{ + // Since C++11 this could be string_class_tag as std::vector gained data() member + typedef range_type_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::list< char > > +{ + typedef range_type_tag tag_type; + typedef char char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +template< > +struct +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") +path_source_traits< std::list< wchar_t > > +{ + typedef range_type_tag tag_type; + typedef wchar_t char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +template< > +struct path_source_traits< directory_entry > +{ + typedef directory_entry_tag tag_type; + typedef path_native_char_type char_type; + static BOOST_CONSTEXPR_OR_CONST bool is_native = false; +}; + +#undef BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE +#undef BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE + + +//! The trait tests if the type is a known path Source tag +template< typename Tag > +struct is_known_path_source_tag : + public boost::true_type +{ +}; + +template< > +struct is_known_path_source_tag< unknown_type_tag > : + public boost::false_type +{ +}; + +//! The trait tests if the type is compatible with path Source requirements +template< typename T > +struct is_path_source : + public is_known_path_source_tag< typename path_source_traits< T >::tag_type >::type +{ +}; + + +//! The trait indicates whether the type is a path Source that is natively supported by path::string_type as the source for construction/assignment/appending +template< typename T > +struct is_native_path_source : + public boost::integral_constant< bool, path_source_traits< T >::is_native > +{ +}; + + +//! The trait indicates whether the type is one of the supported path character types +template< typename T > +struct is_path_char_type : + public boost::false_type +{ +}; + +template< > +struct is_path_char_type< char > : + public boost::true_type +{ +}; + +template< > +struct is_path_char_type< wchar_t > : + public boost::true_type +{ +}; + + +template< typename Iterator > +struct is_iterator_to_path_chars : + public is_path_char_type< typename std::iterator_traits< Iterator >::value_type >::type +{ +}; + +//! The trait indicates whether the type is an iterator over a sequence of path characters +template< typename Iterator > +struct is_path_source_iterator : + public boost::conjunction< + boost::iterators::is_iterator< Iterator >, + is_iterator_to_path_chars< Iterator > + >::type +{ +}; + + +//! The trait indicates whether the type is a pointer to a sequence of native path characters +template< typename T > +struct is_native_char_ptr : + public boost::false_type +{ +}; + +template< > +struct is_native_char_ptr< path_native_char_type* > : + public boost::true_type +{ +}; + +template< > +struct is_native_char_ptr< const path_native_char_type* > : + public boost::true_type +{ +}; + + +//! Converts character encoding using the supplied codecvt facet. If \a cvt is \c NULL then \c path::codecvt() will be used. +BOOST_FILESYSTEM_DECL +void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt = NULL); + +//! \overload convert +BOOST_FILESYSTEM_DECL +void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt = NULL); + + +// Source dispatch -----------------------------------------------------------------// + +template< typename Source, typename Callback > +typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt = NULL); + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(const char* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag) +{ + return cb(source, source + std::strlen(source), cvt); +} + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(const wchar_t* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag) +{ + return cb(source, source + std::wcslen(source), cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, string_class_tag) +{ + return cb(source.data(), source.data() + source.size(), cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + std::basic_string< typename Source::value_type > src(source.begin(), source.end()); + return cb(src.data(), src.data() + src.size(), cvt); +} + +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< char > const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + const char* data = NULL, *data_end = NULL; + if (!source.empty()) + { + data = &source[0]; + data_end = data + source.size(); + } + return cb(data, data_end, cvt); +} + +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< wchar_t > const& source, Callback cb, const codecvt_type* cvt, range_type_tag) +{ + const wchar_t* data = NULL, *data_end = NULL; + if (!source.empty()) + { + data = &source[0]; + data_end = data + source.size(); + } + return cb(data, data_end, cvt); +} + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 + +// Defined in directory.hpp to avoid circular header dependencies +template< typename Callback > +typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag); + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt) +{ + return path_traits::dispatch(source, cb, cvt, + typename path_traits::path_source_traits< typename boost::remove_cv< Source >::type >::tag_type()); +} + + +typedef char yes_type; +struct no_type { char buf[2]; }; + +#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +namespace is_convertible_to_path_source_impl { + +yes_type check(const char*); +yes_type check(const wchar_t*); +yes_type check(std::string const&); +yes_type check(std::wstring const&); +yes_type check(boost::container::basic_string< char, std::char_traits< char >, void > const&); +yes_type check(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +yes_type check(std::string_view const&); +yes_type check(std::wstring_view const&); +#endif +yes_type check(boost::basic_string_view< char, std::char_traits< char > > const&); +yes_type check(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_path_source_impl + +//! The type trait indicates whether the type has a conversion path to one of the path source types +template< typename T > +struct is_convertible_to_path_source : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_path_source_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +// Note: We use separate checks for convertibility to std::string_view and other types to avoid ambiguity with an implicit range constructor +// of std::string_view in the early C++23 draft (N4892). If a user's type is convertible to e.g. std::string and also satisfies +// ranges::contiguous_range and ranges::sized_range concepts then the conversion is ambiguous: the type is convertible to std::string +// through the conversion operator in the user's class and is also convertible to std::string_view through the implicit conversion +// constructor in std::string_view. The solution is to check convertibility to std::string_view separately first. + +namespace is_convertible_to_std_string_view_impl { + +yes_type check(std::string_view const&); +yes_type check(std::wstring_view const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_std_string_view_impl + +template< typename T > +struct is_convertible_to_std_string_view : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_std_string_view_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +namespace is_convertible_to_path_source_non_std_string_view_impl { + +yes_type check(const char*); +yes_type check(const wchar_t*); +yes_type check(std::string const&); +yes_type check(std::wstring const&); +yes_type check(boost::container::basic_string< char, std::char_traits< char >, void > const&); +yes_type check(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&); +yes_type check(boost::basic_string_view< char, std::char_traits< char > > const&); +yes_type check(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&); +#if !defined(BOOST_NO_CXX11_NULLPTR) +no_type check(std::nullptr_t); +#endif +no_type check(...); + +} // namespace is_convertible_to_path_source_non_std_string_view_impl + +template< typename T > +struct is_convertible_to_path_source_non_std_string_view : + public boost::integral_constant< + bool, + sizeof(is_convertible_to_path_source_non_std_string_view_impl::check(boost::declval< T const& >())) == sizeof(yes_type) + > +{ +}; + +//! The type trait indicates whether the type has a conversion path to one of the path source types +template< typename T > +struct is_convertible_to_path_source : + public boost::disjunction< + is_convertible_to_std_string_view< T >, + is_convertible_to_path_source_non_std_string_view< T > + >::type +{ +}; + +#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +//! The type trait makes \a T dependent on the second template argument. Used to delay type resolution and name binding. +template< typename T, typename > +struct make_dependent +{ + typedef T type; +}; + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< const char*, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< const wchar_t*, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::container::basic_string< char, std::char_traits< char >, void > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::basic_string_view< char, std::char_traits< char > > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl +( + boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const& source, + Callback cb, + const codecvt_type* cvt +) +{ + typedef typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); +} + +#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) +{ + typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename boost::disable_if_c< + is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value, + typename Callback::result_type +>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); +} + +template< typename Source, typename Callback > +BOOST_FORCEINLINE typename boost::enable_if_c< + is_convertible_to_std_string_view< typename boost::remove_cv< Source >::type >::value, + typename Callback::result_type +>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = NULL) +{ + typedef typename boost::remove_cv< Source >::type source_t; + return path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt); +} + +#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) + +} // namespace path_traits +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include <boost/filesystem/detail/footer.hpp> + +#endif // BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp index 68b13638e1..2afcfb6735 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp @@ -4,7 +4,7 @@ // Copyright Jan Langer 2002 // Copyright Dietmar Kuehl 2001 // Copyright Vladimir Prus 2002 -// Copyright Andrey Semashev 2019 +// Copyright Andrey Semashev 2019, 2022 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -19,11 +19,11 @@ #include <boost/filesystem/config.hpp> #include <boost/filesystem/path.hpp> #include <boost/filesystem/file_status.hpp> +#include <boost/filesystem/detail/path_traits.hpp> #include <cstddef> #include <string> #include <vector> -#include <utility> // std::move #include <boost/assert.hpp> #include <boost/core/scoped_enum.hpp> @@ -41,6 +41,17 @@ namespace boost { namespace filesystem { +class directory_iterator; + +namespace detail { + +struct directory_iterator_params; + +BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec); +BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); + +} // namespace detail + //--------------------------------------------------------------------------------------// // // // directory_entry // @@ -53,20 +64,30 @@ namespace filesystem { class directory_entry { + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, detail::directory_iterator_params* params, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec); + public: typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry directory_entry() BOOST_NOEXCEPT {} - explicit directory_entry(boost::filesystem::path const& p) : - m_path(p), m_status(file_status()), m_symlink_status(file_status()) + explicit directory_entry(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + directory_entry(boost::filesystem::path const& p, system::error_code& ec) : + m_path(p) { + refresh_impl(&ec); + if (ec) + m_path.clear(); } - +#else directory_entry(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) : m_path(p), m_status(st), m_symlink_status(symlink_st) { } +#endif directory_entry(directory_entry const& rhs) : m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status) @@ -87,69 +108,349 @@ public: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) directory_entry(directory_entry&& rhs) BOOST_NOEXCEPT : - m_path(std::move(rhs.m_path)), - m_status(std::move(rhs.m_status)), - m_symlink_status(std::move(rhs.m_symlink_status)) + m_path(static_cast< boost::filesystem::path&& >(rhs.m_path)), + m_status(static_cast< file_status&& >(rhs.m_status)), + m_symlink_status(static_cast< file_status&& >(rhs.m_symlink_status)) { } directory_entry& operator=(directory_entry&& rhs) BOOST_NOEXCEPT { - m_path = std::move(rhs.m_path); - m_status = std::move(rhs.m_status); - m_symlink_status = std::move(rhs.m_symlink_status); + m_path = static_cast< boost::filesystem::path&& >(rhs.m_path); + m_status = static_cast< file_status&& >(rhs.m_status); + m_symlink_status = static_cast< file_status&& >(rhs.m_symlink_status); return *this; } + + void assign(boost::filesystem::path&& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path&& p, system::error_code& ec) + { + m_path = static_cast< boost::filesystem::path&& >(p); + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path&& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(static_cast< boost::filesystem::path&& >(p), st, symlink_st); + } #endif +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - void assign(boost::filesystem::path const& p, file_status st = file_status(), file_status symlink_st = file_status()) + void assign(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path const& p, system::error_code& ec) { m_path = p; - m_status = st; - m_symlink_status = symlink_st; + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(p, st, symlink_st); } +#endif + + void replace_filename(boost::filesystem::path const& p); - void replace_filename(boost::filesystem::path const& p, file_status st = file_status(), file_status symlink_st = file_status()) +#if BOOST_FILESYSTEM_VERSION >= 4 + void replace_filename(boost::filesystem::path const& p, system::error_code& ec) { - m_path.remove_filename(); - m_path /= p; - m_status = st; - m_symlink_status = symlink_st; + m_path.replace_filename(p); + refresh_impl(&ec); + } +#else + void replace_filename(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + replace_filename_with_status(p, st, symlink_st); } -#ifndef BOOST_FILESYSTEM_NO_DEPRECATED + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead") void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st) { - replace_filename(p, st, symlink_st); + replace_filename_with_status(p, st, symlink_st); } #endif - boost::filesystem::path const& path() const BOOST_NOEXCEPT + boost::filesystem::path const& path() const BOOST_NOEXCEPT { return m_path; } + operator boost::filesystem::path const&() const BOOST_NOEXCEPT { return m_path; } + + void refresh() { refresh_impl(); } + void refresh(system::error_code& ec) BOOST_NOEXCEPT { refresh_impl(&ec); } + + file_status status() const { - return m_path; + if (!filesystem::status_known(m_status)) + refresh_impl(); + return m_status; + } + + file_status status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_status)) + refresh_impl(&ec); + return m_status; + } + + file_status symlink_status() const + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(); + return m_symlink_status; + } + + file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status; + } + + filesystem::file_type file_type() const + { + if (!filesystem::type_present(m_status)) + refresh_impl(); + return m_status.type(); + } + + filesystem::file_type file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_status)) + refresh_impl(&ec); + return m_status.type(); + } + + filesystem::file_type symlink_file_type() const + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(); + return m_symlink_status.type(); + } + + filesystem::file_type symlink_file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status.type(); + } + + bool exists() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool exists(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool is_regular_file() const + { + return this->file_type() == filesystem::regular_file; + } + + bool is_regular_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::regular_file; + } + + bool is_directory() const + { + return this->file_type() == filesystem::directory_file; + } + + bool is_directory(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::directory_file; + } + + bool is_symlink() const + { + return this->symlink_file_type() == filesystem::symlink_file; + } + + bool is_symlink(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->symlink_file_type(ec) == filesystem::symlink_file; } - operator boost::filesystem::path const&() const BOOST_NOEXCEPT { return m_path; } - file_status status() const { return get_status(); } - file_status status(system::error_code& ec) const BOOST_NOEXCEPT { return get_status(&ec); } - file_status symlink_status() const { return get_symlink_status(); } - file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT { return get_symlink_status(&ec); } - - bool operator==(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path == rhs.m_path; } - bool operator!=(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path != rhs.m_path; } - bool operator<(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path < rhs.m_path; } - bool operator<=(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path <= rhs.m_path; } - bool operator>(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path > rhs.m_path; } - bool operator>=(directory_entry const& rhs) const BOOST_NOEXCEPT { return m_path >= rhs.m_path; } + + bool is_block_file() const + { + return this->file_type() == filesystem::block_file; + } + + bool is_block_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::block_file; + } + + bool is_character_file() const + { + return this->file_type() == filesystem::character_file; + } + + bool is_character_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::character_file; + } + + bool is_fifo() const + { + return this->file_type() == filesystem::fifo_file; + } + + bool is_fifo(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::fifo_file; + } + + bool is_socket() const + { + return this->file_type() == filesystem::socket_file; + } + + bool is_socket(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::socket_file; + } + + bool is_reparse_file() const + { + return this->symlink_file_type() == filesystem::reparse_file; + } + + bool is_reparse_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->symlink_file_type(ec) == filesystem::reparse_file; + } + + bool is_other() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool is_other(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; } + bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; } + bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; } + bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; } + bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; } + bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; } private: - BOOST_FILESYSTEM_DECL file_status get_status(system::error_code* ec = NULL) const; - BOOST_FILESYSTEM_DECL file_status get_symlink_status(system::error_code* ec = NULL) const; + BOOST_FILESYSTEM_DECL void refresh_impl(system::error_code* ec = NULL) const; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + void assign_with_status(boost::filesystem::path&& p, file_status st, file_status symlink_st) + { + m_path = static_cast< boost::filesystem::path&& >(p); + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); + } +#endif + + void assign_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + m_path = p; +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); +#else + m_status = st; + m_symlink_status = symlink_st; +#endif + } + + void replace_filename_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + m_path.replace_filename(p); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + m_status = static_cast< file_status&& >(st); + m_symlink_status = static_cast< file_status&& >(symlink_st); +#else + m_status = st; + m_symlink_status = symlink_st; +#endif + } private: boost::filesystem::path m_path; mutable file_status m_status; // stat()-like mutable file_status m_symlink_status; // lstat()-like -}; // directory_entry +}; + +#if !defined(BOOST_FILESYSTEM_SOURCE) + +inline directory_entry::directory_entry(boost::filesystem::path const& p) : + m_path(p) +{ +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#endif +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +inline void directory_entry::assign(boost::filesystem::path&& p) +{ + m_path = static_cast< boost::filesystem::path&& >(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +inline void directory_entry::assign(boost::filesystem::path const& p) +{ + m_path = p; +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +inline void directory_entry::replace_filename(boost::filesystem::path const& p) +{ + m_path.replace_filename(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +#endif // !defined(BOOST_FILESYSTEM_SOURCE) + +namespace detail { +namespace path_traits { + +// Dispatch function for integration with path class +template< typename Callback > +BOOST_FORCEINLINE typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag) +{ + boost::filesystem::path::string_type const& source = de.path().native(); + return cb(source.data(), source.data() + source.size(), cvt); +} + +} // namespace path_traits +} // namespace detail //--------------------------------------------------------------------------------------// // // @@ -167,70 +468,147 @@ inline file_status status(directory_entry const& e) { return e.status(); } + inline file_status status(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { return e.status(ec); } + +inline file_status symlink_status(directory_entry const& e) +{ + return e.symlink_status(); +} + +inline file_status symlink_status(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.symlink_status(ec); +} + inline bool type_present(directory_entry const& e) { - return filesystem::type_present(e.status()); + return e.file_type() != filesystem::status_error; } + inline bool type_present(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::type_present(e.status(ec)); + return e.file_type(ec) != filesystem::status_error; } + inline bool status_known(directory_entry const& e) { return filesystem::status_known(e.status()); } + inline bool status_known(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { return filesystem::status_known(e.status(ec)); } + inline bool exists(directory_entry const& e) { - return filesystem::exists(e.status()); + return e.exists(); } + inline bool exists(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::exists(e.status(ec)); + return e.exists(ec); } + inline bool is_regular_file(directory_entry const& e) { - return filesystem::is_regular_file(e.status()); + return e.is_regular_file(); } + inline bool is_regular_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::is_regular_file(e.status(ec)); + return e.is_regular_file(ec); } + inline bool is_directory(directory_entry const& e) { - return filesystem::is_directory(e.status()); + return e.is_directory(); } + inline bool is_directory(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::is_directory(e.status(ec)); + return e.is_directory(ec); } + inline bool is_symlink(directory_entry const& e) { - return filesystem::is_symlink(e.symlink_status()); + return e.is_symlink(); } + inline bool is_symlink(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::is_symlink(e.symlink_status(ec)); + return e.is_symlink(ec); +} + +inline bool is_block_file(directory_entry const& e) +{ + return e.is_block_file(); +} + +inline bool is_block_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_block_file(ec); +} + +inline bool is_character_file(directory_entry const& e) +{ + return e.is_character_file(); +} + +inline bool is_character_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_character_file(ec); } + +inline bool is_fifo(directory_entry const& e) +{ + return e.is_fifo(); +} + +inline bool is_fifo(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_fifo(ec); +} + +inline bool is_socket(directory_entry const& e) +{ + return e.is_socket(); +} + +inline bool is_socket(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_socket(ec); +} + +inline bool is_reparse_file(directory_entry const& e) +{ + return e.is_reparse_file(); +} + +inline bool is_reparse_file(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT +{ + return e.is_reparse_file(ec); +} + inline bool is_other(directory_entry const& e) { - return filesystem::is_other(e.status()); + return e.is_other(); } + inline bool is_other(directory_entry const& e, system::error_code& ec) BOOST_NOEXCEPT { - return filesystem::is_other(e.status(ec)); + return e.is_other(ec); } + #ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") inline bool is_regular(directory_entry const& e) { - return filesystem::is_regular(e.status()); + return filesystem::is_regular_file(e); } #endif @@ -243,20 +621,18 @@ inline bool is_regular(directory_entry const& e) BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(directory_options, unsigned int) { none = 0u, - skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty - follow_directory_symlink = 1u << 1, // recursive_directory_iterator: follow directory symlinks - skip_dangling_symlinks = 1u << 2, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks, - pop_on_error = 1u << 3, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors, - // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator - _detail_no_follow = 1u << 4, // internal use only - _detail_no_push = 1u << 5 // internal use only + skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty + follow_directory_symlink = 1u << 1u, // recursive_directory_iterator: follow directory symlinks + skip_dangling_symlinks = 1u << 2u, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks, + pop_on_error = 1u << 3u, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors, + // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator + _detail_no_follow = 1u << 4u, // internal use only + _detail_no_push = 1u << 5u // internal use only } BOOST_SCOPED_ENUM_DECLARE_END(directory_options) BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(directory_options)) -class directory_iterator; - namespace detail { struct dir_itr_imp : @@ -286,11 +662,6 @@ struct dir_itr_imp : BOOST_FILESYSTEM_DECL static void operator delete(void* p) BOOST_NOEXCEPT; }; -struct directory_iterator_params; - -BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec); -BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); - } // namespace detail //--------------------------------------------------------------------------------------// @@ -336,13 +707,13 @@ public: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) directory_iterator(directory_iterator&& that) BOOST_NOEXCEPT : - m_imp(std::move(that.m_imp)) + m_imp(static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp)) { } directory_iterator& operator=(directory_iterator&& that) BOOST_NOEXCEPT { - m_imp = std::move(that.m_imp); + m_imp = static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp); return *this; } #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -540,11 +911,13 @@ public: #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) // Deprecated constructors + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_options instead of symlink_option") recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(symlink_option) opts) { detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), NULL); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_options instead of symlink_option") recursive_directory_iterator(path const& dir_path, BOOST_SCOPED_ENUM_NATIVE(symlink_option) opts, system::error_code& ec) BOOST_NOEXCEPT { detail::recursive_directory_iterator_construct(*this, dir_path, static_cast< unsigned int >(opts), &ec); @@ -556,13 +929,13 @@ public: #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) recursive_directory_iterator(recursive_directory_iterator&& that) BOOST_NOEXCEPT : - m_imp(std::move(that.m_imp)) + m_imp(static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp)) { } recursive_directory_iterator& operator=(recursive_directory_iterator&& that) BOOST_NOEXCEPT { - m_imp = std::move(that.m_imp); + m_imp = static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp); return *this; } #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -586,6 +959,7 @@ public: } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator::depth() instead") int level() const BOOST_NOEXCEPT { return depth(); @@ -614,6 +988,7 @@ public: } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator::disable_recursion_pending() instead") void no_push(bool value = true) BOOST_NOEXCEPT { disable_recursion_pending(value); @@ -664,6 +1039,7 @@ private: }; #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use recursive_directory_iterator instead") typedef recursive_directory_iterator wrecursive_directory_iterator; #endif diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp index 90eca99e84..fb36240127 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp @@ -155,13 +155,13 @@ public: // Note: std::move is not constexpr in C++11, that's why we're not using it here BOOST_CONSTEXPR file_status(file_status&& rhs) BOOST_NOEXCEPT : m_value(static_cast< file_type&& >(rhs.m_value)), - m_perms(static_cast< enum perms&& >(rhs.m_perms)) + m_perms(static_cast< perms&& >(rhs.m_perms)) { } BOOST_CXX14_CONSTEXPR file_status& operator=(file_status&& rhs) BOOST_NOEXCEPT { m_value = static_cast< file_type&& >(rhs.m_value); - m_perms = static_cast< enum perms&& >(rhs.m_perms); + m_perms = static_cast< perms&& >(rhs.m_perms); return *this; } #endif @@ -174,28 +174,28 @@ public: BOOST_CXX14_CONSTEXPR void type(file_type v) BOOST_NOEXCEPT { m_value = v; } BOOST_CXX14_CONSTEXPR void permissions(perms prms) BOOST_NOEXCEPT { m_perms = prms; } - BOOST_CONSTEXPR bool operator==(const file_status& rhs) const BOOST_NOEXCEPT + BOOST_CONSTEXPR bool operator==(file_status const& rhs) const BOOST_NOEXCEPT { return type() == rhs.type() && permissions() == rhs.permissions(); } - BOOST_CONSTEXPR bool operator!=(const file_status& rhs) const BOOST_NOEXCEPT + BOOST_CONSTEXPR bool operator!=(file_status const& rhs) const BOOST_NOEXCEPT { return !(*this == rhs); } private: file_type m_value; - enum perms m_perms; + perms m_perms; }; inline BOOST_CONSTEXPR bool type_present(file_status f) BOOST_NOEXCEPT { - return f.type() != status_error; + return f.type() != filesystem::status_error; } inline BOOST_CONSTEXPR bool permissions_present(file_status f) BOOST_NOEXCEPT { - return f.permissions() != perms_not_known; + return f.permissions() != filesystem::perms_not_known; } inline BOOST_CONSTEXPR bool status_known(file_status f) BOOST_NOEXCEPT @@ -205,22 +205,47 @@ inline BOOST_CONSTEXPR bool status_known(file_status f) BOOST_NOEXCEPT inline BOOST_CONSTEXPR bool exists(file_status f) BOOST_NOEXCEPT { - return f.type() != status_error && f.type() != file_not_found; + return f.type() != filesystem::status_error && f.type() != filesystem::file_not_found; } inline BOOST_CONSTEXPR bool is_regular_file(file_status f) BOOST_NOEXCEPT { - return f.type() == regular_file; + return f.type() == filesystem::regular_file; } inline BOOST_CONSTEXPR bool is_directory(file_status f) BOOST_NOEXCEPT { - return f.type() == directory_file; + return f.type() == filesystem::directory_file; } inline BOOST_CONSTEXPR bool is_symlink(file_status f) BOOST_NOEXCEPT { - return f.type() == symlink_file; + return f.type() == filesystem::symlink_file; +} + +inline BOOST_CONSTEXPR bool is_block_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::block_file; +} + +inline BOOST_CONSTEXPR bool is_character_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::character_file; +} + +inline BOOST_CONSTEXPR bool is_fifo(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::fifo_file; +} + +inline BOOST_CONSTEXPR bool is_socket(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::socket_file; +} + +inline BOOST_CONSTEXPR bool is_reparse_file(file_status f) BOOST_NOEXCEPT +{ + return f.type() == filesystem::reparse_file; } inline BOOST_CONSTEXPR bool is_other(file_status f) BOOST_NOEXCEPT @@ -229,6 +254,7 @@ inline BOOST_CONSTEXPR bool is_other(file_status f) BOOST_NOEXCEPT } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") inline bool is_regular(file_status f) BOOST_NOEXCEPT { return filesystem::is_regular_file(f); diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp index 856de7c1a5..0b7f736878 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp @@ -176,7 +176,7 @@ inline file_status status(path const& p) return detail::status(p); } -inline file_status status(path const& p, system::error_code& ec) +inline file_status status(path const& p, system::error_code& ec) BOOST_NOEXCEPT { return detail::status(p, &ec); } @@ -186,70 +186,122 @@ inline file_status symlink_status(path const& p) return detail::symlink_status(p); } -inline file_status symlink_status(path const& p, system::error_code& ec) +inline file_status symlink_status(path const& p, system::error_code& ec) BOOST_NOEXCEPT { return detail::symlink_status(p, &ec); } inline bool exists(path const& p) { - return exists(detail::status(p)); + return filesystem::exists(detail::status(p)); } -inline bool exists(path const& p, system::error_code& ec) +inline bool exists(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return exists(detail::status(p, &ec)); + return filesystem::exists(detail::status(p, &ec)); +} + +inline bool is_regular_file(path const& p) +{ + return filesystem::is_regular_file(detail::status(p)); +} + +inline bool is_regular_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_regular_file(detail::status(p, &ec)); } inline bool is_directory(path const& p) { - return is_directory(detail::status(p)); + return filesystem::is_directory(detail::status(p)); } -inline bool is_directory(path const& p, system::error_code& ec) +inline bool is_directory(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return is_directory(detail::status(p, &ec)); + return filesystem::is_directory(detail::status(p, &ec)); } -inline bool is_regular_file(path const& p) +inline bool is_symlink(path const& p) { - return is_regular_file(detail::status(p)); + return filesystem::is_symlink(detail::symlink_status(p)); } -inline bool is_regular_file(path const& p, system::error_code& ec) +inline bool is_symlink(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return is_regular_file(detail::status(p, &ec)); + return filesystem::is_symlink(detail::symlink_status(p, &ec)); } -inline bool is_other(path const& p) +inline bool is_block_file(path const& p) { - return is_other(detail::status(p)); + return filesystem::is_block_file(detail::status(p)); } -inline bool is_other(path const& p, system::error_code& ec) +inline bool is_block_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return is_other(detail::status(p, &ec)); + return filesystem::is_block_file(detail::status(p, &ec)); } -inline bool is_symlink(path const& p) +inline bool is_character_file(path const& p) +{ + return filesystem::is_character_file(detail::status(p)); +} + +inline bool is_character_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_character_file(detail::status(p, &ec)); +} + +inline bool is_fifo(path const& p) +{ + return filesystem::is_fifo(detail::status(p)); +} + +inline bool is_fifo(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_fifo(detail::status(p, &ec)); +} + +inline bool is_socket(path const& p) +{ + return filesystem::is_socket(detail::status(p)); +} + +inline bool is_socket(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_socket(detail::status(p, &ec)); +} + +inline bool is_reparse_file(path const& p) +{ + return filesystem::is_reparse_file(detail::symlink_status(p)); +} + +inline bool is_reparse_file(path const& p, system::error_code& ec) BOOST_NOEXCEPT +{ + return filesystem::is_reparse_file(detail::symlink_status(p, &ec)); +} + +inline bool is_other(path const& p) { - return is_symlink(detail::symlink_status(p)); + return filesystem::is_other(detail::status(p)); } -inline bool is_symlink(path const& p, system::error_code& ec) +inline bool is_other(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return is_symlink(detail::symlink_status(p, &ec)); + return filesystem::is_other(detail::status(p, &ec)); } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") inline bool is_regular(path const& p) { - return is_regular(detail::status(p)); + return filesystem::is_regular_file(p); } -inline bool is_regular(path const& p, system::error_code& ec) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_regular_file() instead") +inline bool is_regular(path const& p, system::error_code& ec) BOOST_NOEXCEPT { - return is_regular(detail::status(p, &ec)); + return filesystem::is_regular_file(p, ec); } #endif @@ -347,11 +399,13 @@ inline path canonical(path const& p, path const& base, system::error_code& ec) } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use absolute() instead") inline path complete(path const& p) { return absolute(p, initial_path()); } +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use absolute() instead") inline path complete(path const& p, path const& base) { return absolute(p, base); @@ -379,11 +433,13 @@ inline void copy(path const& from, path const& to, BOOST_SCOPED_ENUM_NATIVE(copy } #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use create_directory() instead") inline void copy_directory(path const& from, path const& to) { detail::copy_directory(from, to); } +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use create_directory() instead") inline void copy_directory(path const& from, path const& to, system::error_code& ec) BOOST_NOEXCEPT { detail::copy_directory(from, to, &ec); @@ -413,12 +469,14 @@ inline bool copy_file(path const& from, path const& to, // See ticket #2925 } #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use copy_options instead of copy_option") inline bool copy_file(path const& from, path const& to, // See ticket #2925 BOOST_SCOPED_ENUM_NATIVE(copy_option) options) { return detail::copy_file(from, to, static_cast< unsigned int >(options)); } +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use copy_options instead of copy_option") inline bool copy_file(path const& from, path const& to, // See ticket #2925 BOOST_SCOPED_ENUM_NATIVE(copy_option) options, system::error_code& ec) BOOST_NOEXCEPT { @@ -646,6 +704,7 @@ inline space_info space(path const& p, system::error_code& ec) BOOST_NOEXCEPT } #ifndef BOOST_FILESYSTEM_NO_DEPRECATED +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use is_symlink(symlink_status(path)) instead") inline bool symbolic_link_exists(path const& p) { return is_symlink(filesystem::symlink_status(p)); diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp index 0554c987a1..729e188125 100644 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp +++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp @@ -2,7 +2,7 @@ // Copyright Vladimir Prus 2002 // Copyright Beman Dawes 2002-2005, 2009 -// Copyright Andrey Semashev 2021 +// Copyright Andrey Semashev 2021-2023 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -18,25 +18,25 @@ #include <boost/assert.hpp> #include <boost/filesystem/config.hpp> -#include <boost/filesystem/path_traits.hpp> // includes <cwchar> +#include <boost/filesystem/detail/path_traits.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_categories.hpp> #include <boost/core/enable_if.hpp> #include <boost/io/quoted.hpp> #include <boost/functional/hash_fwd.hpp> -#include <boost/type_traits/integral_constant.hpp> +#include <boost/type_traits/negation.hpp> +#include <boost/type_traits/conjunction.hpp> +#include <boost/type_traits/disjunction.hpp> #include <boost/type_traits/is_same.hpp> -#include <boost/type_traits/is_integral.hpp> -#include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_cv.hpp> -#include <boost/type_traits/decay.hpp> #include <cstddef> -#include <cwchar> // for mbstate_t -#include <string> #include <iosfwd> -#include <iterator> #include <locale> -#include <utility> +#include <string> +#include <iterator> +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include <string_view> +#endif #include <boost/filesystem/detail/header.hpp> // must be the last #include @@ -69,59 +69,82 @@ BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSepa path_constants< Char, Separator, PreferredSeparator, Dot >::dot; #endif -// A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view. -struct substring +class path_iterator; +class path_reverse_iterator; + +} // namespace path_detail + +namespace detail { + +struct path_algorithms { - std::size_t pos; - std::size_t size; -}; + // A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view. + struct substring + { + std::size_t pos; + std::size_t size; + }; -template< typename T > -struct is_native_char_ptr_impl : public boost::false_type {}; + typedef path_traits::path_native_char_type value_type; + typedef std::basic_string< value_type > string_type; -#if defined(BOOST_WINDOWS_API) -template< > -struct is_native_char_ptr_impl< wchar_t* > : public boost::true_type {}; -template< > -struct is_native_char_ptr_impl< const wchar_t* > : public boost::true_type {}; -#else // defined(BOOST_WINDOWS_API) -template< > -struct is_native_char_ptr_impl< char* > : public boost::true_type {}; -template< > -struct is_native_char_ptr_impl< const char* > : public boost::true_type {}; -#endif // defined(BOOST_WINDOWS_API) + static bool has_filename_v3(path const& p); + static bool has_filename_v4(path const& p); + BOOST_FILESYSTEM_DECL static path filename_v3(path const& p); + static path filename_v4(path const& p); -template< typename T > -struct is_native_char_ptr : public is_native_char_ptr_impl< typename boost::remove_cv< typename boost::remove_reference< T >::type >::type > {}; + BOOST_FILESYSTEM_DECL static path stem_v3(path const& p); + BOOST_FILESYSTEM_DECL static path stem_v4(path const& p); + BOOST_FILESYSTEM_DECL static path extension_v3(path const& p); + static path extension_v4(path const& p); -template< typename T > -struct is_native_pathable_impl : public boost::false_type {}; + BOOST_FILESYSTEM_DECL static void remove_filename_v3(path& p); + BOOST_FILESYSTEM_DECL static void remove_filename_v4(path& p); -template< typename T > -struct is_native_pathable_impl< T* > : public is_native_char_ptr_impl< T* > {}; + BOOST_FILESYSTEM_DECL static void replace_extension_v3(path& p, path const& new_extension); + BOOST_FILESYSTEM_DECL static void replace_extension_v4(path& p, path const& new_extension); -#if defined(BOOST_WINDOWS_API) -template< > -struct is_native_pathable_impl< const wchar_t[] > : public boost::true_type {}; -template< std::size_t N > -struct is_native_pathable_impl< const wchar_t[N] > : public boost::true_type {}; -template< > -struct is_native_pathable_impl< std::basic_string< wchar_t > > : public boost::true_type {}; -#else // defined(BOOST_WINDOWS_API) -template< > -struct is_native_pathable_impl< const char[] > : public boost::true_type {}; -template< std::size_t N > -struct is_native_pathable_impl< const char[N] > : public boost::true_type {}; -template< > -struct is_native_pathable_impl< std::basic_string< char > > : public boost::true_type {}; -#endif // defined(BOOST_WINDOWS_API) -template< > -struct is_native_pathable_impl< filesystem::path > : public boost::true_type {}; + BOOST_FILESYSTEM_DECL static path lexically_normal_v3(path const& p); + BOOST_FILESYSTEM_DECL static path lexically_normal_v4(path const& p); -template< typename T > -struct is_native_pathable : public is_native_pathable_impl< typename boost::remove_cv< typename boost::remove_reference< T >::type >::type > {}; + BOOST_FILESYSTEM_DECL static int compare_v3(path const& left, path const& right); + BOOST_FILESYSTEM_DECL static int compare_v4(path const& left, path const& right); -} // namespace path_detail + BOOST_FILESYSTEM_DECL static void append_v3(path& p, const value_type* b, const value_type* e); + BOOST_FILESYSTEM_DECL static void append_v4(path& p, const value_type* b, const value_type* e); + static void append_v4(path& left, path const& right); + + // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. + // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. + BOOST_FILESYSTEM_DECL static string_type::size_type append_separator_if_needed(path& p); + BOOST_FILESYSTEM_DECL static void erase_redundant_separator(path& p, string_type::size_type sep_pos); + + BOOST_FILESYSTEM_DECL static string_type::size_type find_root_name_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_root_path_size(path const& p); + BOOST_FILESYSTEM_DECL static substring find_root_directory(path const& p); + BOOST_FILESYSTEM_DECL static substring find_relative_path(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_parent_path_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_filename_v4_size(path const& p); + BOOST_FILESYSTEM_DECL static string_type::size_type find_extension_v4_size(path const& p); + + BOOST_FILESYSTEM_DECL static int lex_compare_v3 + ( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 + ); + BOOST_FILESYSTEM_DECL static int lex_compare_v4 + ( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 + ); + + BOOST_FILESYSTEM_DECL static void increment_v3(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void increment_v4(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v3(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v4(path_detail::path_iterator& it); +}; + +} // namespace detail //------------------------------------------------------------------------------------// // // @@ -132,19 +155,23 @@ struct is_native_pathable : public is_native_pathable_impl< typename boost::remo class path : public filesystem::path_detail::path_constants< #ifdef BOOST_WINDOWS_API - wchar_t, L'/', L'\\', L'.' + detail::path_traits::path_native_char_type, L'/', L'\\', L'.' #else - char, '/', '/', '.' + detail::path_traits::path_native_char_type, '/', '/', '.' #endif > { + friend class path_detail::path_iterator; + friend class path_detail::path_reverse_iterator; + friend struct detail::path_algorithms; + public: // value_type is the character type used by the operating system API to // represent paths. - typedef path_constants_base::value_type value_type; - typedef std::basic_string< value_type > string_type; - typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type; + typedef detail::path_algorithms::value_type value_type; + typedef detail::path_algorithms::string_type string_type; + typedef detail::path_traits::codecvt_type codecvt_type; // ----- character encoding conversions ----- @@ -201,131 +228,302 @@ public: // that actually depend on locale(""). It further ensures that exceptions thrown // as a result of such failues occur after main() has started, so can be caught. +private: + //! Assignment operation + class assign_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit assign_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.m_pathname.assign(source, source_end); + } + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + m_self.m_pathname.clear(); + detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt); + } + }; + + //! Concatenation operation + class concat_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit concat_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.m_pathname.append(source, source_end); + } + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt); + } + }; + + //! Path appending operation + class append_op + { + private: + path& m_self; + + public: + typedef void result_type; + + explicit append_op(path& self) BOOST_NOEXCEPT : m_self(self) {} + + BOOST_FORCEINLINE result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const + { + m_self.append(source, source_end); + } + + template< typename OtherChar > + BOOST_FORCEINLINE result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const + { + string_type src; + detail::path_traits::convert(source, source_end, src, cvt); + m_self.append(src.data(), src.data() + src.size()); + } + }; + + //! Path comparison operation + class compare_op + { + private: + path const& m_self; + + public: + typedef int result_type; + + explicit compare_op(path const& self) BOOST_NOEXCEPT : m_self(self) {} + + result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = NULL) const; + + template< typename OtherChar > + result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = NULL) const; + }; + +public: + typedef path_detail::path_iterator iterator; + typedef iterator const_iterator; + typedef path_detail::path_reverse_iterator reverse_iterator; + typedef reverse_iterator const_reverse_iterator; + +public: // ----- constructors ----- path() BOOST_NOEXCEPT {} path(path const& p) : m_pathname(p.m_pathname) {} + path(path const& p, codecvt_type const&) : m_pathname(p.m_pathname) {} - template< class Source > + path(const value_type* s) : m_pathname(s) {} + path(const value_type* s, codecvt_type const&) : m_pathname(s) {} + path(string_type const& s) : m_pathname(s) {} + path(string_type const& s, codecvt_type const&) : m_pathname(s) {} +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + path(std::basic_string_view< value_type > const& s) : m_pathname(s) {} + path(std::basic_string_view< value_type > const& s, codecvt_type const&) : m_pathname(s) {} +#endif + +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename Source, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type + > + path(Source const& source) +#else + template< typename Source > path(Source const& source, typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value >::type* = NULL) +#endif { - path_traits::dispatch(source, m_pathname); + assign(source); } - path(const value_type* s) : m_pathname(s) {} - path(string_type const& s) : m_pathname(s) {} +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename Source, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type + > + explicit path(Source const& source, codecvt_type const& cvt) +#else + template< typename Source > + explicit path(Source const& source, codecvt_type const& cvt, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_native_path_source< typename boost::remove_cv< Source >::type > > + >::value + >::type* = NULL) +#endif + { + assign(source, cvt); + } // As of October 2015 the interaction between noexcept and =default is so troublesome // for VC++, GCC, and probably other compilers, that =default is not used with noexcept // functions. GCC is not even consistent for the same release on different platforms. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - path(path&& p) BOOST_NOEXCEPT : m_pathname(std::move(p.m_pathname)) + path(path&& p) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(p.m_pathname)) { } - path(path&& p, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(std::move(p.m_pathname)) + path(path&& p, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(p.m_pathname)) { } path& operator=(path&& p) BOOST_NOEXCEPT { - m_pathname = std::move(p.m_pathname); + m_pathname = static_cast< string_type&& >(p.m_pathname); return *this; } path& assign(path&& p) BOOST_NOEXCEPT { - m_pathname = std::move(p.m_pathname); + m_pathname = static_cast< string_type&& >(p.m_pathname); return *this; } path& assign(path&& p, codecvt_type const&) BOOST_NOEXCEPT { - m_pathname = std::move(p.m_pathname); + m_pathname = static_cast< string_type&& >(p.m_pathname); return *this; } - path(string_type&& s) BOOST_NOEXCEPT : m_pathname(std::move(s)) + path(string_type&& s) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(s)) { } - path(string_type&& s, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(std::move(s)) + path(string_type&& s, codecvt_type const&) BOOST_NOEXCEPT : m_pathname(static_cast< string_type&& >(s)) { } path& operator=(string_type&& p) BOOST_NOEXCEPT { - m_pathname = std::move(p); + m_pathname = static_cast< string_type&& >(p); return *this; } path& assign(string_type&& p) BOOST_NOEXCEPT { - m_pathname = std::move(p); + m_pathname = static_cast< string_type&& >(p); return *this; } path& assign(string_type&& p, codecvt_type const&) BOOST_NOEXCEPT { - m_pathname = std::move(p); + m_pathname = static_cast< string_type&& >(p); return *this; } #endif - path(path const& p, codecvt_type const&) : m_pathname(p.m_pathname) {} - path(const value_type* s, codecvt_type const&) : m_pathname(s) {} - path(string_type const& s, codecvt_type const&) : m_pathname(s) {} - - template< class Source > - path(Source const& source, codecvt_type const& cvt, typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value - >::type* = NULL) - { - path_traits::dispatch(source, m_pathname, cvt); - } - path(const value_type* begin, const value_type* end) : m_pathname(begin, end) {} + path(const value_type* begin, const value_type* end, codecvt_type const&) : m_pathname(begin, end) {} - template< class InputIterator > - path(InputIterator begin, InputIterator end, typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator > >::type* = NULL) +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename InputIterator, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type + > + path(InputIterator begin, InputIterator end) +#else + template< typename InputIterator > + path(InputIterator begin, InputIterator end, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type* = NULL) +#endif { if (begin != end) { - // convert requires contiguous string, so copy - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname); + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source)); +#else + assign(source); +#endif } } - path(const value_type* begin, const value_type* end, codecvt_type const&) : m_pathname(begin, end) {} - - template< class InputIterator > - path(InputIterator begin, InputIterator end, codecvt_type const& cvt, typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator > >::type* = NULL) +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< + typename InputIterator, + typename = typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type + > + path(InputIterator begin, InputIterator end, codecvt_type const& cvt) +#else + template< typename InputIterator > + path(InputIterator begin, InputIterator end, codecvt_type const& cvt, typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value + >::type* = NULL) +#endif { if (begin != end) { - // convert requires contiguous string, so copy - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname, cvt); + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source), cvt); +#else + assign(source, cvt); +#endif } } +#if !defined(BOOST_NO_CXX11_NULLPTR) + BOOST_DELETED_FUNCTION(path(std::nullptr_t)) + BOOST_DELETED_FUNCTION(path& operator= (std::nullptr_t)) +#endif + +public: // ----- assignments ----- // We need to explicitly define copy assignment as otherwise it will be implicitly defined as deleted because there is move assignment - path& operator=(path const& p) - { - return assign(p); - } - - path& operator=(string_type const& s) - { - return assign(s); - } - - path& operator=(const value_type* ptr) - { - return assign(ptr); - } + path& operator=(path const& p); - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + boost::disjunction< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, path& >::type operator=(Source const& source) { @@ -338,26 +536,26 @@ public: return *this; } - path& assign(string_type const& s) - { - m_pathname = s; - return *this; - } - - path& assign(const value_type* ptr) + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type assign(Source const& source) { - m_pathname = ptr; + detail::path_traits::dispatch(source, assign_op(*this)); return *this; } - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type assign(Source const& source) { - m_pathname.clear(); - path_traits::dispatch(source, m_pathname); + detail::path_traits::dispatch_convertible(source, assign_op(*this)); return *this; } @@ -367,26 +565,26 @@ public: return *this; } - path& assign(string_type const& s, codecvt_type const&) - { - m_pathname = s; - return *this; - } - - path& assign(const value_type* ptr, codecvt_type const&) + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type assign(Source const& source, codecvt_type const& cvt) { - m_pathname = ptr; + detail::path_traits::dispatch(source, assign_op(*this), &cvt); return *this; } - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type assign(Source const& source, codecvt_type const& cvt) { - m_pathname.clear(); - path_traits::dispatch(source, m_pathname, cvt); + detail::path_traits::dispatch_convertible(source, assign_op(*this), &cvt); return *this; } @@ -396,15 +594,25 @@ public: return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - assign(InputIterator begin, InputIterator end) + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type assign(InputIterator begin, InputIterator end) { m_pathname.clear(); if (begin != end) { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname); + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source)); +#else + assign(source); +#endif } return *this; } @@ -415,39 +623,36 @@ public: return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - assign(InputIterator begin, InputIterator end, codecvt_type const& cvt) + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type assign(InputIterator begin, InputIterator end, codecvt_type const& cvt) { m_pathname.clear(); if (begin != end) { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname, cvt); + typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + source_t source(begin, end); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + assign(static_cast< source_t&& >(source), cvt); +#else + assign(source, cvt); +#endif } return *this; } // ----- concatenation ----- - path& operator+=(path const& p) - { - return concat(p); - } - - path& operator+=(const value_type* ptr) - { - return concat(ptr); - } + path& operator+=(path const& p); - path& operator+=(string_type const& s) - { - return concat(s); - } - - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, path& >::type operator+=(Source const& source) { @@ -460,69 +665,74 @@ public: return *this; } - template< class CharT > - typename boost::enable_if< boost::is_integral< CharT >, path& >::type - operator+=(CharT c) + template< typename CharT > + typename boost::enable_if_c< + detail::path_traits::is_path_char_type< CharT >::value, + path& + >::type operator+=(CharT c) { CharT tmp[2]; tmp[0] = c; tmp[1] = static_cast< CharT >(0); - return concat(tmp); - } - - path& concat(path const& p) - { - m_pathname += p.m_pathname; + concat_op(*this)(tmp, tmp + 1); return *this; } - path& concat(const value_type* ptr) + path& concat(path const& p) { - m_pathname += ptr; + m_pathname.append(p.m_pathname); return *this; } - path& concat(string_type const& s) + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type concat(Source const& source) { - m_pathname += s; + detail::path_traits::dispatch(source, concat_op(*this)); return *this; } - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type concat(Source const& source) { - path_traits::dispatch(source, m_pathname); + detail::path_traits::dispatch_convertible(source, concat_op(*this)); return *this; } path& concat(path const& p, codecvt_type const&) { - m_pathname += p.m_pathname; + m_pathname.append(p.m_pathname); return *this; } - path& concat(const value_type* ptr, codecvt_type const&) - { - m_pathname += ptr; - return *this; - } - - path& concat(string_type const& s, codecvt_type const&) + template< typename Source > + typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type concat(Source const& source, codecvt_type const& cvt) { - m_pathname += s; + detail::path_traits::dispatch(source, concat_op(*this), &cvt); return *this; } - template< class Source > + template< typename Source > typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type concat(Source const& source, codecvt_type const& cvt) { - path_traits::dispatch(source, m_pathname, cvt); + detail::path_traits::dispatch_convertible(source, concat_op(*this), &cvt); return *this; } @@ -532,14 +742,19 @@ public: return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - concat(InputIterator begin, InputIterator end) + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type concat(InputIterator begin, InputIterator end) { if (begin != end) { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname); + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, concat_op(*this)); } return *this; } @@ -550,14 +765,19 @@ public: return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - concat(InputIterator begin, InputIterator end, codecvt_type const& cvt) + template< typename InputIterator > + typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type concat(InputIterator begin, InputIterator end, codecvt_type const& cvt) { if (begin != end) { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), m_pathname, cvt); + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, concat_op(*this), &cvt); } return *this; } @@ -567,124 +787,97 @@ public: // if a separator is added, it is the preferred separator for the platform; // slash for POSIX, backslash for Windows - path& operator/=(path const& p) - { - return append(p); - } + path& operator/=(path const& p); - path& operator/=(const value_type* ptr) - { - return append(ptr); - } - - path& operator/=(string_type const& s) - { - return append(s); - } - - template< class Source > + template< typename Source > BOOST_FORCEINLINE typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, path& >::type operator/=(Source const& source) { return append(source); } - BOOST_FORCEINLINE path& append(path const& p) - { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(p); - return *this; - } - - BOOST_FORCEINLINE path& append(string_type const& p) - { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.c_str(), p.c_str() + p.size()); - return *this; - } + path& append(path const& p); - BOOST_FORCEINLINE path& append(const value_type* ptr) + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type append(Source const& source) { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(ptr, ptr + string_type::traits_type::length(ptr)); + detail::path_traits::dispatch(source, append_op(*this)); return *this; } - template< class Source > - typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type append(Source const& source) { - path p; - path_traits::dispatch(source, p.m_pathname); - return append(p); - } - - BOOST_FORCEINLINE path& append(path const& p, codecvt_type const&) - { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(p); + detail::path_traits::dispatch_convertible(source, append_op(*this)); return *this; } - BOOST_FORCEINLINE path& append(string_type const& p, codecvt_type const&) - { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.c_str(), p.c_str() + p.size()); - return *this; - } + path& append(path const& p, codecvt_type const&); - BOOST_FORCEINLINE path& append(const value_type* ptr, codecvt_type const&) + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + path& + >::type append(Source const& source, codecvt_type const& cvt) { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(ptr, ptr + string_type::traits_type::length(ptr)); + detail::path_traits::dispatch(source, append_op(*this), &cvt); return *this; } - template< class Source > - typename boost::enable_if_c< - path_traits::is_pathable< typename boost::decay< Source >::type >::value && !path_detail::is_native_pathable< Source >::value, + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, path& >::type append(Source const& source, codecvt_type const& cvt) { - path p; - path_traits::dispatch(source, p.m_pathname, cvt); - return append(p); - } - - BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end) - { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end); + detail::path_traits::dispatch_convertible(source, append_op(*this), &cvt); return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - append(InputIterator begin, InputIterator end) - { - path p; - if (begin != end) - { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), p.m_pathname); - } - return append(p); - } + path& append(const value_type* begin, const value_type* end); - BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end, codecvt_type const&) + template< typename InputIterator > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type append(InputIterator begin, InputIterator end) { - BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end); + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, append_op(*this)); return *this; } - template< class InputIterator > - typename boost::disable_if< path_detail::is_native_char_ptr< InputIterator >, path& >::type - append(InputIterator begin, InputIterator end, const codecvt_type& cvt) + path& append(const value_type* begin, const value_type* end, codecvt_type const&); + + template< typename InputIterator > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_path_source_iterator< InputIterator >, + boost::negation< detail::path_traits::is_native_char_ptr< InputIterator > > + >::value, + path& + >::type append(InputIterator begin, InputIterator end, const codecvt_type& cvt) { - path p; - if (begin != end) - { - std::basic_string< typename std::iterator_traits< InputIterator >::value_type > seq(begin, end); - path_traits::convert(seq.c_str(), seq.c_str() + seq.size(), p.m_pathname, cvt); - } - return append(p); + std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); + detail::path_traits::dispatch(source, append_op(*this), &cvt); + return *this; } // ----- modifiers ----- @@ -699,13 +892,12 @@ public: #else // BOOST_WINDOWS_API BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes #endif - BOOST_FILESYSTEM_DECL path& remove_filename(); + path& remove_filename(); + BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators(); BOOST_FILESYSTEM_DECL path& remove_trailing_separator(); - BOOST_FORCEINLINE path& replace_extension(path const& new_extension = path()) - { - BOOST_FILESYSTEM_VERSIONED_SYM(replace_extension)(new_extension); - return *this; - } + BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement); + path& replace_extension(path const& new_extension = path()); + void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); } // ----- observers ----- @@ -733,10 +925,10 @@ public: const value_type* c_str() const BOOST_NOEXCEPT { return m_pathname.c_str(); } string_type::size_type size() const BOOST_NOEXCEPT { return m_pathname.size(); } - template< class String > + template< typename String > String string() const; - template< class String > + template< typename String > String string(codecvt_type const& cvt) const; #ifdef BOOST_WINDOWS_API @@ -744,14 +936,14 @@ public: { std::string tmp; if (!m_pathname.empty()) - path_traits::convert(m_pathname.c_str(), m_pathname.c_str() + m_pathname.size(), tmp); + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); return tmp; } std::string string(codecvt_type const& cvt) const { std::string tmp; if (!m_pathname.empty()) - path_traits::convert(m_pathname.c_str(), m_pathname.c_str() + m_pathname.size(), tmp, cvt); + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt); return tmp; } @@ -767,14 +959,14 @@ public: { std::wstring tmp; if (!m_pathname.empty()) - path_traits::convert(m_pathname.c_str(), m_pathname.c_str() + m_pathname.size(), tmp); + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); return tmp; } std::wstring wstring(codecvt_type const& cvt) const { std::wstring tmp; if (!m_pathname.empty()) - path_traits::convert(m_pathname.c_str(), m_pathname.c_str() + m_pathname.size(), tmp, cvt); + detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt); return tmp; } #endif @@ -787,13 +979,13 @@ public: #ifdef BOOST_WINDOWS_API BOOST_FILESYSTEM_DECL path generic_path() const; #else - path generic_path() const { return path(*this); } + path generic_path() const; #endif - template< class String > + template< typename String > String generic_string() const; - template< class String > + template< typename String > String generic_string(codecvt_type const& cvt) const; #ifdef BOOST_WINDOWS_API @@ -811,51 +1003,88 @@ public: // ----- compare ----- - BOOST_FORCEINLINE int compare(path const& p) const BOOST_NOEXCEPT // generic, lexicographical + int compare(path const& p) const; // generic, lexicographical + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + int + >::type compare(Source const& source) const + { + return detail::path_traits::dispatch(source, compare_op(*this)); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + int + >::type compare(Source const& source) const { - return BOOST_FILESYSTEM_VERSIONED_SYM(compare)(p); + return detail::path_traits::dispatch_convertible(source, compare_op(*this)); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type >::value, + int + >::type compare(Source const& source, codecvt_type const& cvt) const + { + return detail::path_traits::dispatch(source, compare_op(*this), &cvt); + } + + template< typename Source > + BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >, + boost::negation< detail::path_traits::is_path_source< typename boost::remove_cv< Source >::type > > + >::value, + int + >::type compare(Source const& source, codecvt_type const& cvt) const + { + return detail::path_traits::dispatch_convertible(source, compare_op(*this), &cvt); } - int compare(std::string const& s) const { return compare(path(s)); } - int compare(const value_type* s) const { return compare(path(s)); } // ----- decomposition ----- - path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_root_path_size()); } + path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_path_size(*this)); } // returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths - path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_root_name_size()); } + path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_name_size(*this)); } // returns 0 or 1 element path path root_directory() const { - path_detail::substring root_dir = find_root_directory(); + detail::path_algorithms::substring root_dir = detail::path_algorithms::find_root_directory(*this); const value_type* p = m_pathname.c_str() + root_dir.pos; return path(p, p + root_dir.size); } path relative_path() const { - path_detail::substring root_dir = find_relative_path(); - const value_type* p = m_pathname.c_str() + root_dir.pos; - return path(p, p + root_dir.size); + detail::path_algorithms::substring rel_path = detail::path_algorithms::find_relative_path(*this); + const value_type* p = m_pathname.c_str() + rel_path.pos; + return path(p, p + rel_path.size); } - path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_parent_path_size()); } + path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_parent_path_size(*this)); } - BOOST_FORCEINLINE path filename() const { return BOOST_FILESYSTEM_VERSIONED_SYM(filename)(); } // returns 0 or 1 element path - BOOST_FORCEINLINE path stem() const { return BOOST_FILESYSTEM_VERSIONED_SYM(stem)(); } // returns 0 or 1 element path - BOOST_FORCEINLINE path extension() const { return BOOST_FILESYSTEM_VERSIONED_SYM(extension)(); } // returns 0 or 1 element path + path filename() const; // returns 0 or 1 element path + path stem() const; // returns 0 or 1 element path + path extension() const; // returns 0 or 1 element path // ----- query ----- bool empty() const BOOST_NOEXCEPT { return m_pathname.empty(); } bool filename_is_dot() const; bool filename_is_dot_dot() const; - bool has_root_path() const { return find_root_path_size() > 0; } - bool has_root_name() const { return find_root_name_size() > 0; } - bool has_root_directory() const { return find_root_directory().size > 0; } - bool has_relative_path() const { return find_relative_path().size > 0; } - bool has_parent_path() const { return find_parent_path_size() > 0; } - BOOST_FORCEINLINE bool has_filename() const { return BOOST_FILESYSTEM_VERSIONED_SYM(has_filename)(); } + bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; } + bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; } + bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; } + bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; } + bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; } + bool has_filename() const; bool has_stem() const { return !stem().empty(); } bool has_extension() const { return !extension().empty(); } bool is_relative() const { return !is_absolute(); } @@ -871,22 +1100,12 @@ public: // ----- lexical operations ----- - BOOST_FORCEINLINE path lexically_normal() const { return BOOST_FILESYSTEM_VERSIONED_SYM(lexically_normal)(); } + path lexically_normal() const; BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const; - path lexically_proximate(path const& base) const - { - path tmp(lexically_relative(base)); - return tmp.empty() ? *this : tmp; - } + path lexically_proximate(path const& base) const; // ----- iterators ----- - class iterator; - friend class iterator; - typedef iterator const_iterator; - class reverse_iterator; - typedef reverse_iterator const_reverse_iterator; - BOOST_FILESYSTEM_DECL iterator begin() const; BOOST_FILESYSTEM_DECL iterator end() const; reverse_iterator rbegin() const; @@ -901,29 +1120,37 @@ public: #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) // recently deprecated functions supplied by default - path& normalize() - { - path tmp(lexically_normal()); - m_pathname.swap(tmp.m_pathname); - return *this; - } + path& normalize(); + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::remove_filename() instead") path& remove_leaf() { return remove_filename(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::filename() instead") path leaf() const { return filename(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::parent_path() instead") path branch_path() const { return parent_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::generic_path() instead") path generic() const { return generic_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use !path::empty() instead") bool has_leaf() const { return !m_pathname.empty(); } - bool has_branch_path() const { return !parent_path().empty(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::has_parent_path() instead") + bool has_branch_path() const { return has_parent_path(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::is_absolute() instead") bool is_complete() const { return is_absolute(); } #endif #if defined(BOOST_FILESYSTEM_DEPRECATED) // deprecated functions with enough signature or semantic changes that they are // not supplied by default + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") std::string file_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") std::string directory_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") std::string native_file_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::string() instead") std::string native_directory_string() const { return string(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::native() instead") string_type external_file_string() const { return native(); } + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::native() instead") string_type external_directory_string() const { return native(); } #endif @@ -931,55 +1158,6 @@ public: // class path private members // //--------------------------------------------------------------------------------------// private: - bool has_filename_v3() const { return !m_pathname.empty(); } - bool has_filename_v4() const { return find_filename_v4_size() > 0; } - BOOST_FILESYSTEM_DECL path filename_v3() const; - path filename_v4() const - { - string_type::size_type filename_size = find_filename_v4_size(); - string_type::size_type pos = m_pathname.size() - filename_size; - const value_type* p = m_pathname.c_str() + pos; - return path(p, p + filename_size); - } - BOOST_FILESYSTEM_DECL path stem_v3() const; - BOOST_FILESYSTEM_DECL path stem_v4() const; - BOOST_FILESYSTEM_DECL path extension_v3() const; - path extension_v4() const - { - string_type::size_type extension_size = find_extension_v4_size(); - string_type::size_type pos = m_pathname.size() - extension_size; - const value_type* p = m_pathname.c_str() + pos; - return path(p, p + extension_size); - } - - BOOST_FILESYSTEM_DECL void replace_extension_v3(path const& new_extension); - BOOST_FILESYSTEM_DECL void replace_extension_v4(path const& new_extension); - - BOOST_FILESYSTEM_DECL path lexically_normal_v3() const; - BOOST_FILESYSTEM_DECL path lexically_normal_v4() const; - - BOOST_FILESYSTEM_DECL int compare_v3(path const& p) const BOOST_NOEXCEPT; - BOOST_FILESYSTEM_DECL int compare_v4(path const& p) const BOOST_NOEXCEPT; - - BOOST_FILESYSTEM_DECL void append_v3(const value_type* b, const value_type* e); - BOOST_FILESYSTEM_DECL void append_v4(const value_type* b, const value_type* e); - BOOST_FILESYSTEM_DECL void append_v3(path const& p); - BOOST_FILESYSTEM_DECL void append_v4(path const& p); - - // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. - // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. - BOOST_FILESYSTEM_DECL string_type::size_type append_separator_if_needed(); - BOOST_FILESYSTEM_DECL void erase_redundant_separator(string_type::size_type sep_pos); - - BOOST_FILESYSTEM_DECL string_type::size_type find_root_name_size() const; - BOOST_FILESYSTEM_DECL string_type::size_type find_root_path_size() const; - BOOST_FILESYSTEM_DECL path_detail::substring find_root_directory() const; - BOOST_FILESYSTEM_DECL path_detail::substring find_relative_path() const; - BOOST_FILESYSTEM_DECL string_type::size_type find_parent_path_size() const; - BOOST_FILESYSTEM_DECL string_type::size_type find_filename_v4_size() const; - BOOST_FILESYSTEM_DECL string_type::size_type find_extension_v4_size() const; - -private: /* * m_pathname has the type, encoding, and format required by the native * operating system. Thus for POSIX and Windows there is no conversion for @@ -993,8 +1171,6 @@ private: }; namespace detail { -BOOST_FILESYSTEM_DECL int lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2); -BOOST_FILESYSTEM_DECL int lex_compare_v4(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2); BOOST_FILESYSTEM_DECL path const& dot_path(); BOOST_FILESYSTEM_DECL path const& dot_dot_path(); } // namespace detail @@ -1003,13 +1179,15 @@ BOOST_FILESYSTEM_DECL path const& dot_dot_path(); typedef path wpath; #endif +namespace path_detail { + //------------------------------------------------------------------------------------// // class path::iterator // //------------------------------------------------------------------------------------// -class path::iterator : +class path_iterator : public boost::iterator_facade< - path::iterator, + path_iterator, const path, boost::bidirectional_traversal_tag > @@ -1017,24 +1195,18 @@ class path::iterator : private: friend class boost::iterator_core_access; friend class boost::filesystem::path; - friend class boost::filesystem::path::reverse_iterator; - friend BOOST_FILESYSTEM_DECL int detail::lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2); + friend class path_reverse_iterator; + friend struct boost::filesystem::detail::path_algorithms; path const& dereference() const { return m_element; } - bool equal(iterator const& rhs) const + bool equal(path_iterator const& rhs) const BOOST_NOEXCEPT { return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; } - BOOST_FORCEINLINE void increment() { BOOST_FILESYSTEM_VERSIONED_SYM(increment)(); } - BOOST_FORCEINLINE void decrement() { BOOST_FILESYSTEM_VERSIONED_SYM(decrement)(); } - -private: - BOOST_FILESYSTEM_DECL void increment_v3(); - BOOST_FILESYSTEM_DECL void increment_v4(); - BOOST_FILESYSTEM_DECL void decrement_v3(); - BOOST_FILESYSTEM_DECL void decrement_v4(); + void increment(); + void decrement(); private: // current element @@ -1046,22 +1218,22 @@ private: // position of the last separator in the path. // end() iterator is indicated by // m_pos == m_path_ptr->m_pathname.size() - string_type::size_type m_pos; + path::string_type::size_type m_pos; }; //------------------------------------------------------------------------------------// // class path::reverse_iterator // //------------------------------------------------------------------------------------// -class path::reverse_iterator : +class path_reverse_iterator : public boost::iterator_facade< - path::reverse_iterator, + path_reverse_iterator, const path, boost::bidirectional_traversal_tag > { public: - explicit reverse_iterator(iterator itr) : + explicit path_reverse_iterator(path_iterator itr) : m_itr(itr) { if (itr != itr.m_path_ptr->begin()) @@ -1073,14 +1245,14 @@ private: friend class boost::filesystem::path; path const& dereference() const { return m_element; } - bool equal(reverse_iterator const& rhs) const { return m_itr == rhs.m_itr; } + bool equal(path_reverse_iterator const& rhs) const BOOST_NOEXCEPT { return m_itr == rhs.m_itr; } void increment() { --m_itr; if (m_itr != m_itr.m_path_ptr->begin()) { - iterator tmp = m_itr; + path_iterator tmp = m_itr; m_element = *--tmp; } } @@ -1092,99 +1264,209 @@ private: } private: - iterator m_itr; + path_iterator m_itr; path m_element; }; +// std::lexicographical_compare would infinitely recurse because path iterators +// yield paths, so provide a path aware version +bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2); + +} // namespace path_detail + +using path_detail::lexicographical_compare; + //------------------------------------------------------------------------------------// // // // non-member functions // // // //------------------------------------------------------------------------------------// -// std::lexicographical_compare would infinitely recurse because path iterators -// yield paths, so provide a path aware version -inline bool lexicographical_compare(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2) +BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs) { - return BOOST_FILESYSTEM_VERSIONED_SYM(detail::lex_compare)(first1, last1, first2, last2) < 0; + return lhs.compare(rhs) == 0; } -inline bool operator==(path const& lhs, path const& rhs) +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator==(Path const& lhs, Source const& rhs) { return lhs.compare(rhs) == 0; } -inline bool operator==(path const& lhs, path::string_type const& rhs) +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator==(Source const& lhs, Path const& rhs) { - return lhs.compare(rhs) == 0; + return rhs.compare(lhs) == 0; } -inline bool operator==(path::string_type const& lhs, path const& rhs) +BOOST_FORCEINLINE bool operator!=(path const& lhs, path const& rhs) { - return rhs.compare(lhs) == 0; + return lhs.compare(rhs) != 0; } -inline bool operator==(path const& lhs, const path::value_type* rhs) +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator!=(Path const& lhs, Source const& rhs) { - return lhs.compare(rhs) == 0; + return lhs.compare(rhs) != 0; } -inline bool operator==(const path::value_type* lhs, path const& rhs) +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator!=(Source const& lhs, Path const& rhs) { - return rhs.compare(lhs) == 0; + return rhs.compare(lhs) != 0; } -inline bool operator!=(path const& lhs, path const& rhs) +BOOST_FORCEINLINE bool operator<(path const& lhs, path const& rhs) { - return lhs.compare(rhs) != 0; + return lhs.compare(rhs) < 0; } -inline bool operator!=(path const& lhs, path::string_type const& rhs) +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<(Path const& lhs, Source const& rhs) { - return lhs.compare(rhs) != 0; + return lhs.compare(rhs) < 0; } -inline bool operator!=(path::string_type const& lhs, path const& rhs) +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<(Source const& lhs, Path const& rhs) { - return rhs.compare(lhs) != 0; + return rhs.compare(lhs) > 0; } -inline bool operator!=(path const& lhs, const path::value_type* rhs) +BOOST_FORCEINLINE bool operator<=(path const& lhs, path const& rhs) { - return lhs.compare(rhs) != 0; + return lhs.compare(rhs) <= 0; } -inline bool operator!=(const path::value_type* lhs, path const& rhs) +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<=(Path const& lhs, Source const& rhs) { - return rhs.compare(lhs) != 0; + return lhs.compare(rhs) <= 0; } -// TODO: why do == and != have additional overloads, but the others don't? +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator<=(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) >= 0; +} -inline bool operator<(path const& lhs, path const& rhs) +BOOST_FORCEINLINE bool operator>(path const& lhs, path const& rhs) { - return lhs.compare(rhs) < 0; + return lhs.compare(rhs) > 0; } -inline bool operator<=(path const& lhs, path const& rhs) + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>(Path const& lhs, Source const& rhs) +{ + return lhs.compare(rhs) > 0; +} + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>(Source const& lhs, Path const& rhs) +{ + return rhs.compare(lhs) < 0; +} + +BOOST_FORCEINLINE bool operator>=(path const& lhs, path const& rhs) { - return !(rhs < lhs); + return lhs.compare(rhs) >= 0; } -inline bool operator>(path const& lhs, path const& rhs) + +template< typename Path, typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>=(Path const& lhs, Source const& rhs) { - return rhs < lhs; + return lhs.compare(rhs) >= 0; } -inline bool operator>=(path const& lhs, path const& rhs) + +template< typename Source, typename Path > +BOOST_FORCEINLINE typename boost::enable_if_c< + boost::conjunction< + boost::is_same< Path, path >, + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type > + >::value, + bool +>::type operator>=(Source const& lhs, Path const& rhs) { - return !(lhs < rhs); + return rhs.compare(lhs) <= 0; } + // Note: Declared as a template to delay binding to Boost.ContainerHash functions and make the dependency optional -template< typename T > -inline typename boost::enable_if< boost::is_same< T, path >, std::size_t >::type hash_value(T const& p) BOOST_NOEXCEPT +template< typename Path > +inline typename boost::enable_if_c< + boost::is_same< Path, path >::value, + std::size_t +>::type hash_value(Path const& p) BOOST_NOEXCEPT { #ifdef BOOST_WINDOWS_API std::size_t seed = 0u; - for (typename T::value_type const* it = p.c_str(); *it; ++it) + for (typename Path::value_type const* it = p.c_str(); *it; ++it) hash_combine(seed, *it == L'/' ? L'\\' : *it); return seed; #else // BOOST_POSIX_API @@ -1197,33 +1479,34 @@ inline void swap(path& lhs, path& rhs) BOOST_NOEXCEPT lhs.swap(rhs); } -inline path operator/(path const& lhs, path const& rhs) +BOOST_FORCEINLINE path operator/(path lhs, path const& rhs) { - path p = lhs; - p /= rhs; - return p; + lhs.append(rhs); + return lhs; } -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -inline path operator/(path&& lhs, path const& rhs) +template< typename Source > +BOOST_FORCEINLINE typename boost::enable_if_c< + detail::path_traits::is_convertible_to_path_source< typename boost::remove_cv< Source >::type >::value, + path +>::type operator/(path lhs, Source const& rhs) { - lhs /= rhs; - return std::move(lhs); + lhs.append(rhs); + return lhs; } -#endif // inserters and extractors // use boost::io::quoted() to handle spaces in paths // use '&' as escape character to ease use for Windows paths -template< class Char, class Traits > +template< typename Char, typename Traits > inline std::basic_ostream< Char, Traits >& operator<<(std::basic_ostream< Char, Traits >& os, path const& p) { return os << boost::io::quoted(p.template string< std::basic_string< Char > >(), static_cast< Char >('&')); } -template< class Char, class Traits > +template< typename Char, typename Traits > inline std::basic_istream< Char, Traits >& operator>>(std::basic_istream< Char, Traits >& is, path& p) { @@ -1275,10 +1558,96 @@ inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT // class path miscellaneous function implementations // //------------------------------------------------------------------------------------// +namespace detail { + +inline bool path_algorithms::has_filename_v3(path const& p) +{ + return !p.m_pathname.empty(); +} + +inline bool path_algorithms::has_filename_v4(path const& p) +{ + return path_algorithms::find_filename_v4_size(p) > 0; +} + +inline path path_algorithms::filename_v4(path const& p) +{ + string_type::size_type filename_size = path_algorithms::find_filename_v4_size(p); + string_type::size_type pos = p.m_pathname.size() - filename_size; + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +inline path path_algorithms::extension_v4(path const& p) +{ + string_type::size_type extension_size = path_algorithms::find_extension_v4_size(p); + string_type::size_type pos = p.m_pathname.size() - extension_size; + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + extension_size); +} + +inline void path_algorithms::append_v4(path& left, path const& right) +{ + path_algorithms::append_v4(left, right.m_pathname.c_str(), right.m_pathname.c_str() + right.m_pathname.size()); +} + +} // namespace detail + +// Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept, +// any non-template function call that requires a check whether the source argument (which may be fs::path) +// is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload +// resolution and SFINAE checks. Otherwise, the concept check result formally changes between fs::path::iterator +// is not defined and defined, which causes compilation errors with gcc 11 and later. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106808 + +BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const value_type* source, const value_type* source_end, const codecvt_type*) const +{ + path src; + src.m_pathname.assign(source, source_end); + return m_self.compare(src); +} + +template< typename OtherChar > +BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt) const +{ + path src; + detail::path_traits::convert(source, source_end, src.m_pathname, cvt); + return m_self.compare(src); +} + +inline path& path::operator=(path const& p) +{ + return assign(p); +} + +inline path& path::operator+=(path const& p) +{ + return concat(p); +} + +BOOST_FORCEINLINE path& path::operator/=(path const& p) +{ + return append(p); +} + +#if !defined(BOOST_WINDOWS_API) +inline path path::generic_path() const +{ + return path(*this); +} +#endif + +inline path path::lexically_proximate(path const& base) const +{ + path tmp(lexically_relative(base)); + return tmp.empty() ? *this : tmp; +} + inline path::reverse_iterator path::rbegin() const { return reverse_iterator(end()); } + inline path::reverse_iterator path::rend() const { return reverse_iterator(begin()); @@ -1299,92 +1668,164 @@ inline bool path::filename_is_dot_dot() const // to deal with "c:.." edge case on Windows when ':' acts as a separator } +#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::lexically_normal() instead") +BOOST_FORCEINLINE path& path::normalize() +{ + path tmp(lexically_normal()); + m_pathname.swap(tmp.m_pathname); + return *this; +} + +#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) + +// The following functions are defined differently, depending on Boost.Filesystem version in use. +// To avoid ODR violation, these functions are not defined when the library itself is built. +// This makes sure they are not compiled when the library is built, and the only version there is +// is the one in user's code. Users are supposed to consistently use the same Boost.Filesystem version +// in all their translation units. +#if !defined(BOOST_FILESYSTEM_SOURCE) + +BOOST_FORCEINLINE path& path::append(path const& p) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size()); + return *this; +} + +BOOST_FORCEINLINE path& path::append(path const& p, codecvt_type const&) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size()); + return *this; +} + +BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end); + return *this; +} + +BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end, codecvt_type const&) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end); + return *this; +} + +BOOST_FORCEINLINE path& path::remove_filename() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::remove_filename)(*this); + return *this; +} + +BOOST_FORCEINLINE path& path::replace_extension(path const& new_extension) +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::replace_extension)(*this, new_extension); + return *this; +} + +BOOST_FORCEINLINE int path::compare(path const& p) const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::compare)(*this, p); +} + +BOOST_FORCEINLINE path path::filename() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::filename)(*this); +} + +BOOST_FORCEINLINE path path::stem() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::stem)(*this); +} + +BOOST_FORCEINLINE path path::extension() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::extension)(*this); +} + +BOOST_FORCEINLINE bool path::has_filename() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::has_filename)(*this); +} + +BOOST_FORCEINLINE path path::lexically_normal() const +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lexically_normal)(*this); +} + +namespace path_detail { + +BOOST_FORCEINLINE void path_iterator::increment() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::increment)(*this); +} + +BOOST_FORCEINLINE void path_iterator::decrement() +{ + BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::decrement)(*this); +} + +BOOST_FORCEINLINE bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2) +{ + return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lex_compare)(first1, last1, first2, last2) < 0; +} + +} // namespace path_detail + +#endif // !defined(BOOST_FILESYSTEM_SOURCE) + //--------------------------------------------------------------------------------------// // class path member template specializations // //--------------------------------------------------------------------------------------// -template<> +template< > inline std::string path::string< std::string >() const { return string(); } -template<> +template< > inline std::wstring path::string< std::wstring >() const { return wstring(); } -template<> -inline std::string path::string< std::string >(const codecvt_type& cvt) const +template< > +inline std::string path::string< std::string >(codecvt_type const& cvt) const { return string(cvt); } -template<> -inline std::wstring path::string< std::wstring >(const codecvt_type& cvt) const +template< > +inline std::wstring path::string< std::wstring >(codecvt_type const& cvt) const { return wstring(cvt); } -template<> +template< > inline std::string path::generic_string< std::string >() const { return generic_string(); } -template<> +template< > inline std::wstring path::generic_string< std::wstring >() const { return generic_wstring(); } -template<> +template< > inline std::string path::generic_string< std::string >(codecvt_type const& cvt) const { return generic_string(cvt); } -template<> +template< > inline std::wstring path::generic_string< std::wstring >(codecvt_type const& cvt) const { return generic_wstring(cvt); } -//--------------------------------------------------------------------------------------// -// path_traits convert function implementations // -// requiring path::codecvt() be visable // -//--------------------------------------------------------------------------------------// - -namespace path_traits { // without codecvt - -inline void convert(const char* from, - const char* from_end, // NULL for null terminated MBCS - std::wstring& to) -{ - convert(from, from_end, to, path::codecvt()); -} - -inline void convert(const wchar_t* from, - const wchar_t* from_end, // NULL for null terminated MBCS - std::string& to) -{ - convert(from, from_end, to, path::codecvt()); -} - -inline void convert(const char* from, std::wstring& to) -{ - BOOST_ASSERT(!!from); - convert(from, NULL, to, path::codecvt()); -} - -inline void convert(const wchar_t* from, std::string& to) -{ - BOOST_ASSERT(!!from); - convert(from, NULL, to, path::codecvt()); -} - -} // namespace path_traits } // namespace filesystem } // namespace boost diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/path_traits.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/path_traits.hpp deleted file mode 100644 index e4f9b52c0d..0000000000 --- a/contrib/restricted/boost/filesystem/include/boost/filesystem/path_traits.hpp +++ /dev/null @@ -1,384 +0,0 @@ -// filesystem path_traits.hpp --------------------------------------------------------// - -// Copyright Beman Dawes 2009 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/filesystem - -#ifndef BOOST_FILESYSTEM_PATH_TRAITS_HPP -#define BOOST_FILESYSTEM_PATH_TRAITS_HPP - -#include <boost/filesystem/config.hpp> -#include <boost/system/error_category.hpp> -#include <boost/type_traits/is_array.hpp> -#include <boost/type_traits/decay.hpp> -#include <boost/core/enable_if.hpp> -#include <cstddef> -#include <cwchar> // for mbstate_t -#include <string> -#include <vector> -#include <list> -#include <iterator> -#include <locale> -#include <boost/assert.hpp> - -#include <boost/filesystem/detail/header.hpp> // must be the last #include - -namespace boost { -namespace filesystem { - -BOOST_FILESYSTEM_DECL system::error_category const& codecvt_error_category() BOOST_NOEXCEPT; -// uses std::codecvt_base::result used for error codes: -// -// ok: Conversion successful. -// partial: Not all source characters converted; one or more additional source -// characters are needed to produce the final target character, or the -// size of the target intermediate buffer was too small to hold the result. -// error: A character in the source could not be converted to the target encoding. -// noconv: The source and target characters have the same type and encoding, so no -// conversion was necessary. - -class directory_entry; - -namespace path_traits { - -typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type; - -// is_pathable type trait; allows disabling over-agressive class path member templates - -template< class T > -struct is_pathable -{ - static const bool value = false; -}; - -template<> -struct is_pathable< char* > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< const char* > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< wchar_t* > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< const wchar_t* > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::string > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::wstring > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::vector< char > > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::vector< wchar_t > > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::list< char > > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< std::list< wchar_t > > -{ - static const bool value = true; -}; - -template<> -struct is_pathable< directory_entry > -{ - static const bool value = true; -}; - -// Pathable empty - -template< class Container > -inline - // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for - // conforming compilers. Replace by plain "bool" at some future date (2012?) - typename boost::disable_if< boost::is_array< Container >, bool >::type - empty(Container const& c) -{ - return c.begin() == c.end(); -} - -template< class T > -inline bool empty(T* const& c_str) -{ - BOOST_ASSERT(c_str); - return !*c_str; -} - -template< typename T, std::size_t N > -inline bool empty(T (&x)[N]) -{ - return !x[0]; -} - -// value types differ ---------------------------------------------------------------// -// -// A from_end argument of NULL is less efficient than a known end, so use only if needed - -// with codecvt - -BOOST_FILESYSTEM_DECL -void convert(const char* from, - const char* from_end, // NULL for null terminated MBCS - std::wstring& to, codecvt_type const& cvt); - -BOOST_FILESYSTEM_DECL -void convert(const wchar_t* from, - const wchar_t* from_end, // NULL for null terminated MBCS - std::string& to, codecvt_type const& cvt); - -inline void convert(const char* from, std::wstring& to, codecvt_type const& cvt) -{ - BOOST_ASSERT(from); - convert(from, NULL, to, cvt); -} - -inline void convert(const wchar_t* from, std::string& to, codecvt_type const& cvt) -{ - BOOST_ASSERT(from); - convert(from, NULL, to, cvt); -} - -// without codecvt - -inline void convert(const char* from, - const char* from_end, // NULL for null terminated MBCS - std::wstring& to); - -inline void convert(const wchar_t* from, - const wchar_t* from_end, // NULL for null terminated MBCS - std::string& to); - -inline void convert(const char* from, std::wstring& to); - -inline void convert(const wchar_t* from, std::string& to); - -// value types same -----------------------------------------------------------------// - -// char with codecvt - -inline void convert(const char* from, const char* from_end, std::string& to, codecvt_type const&) -{ - BOOST_ASSERT(from); - BOOST_ASSERT(from_end); - to.append(from, from_end); -} - -inline void convert(const char* from, std::string& to, codecvt_type const&) -{ - BOOST_ASSERT(from); - to += from; -} - -// wchar_t with codecvt - -inline void convert(const wchar_t* from, const wchar_t* from_end, std::wstring& to, codecvt_type const&) -{ - BOOST_ASSERT(from); - BOOST_ASSERT(from_end); - to.append(from, from_end); -} - -inline void convert(const wchar_t* from, std::wstring& to, codecvt_type const&) -{ - BOOST_ASSERT(from); - to += from; -} - -// char without codecvt - -inline void convert(const char* from, const char* from_end, std::string& to) -{ - BOOST_ASSERT(from); - BOOST_ASSERT(from_end); - to.append(from, from_end); -} - -inline void convert(const char* from, std::string& to) -{ - BOOST_ASSERT(from); - to += from; -} - -// wchar_t without codecvt - -inline void convert(const wchar_t* from, const wchar_t* from_end, std::wstring& to) -{ - BOOST_ASSERT(from); - BOOST_ASSERT(from_end); - to.append(from, from_end); -} - -inline void convert(const wchar_t* from, std::wstring& to) -{ - BOOST_ASSERT(from); - to += from; -} - -// Source dispatch -----------------------------------------------------------------// - -// contiguous containers with codecvt -template< class U > -inline void dispatch(std::string const& c, U& to, codecvt_type const& cvt) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to, cvt); -} -template< class U > -inline void dispatch(std::wstring const& c, U& to, codecvt_type const& cvt) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to, cvt); -} -template< class U > -inline void dispatch(std::vector< char > const& c, U& to, codecvt_type const& cvt) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to, cvt); -} -template< class U > -inline void dispatch(std::vector< wchar_t > const& c, U& to, codecvt_type const& cvt) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to, cvt); -} - -// contiguous containers without codecvt -template< class U > -inline void dispatch(std::string const& c, U& to) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to); -} -template< class U > -inline void dispatch(std::wstring const& c, U& to) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to); -} -template< class U > -inline void dispatch(std::vector< char > const& c, U& to) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to); -} -template< class U > -inline void dispatch(std::vector< wchar_t > const& c, U& to) -{ - if (!c.empty()) - convert(&*c.begin(), &*c.begin() + c.size(), to); -} - -// non-contiguous containers with codecvt -template< class Container, class U > -inline - // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for - // conforming compilers. Replace by plain "void" at some future date (2012?) - typename boost::disable_if< boost::is_array< Container >, void >::type - dispatch(Container const& c, U& to, codecvt_type const& cvt) -{ - if (!c.empty()) - { - std::basic_string< typename Container::value_type > s(c.begin(), c.end()); - convert(s.c_str(), s.c_str() + s.size(), to, cvt); - } -} - -// c_str -template< class T, class U > -inline void dispatch(T* const& c_str, U& to, codecvt_type const& cvt) -{ - // std::cout << "dispatch() const T *\n"; - BOOST_ASSERT(c_str); - convert(c_str, to, cvt); -} - -// Note: there is no dispatch on C-style arrays because the array may -// contain a string smaller than the array size. - -BOOST_FILESYSTEM_DECL -void dispatch(directory_entry const& de, -#ifdef BOOST_WINDOWS_API - std::wstring& to, -#else - std::string& to, -#endif - codecvt_type const&); - -// non-contiguous containers without codecvt -template< class Container, class U > -inline - // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for - // conforming compilers. Replace by plain "void" at some future date (2012?) - typename boost::disable_if< boost::is_array< Container >, void >::type - dispatch(Container const& c, U& to) -{ - if (!c.empty()) - { - std::basic_string< typename Container::value_type > seq(c.begin(), c.end()); - convert(seq.c_str(), seq.c_str() + seq.size(), to); - } -} - -// c_str -template< class T, class U > -inline void dispatch(T* const& c_str, U& to) -{ - // std::cout << "dispatch() const T *\n"; - BOOST_ASSERT(c_str); - convert(c_str, to); -} - -// Note: there is no dispatch on C-style arrays because the array may -// contain a string smaller than the array size. - -BOOST_FILESYSTEM_DECL -void dispatch(directory_entry const& de, -#ifdef BOOST_WINDOWS_API - std::wstring& to -#else - std::string& to -#endif -); - -} // namespace path_traits -} // namespace filesystem -} // namespace boost - -#include <boost/filesystem/detail/footer.hpp> - -#endif // BOOST_FILESYSTEM_PATH_TRAITS_HPP diff --git a/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp index 72db677a09..a8d2a42732 100644 --- a/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp +++ b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp @@ -15,7 +15,7 @@ #include <boost/config/warning_disable.hpp> #include <boost/filesystem/config.hpp> -#include <boost/filesystem/path_traits.hpp> +#include <boost/filesystem/detail/path_traits.hpp> #include <boost/system/error_category.hpp> #include <locale> #include <string> diff --git a/contrib/restricted/boost/filesystem/src/directory.cpp b/contrib/restricted/boost/filesystem/src/directory.cpp index 6a3e1dc731..f769f8fc18 100644 --- a/contrib/restricted/boost/filesystem/src/directory.cpp +++ b/contrib/restricted/boost/filesystem/src/directory.cpp @@ -74,15 +74,6 @@ #include <boost/filesystem/detail/header.hpp> // must be the last #include -// BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in -// dir_itr_increment. The config tests are placed here because some of the -// macros being tested come from dirent.h. -// -// TODO: find out what macros indicate dirent::d_type present in more libraries -#if defined(BOOST_WINDOWS_API) || defined(_DIRENT_HAVE_D_TYPE) // defined by GNU C library if d_type present -#define BOOST_FILESYSTEM_STATUS_CACHE -#endif - namespace fs = boost::filesystem; using boost::system::error_code; using boost::system::system_category; @@ -96,76 +87,34 @@ namespace filesystem { // // //--------------------------------------------------------------------------------------// -BOOST_FILESYSTEM_DECL -file_status directory_entry::get_status(system::error_code* ec) const +BOOST_FILESYSTEM_DECL void directory_entry::refresh_impl(system::error_code* ec) const { - if (!status_known(m_status)) + system::error_code local_ec; + m_symlink_status = detail::symlink_status(m_path, &local_ec); + + if (!filesystem::is_symlink(m_symlink_status)) { - // optimization: if the symlink status is known, and it isn't a symlink, - // then status and symlink_status are identical so just copy the - // symlink status to the regular status. - if (status_known(m_symlink_status) && !is_symlink(m_symlink_status)) - { - m_status = m_symlink_status; - if (ec) - ec->clear(); - } - else + // Also works if symlink_status fails - set m_status to status_error as well + m_status = m_symlink_status; + + if (BOOST_UNLIKELY(!!local_ec)) { - m_status = detail::status(m_path, ec); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_entry::refresh", m_path, local_ec)); + + *ec = local_ec; + return; } + + if (ec) + ec->clear(); } - else if (ec) + else { - ec->clear(); + m_status = detail::status(m_path, ec); } - - return m_status; } -BOOST_FILESYSTEM_DECL -file_status directory_entry::get_symlink_status(system::error_code* ec) const -{ - if (!status_known(m_symlink_status)) - m_symlink_status = detail::symlink_status(m_path, ec); - else if (ec) - ec->clear(); - - return m_symlink_status; -} - -// dispatch directory_entry supplied here rather than in -// <boost/filesystem/path_traits.hpp>, thus avoiding header circularity. -// test cases are in operations_unit_test.cpp - -namespace path_traits { - -BOOST_FILESYSTEM_DECL -void dispatch(directory_entry const& de, -#ifdef BOOST_WINDOWS_API - std::wstring& to, -#else - std::string& to, -#endif - codecvt_type const&) -{ - to = de.path().native(); -} - -BOOST_FILESYSTEM_DECL -void dispatch(directory_entry const& de, -#ifdef BOOST_WINDOWS_API - std::wstring& to -#else - std::string& to -#endif -) -{ - to = de.path().native(); -} - -} // namespace path_traits - //--------------------------------------------------------------------------------------// // // // directory_iterator // @@ -353,24 +302,43 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat filename = result->d_name; -#ifdef BOOST_FILESYSTEM_STATUS_CACHE +#if defined(BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE) if (result->d_type == DT_UNKNOWN) // filesystem does not supply d_type value { sf = symlink_sf = fs::file_status(fs::status_error); } else // filesystem supplies d_type value { - if (result->d_type == DT_DIR) - sf = symlink_sf = fs::file_status(fs::directory_file); - else if (result->d_type == DT_REG) + if (result->d_type == DT_REG) sf = symlink_sf = fs::file_status(fs::regular_file); + else if (result->d_type == DT_DIR) + sf = symlink_sf = fs::file_status(fs::directory_file); else if (result->d_type == DT_LNK) { sf = fs::file_status(fs::status_error); symlink_sf = fs::file_status(fs::symlink_file); } else - sf = symlink_sf = fs::file_status(fs::status_error); + { + switch (result->d_type) + { + case DT_SOCK: + sf = symlink_sf = fs::file_status(fs::socket_file); + break; + case DT_FIFO: + sf = symlink_sf = fs::file_status(fs::fifo_file); + break; + case DT_BLK: + sf = symlink_sf = fs::file_status(fs::block_file); + break; + case DT_CHR: + sf = symlink_sf = fs::file_status(fs::character_file); + break; + default: + sf = symlink_sf = fs::file_status(fs::status_error); + break; + } + } } #else sf = symlink_sf = fs::file_status(fs::status_error); @@ -599,9 +567,12 @@ extra_data_format g_extra_data_format = file_directory_information_format; * \brief Extra buffer size for GetFileInformationByHandleEx-based or NtQueryDirectoryFile-based directory iterator. * * Must be large enough to accommodate at least one FILE_DIRECTORY_INFORMATION or *_DIR_INFO struct and one filename. - * NTFS, VFAT, exFAT support filenames up to 255 UTF-16/UCS-2 characters. ReFS supports filenames up to 32768 UTF-16 characters. + * NTFS, VFAT, exFAT and ReFS support filenames up to 255 UTF-16/UCS-2 characters. (For ReFS, there is no information + * on the on-disk format, and it is possible that it supports longer filenames, up to 32768 UTF-16/UCS-2 characters.) + * The buffer cannot be larger than 64k, because up to Windows 8.1, NtQueryDirectoryFile and GetFileInformationByHandleEx + * fail with ERROR_INVALID_PARAMETER when trying to retrieve the filenames from a network share. */ -BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = sizeof(file_id_extd_dir_info) + 65536u; +BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = 65536u; inline system::error_code dir_itr_close(dir_itr_imp& imp) BOOST_NOEXCEPT { @@ -763,6 +734,28 @@ done: return error_code(); } +//! Returns \c true if the error code indicates that the OS or the filesystem does not support a particular directory info class +inline bool is_dir_info_class_not_supported(DWORD error) +{ + // Some mounted filesystems may not support FILE_ID_128 identifiers, which will cause + // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER, + // even though in general the operation is supported by the kernel. SMBv1 returns a special error + // code ERROR_INVALID_LEVEL in this case. + // Some other filesystems also don't implement other info classes and return ERROR_INVALID_PARAMETER + // (e.g. see https://github.com/boostorg/filesystem/issues/266), ERROR_GEN_FAILURE, ERROR_INVALID_FUNCTION + // or ERROR_INTERNAL_ERROR (https://github.com/boostorg/filesystem/issues/286). Treat these error codes + // as "non-permanent", even though ERROR_INVALID_PARAMETER is also returned if GetFileInformationByHandleEx + // in general does not support a certain info class. Worst case, we will make extra syscalls on directory + // iterator construction. + // Also note that Wine returns ERROR_CALL_NOT_IMPLEMENTED for unimplemented info classes, and + // up until 7.21 it didn't implement FileIdExtdDirectoryRestartInfo and FileFullDirectoryRestartInfo. + // (https://bugs.winehq.org/show_bug.cgi?id=53590) + return error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER || + error == ERROR_INVALID_LEVEL || error == ERROR_CALL_NOT_IMPLEMENTED || + error == ERROR_GEN_FAILURE || error == ERROR_INVALID_FUNCTION || + error == ERROR_INTERNAL_ERROR; +} + error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, unsigned int opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf) { boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (dir_itr_extra_size) detail::dir_itr_imp()); @@ -828,9 +821,14 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs:: if (BOOST_UNLIKELY((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u)) return make_error_code(system::errc::not_a_directory); - if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u) + if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) { - if ((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u && is_reparse_point_a_symlink_ioctl(h.handle)) + error_code ec; + const ULONG reparse_point_tag = detail::get_reparse_point_tag_ioctl(h.handle, dir, &ec); + if (BOOST_UNLIKELY(!!ec)) + return ec; + + if (detail::is_reparse_point_tag_a_symlink(reparse_point_tag)) return make_error_code(system::errc::too_many_symbolic_link_levels); } } @@ -845,14 +843,10 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs:: { DWORD error = ::GetLastError(); - if (error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER) + if (is_dir_info_class_not_supported(error)) { // Fall back to file_full_dir_info_format. - // Note that some mounted filesystems may not support FILE_ID_128 identifiers, which will cause - // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER, - // even though in general the operation is supported by the kernel. So don't downgrade to - // FileFullDirectoryRestartInfo permanently in this case - only for this particular iterator. - if (error == ERROR_NOT_SUPPORTED) + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_full_dir_info_format); goto fallback_to_file_full_dir_info_format; } @@ -879,11 +873,12 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs:: { DWORD error = ::GetLastError(); - if (error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER) + if (is_dir_info_class_not_supported(error)) { // Fall back to file_id_both_dir_info - filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format); - goto fallback_to_file_id_both_dir_info; + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format); + goto fallback_to_file_id_both_dir_info_format; } if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND) @@ -902,12 +897,20 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs:: break; case file_id_both_dir_info_format: - fallback_to_file_id_both_dir_info: + fallback_to_file_id_both_dir_info_format: { if (!get_file_information_by_handle_ex(iterator_handle, file_id_both_directory_restart_info_class, extra_data, dir_itr_extra_size)) { DWORD error = ::GetLastError(); + if (is_dir_info_class_not_supported(error)) + { + // Fall back to file_directory_information + if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED) + filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_directory_information_format); + goto fallback_to_file_directory_information_format; + } + if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND) goto done; @@ -924,6 +927,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs:: break; default: + fallback_to_file_directory_information_format: { NtQueryDirectoryFile_t* nt_query_directory_file = filesystem::detail::atomic_load_relaxed(boost::filesystem::detail::nt_query_directory_file_api); if (BOOST_UNLIKELY(!nt_query_directory_file)) @@ -1120,7 +1124,18 @@ void directory_iterator_construct(directory_iterator& it, path const& p, unsigne && (filename_str[1] == static_cast< path::string_type::value_type >('\0') || (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0'))))) { - imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat); + path full_path(p); + path_algorithms::append_v4(full_path, filename); + imp->dir_entry.assign_with_status + ( +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + static_cast< path&& >(full_path), +#else + full_path, +#endif + file_stat, + symlink_file_stat + ); it.m_imp.swap(imp); return; } @@ -1180,7 +1195,7 @@ void directory_iterator_increment(directory_iterator& it, system::error_code* ec && (filename_str[1] == static_cast< path::string_type::value_type >('\0') || (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0'))))) { - it.m_imp->dir_entry.replace_filename(filename, file_stat, symlink_file_stat); + it.m_imp->dir_entry.replace_filename_with_status(filename, file_stat, symlink_file_stat); return; } } @@ -1344,14 +1359,14 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: return result; } - file_status symlink_stat; + file_type symlink_ft = status_error; // If we are not recursing into symlinks, we are going to have to know if the // stack top is a symlink, so get symlink_status and verify no error occurred. if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) == 0u || (imp->m_options & static_cast< unsigned int >(directory_options::skip_dangling_symlinks)) != 0u) { - symlink_stat = imp->m_stack.back()->symlink_status(ec); + symlink_ft = imp->m_stack.back()->symlink_file_type(ec); if (ec) return result; } @@ -1364,12 +1379,12 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: // The predicate code has since been rewritten to pass error_code arguments, // per ticket #5653. - if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) != 0u || !fs::is_symlink(symlink_stat)) + if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) != 0u || symlink_ft != symlink_file) { - file_status stat = imp->m_stack.back()->status(ec); + file_type ft = imp->m_stack.back()->file_type(ec); if (BOOST_UNLIKELY(!!ec)) { - if (ec == make_error_condition(system::errc::no_such_file_or_directory) && fs::is_symlink(symlink_stat) && + if (ec == make_error_condition(system::errc::no_such_file_or_directory) && symlink_ft == symlink_file && (imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) { // Skip dangling symlink and continue iteration on the current depth level @@ -1379,7 +1394,7 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: return result; } - if (!fs::is_directory(stat)) + if (ft != directory_file) return result; if (BOOST_UNLIKELY((imp->m_stack.size() - 1u) >= static_cast< std::size_t >((std::numeric_limits< int >::max)()))) diff --git a/contrib/restricted/boost/filesystem/src/operations.cpp b/contrib/restricted/boost/filesystem/src/operations.cpp index dd636e9063..c7808d5941 100644 --- a/contrib/restricted/boost/filesystem/src/operations.cpp +++ b/contrib/restricted/boost/filesystem/src/operations.cpp @@ -70,7 +70,7 @@ #include <unistd.h> #include <fcntl.h> -#if _POSIX_C_SOURCE < 200809L +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) #include <utime.h> #endif #include <limits.h> @@ -1116,7 +1116,7 @@ uintmax_t remove_all_impl count += fs::detail::remove_all_impl ( #if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) - itr->path().filename(), + path_algorithms::filename_v4(itr->path()), #else itr->path(), #endif @@ -1511,50 +1511,36 @@ boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_ha #endif // !defined(UNDER_CE) -bool is_reparse_point_a_symlink_ioctl(HANDLE h) +ULONG get_reparse_point_tag_ioctl(HANDLE h, path const& p, error_code* ec) { - boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new (std::nothrow) reparse_data_buffer_with_storage); + if (BOOST_UNLIKELY(!buf.get())) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Cannot allocate memory to query reparse point", p, make_error_code(system::errc::not_enough_memory))); + + *ec = make_error_code(system::errc::not_enough_memory); + return 0u; + } // Query the reparse data DWORD dwRetLen = 0u; BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); if (BOOST_UNLIKELY(!result)) - return false; - - return is_reparse_point_tag_a_symlink(buf->rdb.ReparseTag); -} - -namespace { - -inline bool is_reparse_point_a_symlink(path const& p) -{ - handle_wrapper h(create_file_handle( - p, - FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); - if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) - return false; - - GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); - if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) { - file_attribute_tag_info info; - BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info)); - if (BOOST_UNLIKELY(!result)) - return false; - - if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) - return false; + DWORD err = ::GetLastError(); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Failed to query reparse point", p, error_code(err, system_category()))); - return is_reparse_point_tag_a_symlink(info.ReparseTag); + ec->assign(err, system_category()); + return 0u; } - return is_reparse_point_a_symlink_ioctl(h.handle); + return buf->rdb.ReparseTag; } +namespace { + inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) { return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); @@ -1590,6 +1576,7 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) { fs::file_type ftype; DWORD attrs; + ULONG reparse_tag = 0u; GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) { @@ -1609,12 +1596,7 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) } attrs = info.FileAttributes; - - if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) - { - ftype = is_reparse_point_tag_a_symlink(info.ReparseTag) ? fs::symlink_file : fs::reparse_file; - goto done; - } + reparse_tag = info.ReparseTag; } else { @@ -1626,25 +1608,48 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) attrs = info.dwFileAttributes; - if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) { - ftype = is_reparse_point_a_symlink_ioctl(h) ? fs::symlink_file : fs::reparse_file; - goto done; + reparse_tag = get_reparse_point_tag_ioctl(h, p, ec); + if (ec) + { + if (BOOST_UNLIKELY(!!ec)) + return fs::file_status(fs::status_error); + } } } - ftype = (attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file; + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } -done: return fs::file_status(ftype, make_permissions(p, attrs)); } //! symlink_status() implementation fs::file_status symlink_status_impl(path const& p, error_code* ec) { + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 handle_wrapper h(create_file_handle( p.c_str(), - FILE_READ_ATTRIBUTES, // dwDesiredAccess; attributes only + FILE_READ_ATTRIBUTES | FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, // lpSecurityAttributes OPEN_EXISTING, @@ -1688,7 +1693,7 @@ fs::file_status status_impl(path const& p, error_code* ec) // Resolve the symlink handle_wrapper h(create_file_handle( p.c_str(), - FILE_READ_ATTRIBUTES, // dwDesiredAccess; attributes only + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // lpSecurityAttributes OPEN_EXISTING, @@ -1775,7 +1780,7 @@ DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) break; err = ::GetLastError(); - if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED)) + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) { // Downgrade to the older implementation impl = remove_disp_ex_flag_posix_semantics; @@ -1833,7 +1838,7 @@ DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) break; } - else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED)) + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) { // Downgrade to the older implementation impl = remove_disp; @@ -1902,7 +1907,7 @@ inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec { handle_wrapper h(create_file_handle( p, - DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, @@ -1999,12 +2004,12 @@ uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) ( hh.handle, h, - nested_path.filename(), + path_algorithms::filename_v4(nested_path), 0u, // FileAttributes - FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, - FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT ); if (!NT_SUCCESS(status)) @@ -2027,7 +2032,7 @@ uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) { hh.handle = create_file_handle( nested_path, - FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, @@ -2144,7 +2149,7 @@ inline uintmax_t remove_all_impl(path const& p, error_code* ec) { handle_wrapper h(create_file_handle( p, - FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, @@ -2385,12 +2390,12 @@ path absolute(path const& p, path const& base, system::error_code* ec) else { res.concat(abs_base.root_directory()); - res /= abs_base.relative_path(); + path_algorithms::append_v4(res, abs_base.relative_path()); } path p_relative_path(p.relative_path()); if (!p_relative_path.empty()) - res /= p_relative_path; + path_algorithms::append_v4(res, p_relative_path); return res; } @@ -2437,14 +2442,14 @@ path canonical(path const& p, path const& base, system::error_code* ec) path result; while (true) { - for (path::iterator itr(source.begin()), end(source.end()); itr != end; ++itr) + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) { - if (*itr == dot_p) + if (path_algorithms::compare_v4(*itr, dot_p) == 0) continue; - if (*itr == dot_dot_p) + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) { - if (result != root) - result.remove_filename(); + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); continue; } @@ -2459,7 +2464,7 @@ path canonical(path const& p, path const& base, system::error_code* ec) continue; } - result /= *itr; + path_algorithms::append_v4(result, *itr); // If we don't have an absolute path yet then don't check symlink status. // This avoids checking "C:" which is "the current directory on drive C" @@ -2484,14 +2489,14 @@ path canonical(path const& p, path const& base, system::error_code* ec) path link(detail::read_symlink(result, ec)); if (ec && *ec) goto return_empty_path; - result.remove_filename(); + result.remove_filename_and_trailing_separators(); if (link.is_absolute()) { - for (++itr; itr != end; ++itr) + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) { - if (*itr != dot_p) - link /= *itr; + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); } source = link; root = source.root_path(); @@ -2499,15 +2504,15 @@ path canonical(path const& p, path const& base, system::error_code* ec) else // link is relative { link.remove_trailing_separator(); - if (link == dot_p) + if (path_algorithms::compare_v4(link, dot_p) == 0) continue; path new_source(result); - new_source /= link; - for (++itr; itr != end; ++itr) + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) { - if (*itr != dot_p) - new_source /= *itr; + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); } source = new_source; } @@ -2603,10 +2608,10 @@ void copy(path const& from, path const& to, unsigned int options, system::error_ relative_from = detail::relative(abs_from, abs_to, ec); if (ec && *ec) return; - if (relative_from != dot_path()) - relative_from /= from.filename(); + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); else - relative_from = from.filename(); + relative_from = path_algorithms::filename_v4(from); pfrom = &relative_from; } detail::create_symlink(*pfrom, to, ec); @@ -2642,7 +2647,11 @@ void copy(path const& from, path const& to, unsigned int options, system::error_ } if (is_directory(to_stat)) - detail::copy_file(from, to / from.filename(), options, ec); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } else detail::copy_file(from, to, options, ec); } @@ -2697,8 +2706,12 @@ void copy(path const& from, path const& to, unsigned int options, system::error_ while (itr != end_dit) { path const& p = itr->path(); - // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none - detail::copy(p, to / p.filename(), options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + } if (ec && *ec) return; @@ -2953,7 +2966,14 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError handle_wrapper hw_from, hw_to; - hw_from.handle = create_file_handle(from.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + // See the comment in last_write_time regarding access rights used here for GetFileTime. + hw_from.handle = create_file_handle( + from.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); FILETIME lwt_from; if (hw_from.handle == INVALID_HANDLE_VALUE) @@ -2967,7 +2987,13 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) goto fail_last_error; - hw_to.handle = create_file_handle(to.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + hw_to.handle = create_file_handle( + to.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); if (hw_to.handle != INVALID_HANDLE_VALUE) { @@ -3088,9 +3114,9 @@ bool create_directories(path const& p, system::error_code* ec) error_code local_ec; // Find the initial part of the path that exists - for (path fname = parent.filename(); parent.has_relative_path(); fname = parent.filename()) + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) { - if (!fname.empty() && fname != dot_p && fname != dot_dot_p) + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) { file_status existing_status = detail::status_impl(parent, &local_ec); @@ -3107,19 +3133,19 @@ bool create_directories(path const& p, system::error_code* ec) } } - --it; - parent.remove_filename(); + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); } // Create missing directories bool created = false; - for (; it != e; ++it) + for (; it != e; path_algorithms::increment_v4(it)) { path const& fname = *it; - parent /= fname; - if (!fname.empty() && fname != dot_p && fname != dot_dot_p) + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) { - created = create_directory(parent, NULL, &local_ec); + created = detail::create_directory(parent, NULL, &local_ec); if (BOOST_UNLIKELY(!!local_ec)) { if (!ec) @@ -3749,9 +3775,10 @@ std::time_t creation_time(path const& p, system::error_code* ec) #else // defined(BOOST_POSIX_API) + // See the comment in last_write_time regarding access rights used here for GetFileTime. handle_wrapper hw(create_file_handle( p.c_str(), - FILE_READ_ATTRIBUTES, + FILE_READ_ATTRIBUTES | FILE_READ_EA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, @@ -3765,7 +3792,6 @@ std::time_t creation_time(path const& p, system::error_code* ec) } FILETIME ct; - if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) goto fail; @@ -3807,9 +3833,12 @@ std::time_t last_write_time(path const& p, system::error_code* ec) #else // defined(BOOST_POSIX_API) + // GetFileTime is documented to require GENERIC_READ access right, but this causes problems if the file + // is opened by another process without FILE_SHARE_READ. In practice, FILE_READ_ATTRIBUTES works, and + // FILE_READ_EA is also added for good measure, in case if it matters for SMBv1. handle_wrapper hw(create_file_handle( p.c_str(), - FILE_READ_ATTRIBUTES, + FILE_READ_ATTRIBUTES | FILE_READ_EA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, @@ -3823,7 +3852,6 @@ std::time_t last_write_time(path const& p, system::error_code* ec) } FILETIME lwt; - if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) goto fail; @@ -4055,9 +4083,8 @@ path read_symlink(path const& p, system::error_code* ec) DWORD error; if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) { + return_last_error: error = ::GetLastError(); - - return_error: emit_error(error, p, ec, "boost::filesystem::read_symlink"); return symlink_path; } @@ -4065,10 +4092,7 @@ path read_symlink(path const& p, system::error_code* ec) boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); DWORD sz = 0u; if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) - { - error = ::GetLastError(); - goto return_error; - } + goto return_last_error; const wchar_t* buffer; std::size_t offset, len; @@ -4310,11 +4334,8 @@ path temp_directory_path(system::error_code* ec) #else // Windows #if !defined(UNDER_CE) - const wchar_t* tmp_env = L"TMP"; - const wchar_t* temp_env = L"TEMP"; - const wchar_t* localappdata_env = L"LOCALAPPDATA"; - const wchar_t* userprofile_env = L"USERPROFILE"; - const wchar_t* env_list[] = { tmp_env, temp_env, localappdata_env, userprofile_env }; + static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; path p; for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) @@ -4324,7 +4345,7 @@ path temp_directory_path(system::error_code* ec) { p = env; if (i >= 2) - p /= L"Temp"; + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); error_code lcl_ec; if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) break; @@ -4349,7 +4370,7 @@ path temp_directory_path(system::error_code* ec) goto getwindir_error; p = buf.get(); // do not depend on initial buf size, see ticket #10388 - p /= L"Temp"; + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); } return p; @@ -4395,7 +4416,12 @@ path system_complete(path const& p, system::error_code* ec) { #ifdef BOOST_POSIX_API - return (p.empty() || p.is_absolute()) ? p : current_path() / p; + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; #else if (p.empty()) @@ -4432,9 +4458,9 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec) path::iterator itr(p_end); path head(p); - for (; !head.empty(); --itr) + for (; !head.empty(); path_algorithms::decrement_v4(itr)) { - file_status head_status = detail::status_impl(head, &local_ec); + file_status head_status(detail::status_impl(head, &local_ec)); if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) { if (!ec) @@ -4447,35 +4473,86 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec) if (head_status.type() != fs::file_not_found) break; - head.remove_filename(); + head.remove_filename_and_trailing_separators(); } + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + #else - // On Windows, filesystem APIs such as GetFileAttributesW perform lexical path normalization internally. - // As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would break - // canonical, as symlink_status that it calls internally would report an error that the file at the intermediate - // path does not exist. To avoid this, scan the initial path in the forward direction. - // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW, - // which is called in status() may return "file not found" for paths to network shares and mounted cloud - // storages that have forward slashes as separators. + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. path::iterator itr(p.begin()); path head; - for (; itr != p_end; ++itr) + if (p.has_root_name()) { - path const& p_elem = *itr; - if (p_elem.size() == 1u && detail::is_directory_separator(p_elem.native()[0])) + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) { - // Convert generic separator returned by the iterator for the root directory to - // the preferred separator. - head += path::preferred_separator; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); } - else + + if (head_status.type() == fs::file_not_found) { - head /= p_elem; + // If the root path does not exist then no path element exists + return path_algorithms::lexically_normal_v4(p); } + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); - file_status head_status = detail::status_impl(head, &local_ec); + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) { if (!ec) @@ -4487,38 +4564,27 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec) if (head_status.type() == fs::file_not_found) { - head.remove_filename(); + head.remove_filename_and_trailing_separators(); break; } } + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + #endif - path const& dot_p = dot_path(); - path const& dot_dot_p = dot_dot_path(); path tail; bool tail_has_dots = false; - for (; itr != p_end; ++itr) + for (; itr != p_end; path_algorithms::increment_v4(itr)) { path const& tail_elem = *itr; -#if defined(BOOST_WINDOWS_API) - if (tail_elem.size() == 1u && detail::is_directory_separator(tail_elem.native()[0])) - { - // Convert generic separator returned by the iterator for the root directory to - // the preferred separator. - tail += path::preferred_separator; - continue; - } -#endif - tail /= tail_elem; + path_algorithms::append_v4(tail, tail_elem); // for a later optimization, track if any dot or dot-dot elements are present - if (!tail_has_dots && (tail_elem == dot_p || tail_elem == dot_dot_p)) + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) tail_has_dots = true; } - if (head.empty()) - return p.lexically_normal(); - head = detail::canonical(head, base, &local_ec); if (BOOST_UNLIKELY(!!local_ec)) { @@ -4531,11 +4597,11 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec) if (BOOST_LIKELY(!tail.empty())) { - head /= tail; + path_algorithms::append_v4(head, tail); // optimization: only normalize if tail had dot or dot-dot element if (tail_has_dots) - return head.lexically_normal(); + return path_algorithms::lexically_normal_v4(head); } return head; diff --git a/contrib/restricted/boost/filesystem/src/path.cpp b/contrib/restricted/boost/filesystem/src/path.cpp index 27b32e57c5..1d9748cac7 100644 --- a/contrib/restricted/boost/filesystem/src/path.cpp +++ b/contrib/restricted/boost/filesystem/src/path.cpp @@ -1,7 +1,7 @@ // filesystem path.cpp ------------------------------------------------------------- // // Copyright Beman Dawes 2008 -// Copyright Andrey Semashev 2021 +// Copyright Andrey Semashev 2021-2023 // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -12,7 +12,7 @@ #include <boost/filesystem/config.hpp> #include <boost/filesystem/path.hpp> -#include <boost/filesystem/path_traits.hpp> // codecvt_error_category() +#include <boost/filesystem/detail/path_traits.hpp> // codecvt_error_category() #include <boost/scoped_array.hpp> #include <boost/system/error_category.hpp> // for BOOST_SYSTEM_HAS_CONSTEXPR #include <boost/assert.hpp> @@ -60,7 +60,6 @@ namespace { typedef path::value_type value_type; typedef path::string_type string_type; typedef string_type::size_type size_type; -using boost::filesystem::path_detail::substring; #ifdef BOOST_WINDOWS_API @@ -151,110 +150,247 @@ inline void first_element(string_type const& src, size_type& element_pos, size_t namespace boost { namespace filesystem { +namespace detail { -BOOST_FILESYSTEM_DECL void path::append_v3(path const& p) +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) { - if (!p.empty()) + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) { - if (BOOST_LIKELY(this != &p)) - { - if (!detail::is_directory_separator(*p.m_pathname.begin())) - append_separator_if_needed(); - m_pathname += p.m_pathname; - } - else - { - // self-append - path rhs(p); - append_v3(rhs); - } + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); } + return std::make_pair(it1, it2); } -BOOST_FILESYSTEM_DECL void path::append_v3(const value_type* begin, const value_type* end) +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) { - if (begin != end) + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) { - if (BOOST_LIKELY(begin < m_pathname.data() || begin >= (m_pathname.data() + m_pathname.size()))) + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) { - if (!detail::is_directory_separator(*begin)) - append_separator_if_needed(); - m_pathname.append(begin, end); + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } } - else + + if (normal.empty() || last_element_was_dot) { - // overlapping source - path rhs(begin, end); - append_v3(rhs); + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); } } + + return normal; } -BOOST_FILESYSTEM_DECL void path::append_v4(path const& p) +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) { - if (!p.empty()) - { - if (BOOST_LIKELY(this != &p)) - { - const size_type that_size = p.m_pathname.size(); - size_type that_root_name_size = 0; - size_type that_root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), that_size, that_root_name_size); + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); - // if (p.is_absolute()) - if - ( -#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) - that_root_name_size > 0 && +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } #endif - that_root_dir_pos < that_size - ) + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; { - return_assign: - assign(p); - return; - } + const size_type start_pos = i; - size_type this_root_name_size = 0; - find_root_directory_start(m_pathname.c_str(), m_pathname.size(), this_root_name_size); + // Find next separator + i += find_separator(pathname + i, pathname_size - i); - if - ( - that_root_name_size > 0 && - (that_root_name_size != this_root_name_size || std::memcmp(m_pathname.c_str(), p.m_pathname.c_str(), this_root_name_size * sizeof(value_type)) != 0) - ) + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) { - goto return_assign; + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; } - if (that_root_dir_pos < that_size) + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) { - // Remove root directory (if any) and relative path to replace with those from p - m_pathname.erase(m_pathname.begin() + this_root_name_size, m_pathname.end()); + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; } + } - const value_type* const that_path = p.m_pathname.c_str() + that_root_name_size; - if (!detail::is_directory_separator(*that_path)) - append_separator_if_needed(); - m_pathname.append(that_path, that_size - that_root_name_size); + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); } else { - // self-append - path rhs(p); - append_v4(rhs); + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); } } - else if (has_filename_v4()) - { - m_pathname.push_back(preferred_separator); - } } -BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_type* end) +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) { if (begin != end) { - if (BOOST_LIKELY(begin < m_pathname.data() || begin >= (m_pathname.data() + m_pathname.size()))) + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) { const size_type that_size = end - begin; size_type that_root_name_size = 0; @@ -270,17 +406,17 @@ BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_ ) { return_assign: - assign(begin, end); + p.assign(begin, end); return; } size_type this_root_name_size = 0; - find_root_directory_start(m_pathname.c_str(), m_pathname.size(), this_root_name_size); + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); if ( that_root_name_size > 0 && - (that_root_name_size != this_root_name_size || std::memcmp(m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) ) { goto return_assign; @@ -289,197 +425,219 @@ BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_ if (that_root_dir_pos < that_size) { // Remove root directory (if any) and relative path to replace with those from p - m_pathname.erase(m_pathname.begin() + this_root_name_size, m_pathname.end()); + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); } const value_type* const that_path = begin + that_root_name_size; if (!detail::is_directory_separator(*that_path)) - append_separator_if_needed(); - m_pathname.append(that_path, end); + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); } else { // overlapping source - path rhs(begin, end); - append_v4(rhs); + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); } } - else if (has_filename_v4()) + else if (path_algorithms::has_filename_v4(p)) { - m_pathname.push_back(preferred_separator); + p.m_pathname.push_back(path::preferred_separator); } } -#ifdef BOOST_WINDOWS_API +// compare -------------------------------------------------------------------------// -BOOST_FILESYSTEM_DECL path path::generic_path() const +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) { - path tmp(*this); - std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); - return tmp; + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; } -#endif // BOOST_WINDOWS_API +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} -BOOST_FILESYSTEM_DECL int path::compare_v3(path const& p) const BOOST_NOEXCEPT +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) { - return detail::lex_compare_v3(begin(), end(), p.begin(), p.end()); + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); } -BOOST_FILESYSTEM_DECL int path::compare_v4(path const& p) const BOOST_NOEXCEPT +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) { - return detail::lex_compare_v4(begin(), end(), p.begin(), p.end()); + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); } -// append_separator_if_needed ----------------------------------------------------// +// append_separator_if_needed ------------------------------------------------------// -BOOST_FILESYSTEM_DECL path::string_type::size_type path::append_separator_if_needed() +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) { - if (!m_pathname.empty() && + if (!p.m_pathname.empty() && #ifdef BOOST_WINDOWS_API - *(m_pathname.end() - 1) != colon && + *(p.m_pathname.end() - 1) != colon && #endif - !detail::is_directory_separator(*(m_pathname.end() - 1))) + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) { - string_type::size_type tmp(m_pathname.size()); - m_pathname += preferred_separator; + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); return tmp; } return 0; } -// erase_redundant_separator -----------------------------------------------------// +// erase_redundant_separator -------------------------------------------------------// -BOOST_FILESYSTEM_DECL void path::erase_redundant_separator(string_type::size_type sep_pos) +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) { - if (sep_pos // a separator was added - && sep_pos < m_pathname.size() // and something was appended - && (m_pathname[sep_pos + 1] == separator // and it was also separator + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator #ifdef BOOST_WINDOWS_API - || m_pathname[sep_pos + 1] == preferred_separator // or preferred_separator + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator #endif )) { - m_pathname.erase(m_pathname.begin() + sep_pos); // erase the added separator + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator } } // modifiers -----------------------------------------------------------------------// -#ifdef BOOST_WINDOWS_API -BOOST_FILESYSTEM_DECL path& path::make_preferred() +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) { - std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); - return *this; + p.remove_filename_and_trailing_separators(); } -#endif -BOOST_FILESYSTEM_DECL path& path::remove_filename() +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) { - size_type end_pos = find_parent_path_size(); - m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); - return *this; + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); } -BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() -{ - if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) - m_pathname.erase(m_pathname.end() - 1); - return *this; -} - -BOOST_FILESYSTEM_DECL void path::replace_extension_v3(path const& new_extension) +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) { // erase existing extension, including the dot, if any - size_type ext_pos = m_pathname.size() - extension_v3().m_pathname.size(); - m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end()); + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); if (!new_extension.empty()) { // append new_extension, adding the dot if necessary - if (new_extension.m_pathname[0] != dot) - m_pathname.push_back(dot); - m_pathname.append(new_extension.m_pathname); + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); } } -BOOST_FILESYSTEM_DECL void path::replace_extension_v4(path const& new_extension) +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) { // erase existing extension, including the dot, if any - size_type ext_pos = m_pathname.size() - find_extension_v4_size(); - m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end()); + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); if (!new_extension.empty()) { // append new_extension, adding the dot if necessary - if (new_extension.m_pathname[0] != dot) - m_pathname.push_back(dot); - m_pathname.append(new_extension.m_pathname); + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); } } // decomposition -------------------------------------------------------------------// -BOOST_FILESYSTEM_DECL size_type path::find_root_name_size() const +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) { size_type root_name_size = 0; - find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size); + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); return root_name_size; } -BOOST_FILESYSTEM_DECL size_type path::find_root_path_size() const +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) { size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size); + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); size_type size = root_name_size; - if (root_dir_pos < m_pathname.size()) + if (root_dir_pos < p.m_pathname.size()) size = root_dir_pos + 1; return size; } -BOOST_FILESYSTEM_DECL substring path::find_root_directory() const +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) { substring root_dir; size_type root_name_size = 0; - root_dir.pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size); - root_dir.size = static_cast< std::size_t >(root_dir.pos < m_pathname.size()); + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); return root_dir; } -BOOST_FILESYSTEM_DECL substring path::find_relative_path() const +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) { size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size); + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); // Skip root name, root directory and any duplicate separators size_type size = root_name_size; - if (root_dir_pos < m_pathname.size()) + if (root_dir_pos < p.m_pathname.size()) { size = root_dir_pos + 1; - for (size_type n = m_pathname.size(); size < n; ++size) + for (size_type n = p.m_pathname.size(); size < n; ++size) { - if (!detail::is_directory_separator(m_pathname[size])) + if (!detail::is_directory_separator(p.m_pathname[size])) break; } } substring rel_path; rel_path.pos = size; - rel_path.size = m_pathname.size() - size; + rel_path.size = p.m_pathname.size() - size; return rel_path; } -BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) { - const size_type size = m_pathname.size(); + const size_type size = p.m_pathname.size(); size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); - size_type filename_size = find_filename_size(m_pathname, root_name_size, size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); size_type end_pos = size - filename_size; while (true) { @@ -493,7 +651,7 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const --end_pos; - if (!detail::is_directory_separator(m_pathname[end_pos])) + if (!detail::is_directory_separator(p.m_pathname[end_pos])) { ++end_pos; break; @@ -510,13 +668,13 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const return end_pos; } -BOOST_FILESYSTEM_DECL path path::filename_v3() const +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) { - const size_type size = m_pathname.size(); + const size_type size = p.m_pathname.size(); size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); size_type filename_size, pos; - if (root_dir_pos < size && detail::is_directory_separator(m_pathname[size - 1]) && is_root_separator(m_pathname, root_dir_pos, size - 1)) + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) { // Return root directory pos = root_dir_pos; @@ -530,77 +688,77 @@ BOOST_FILESYSTEM_DECL path path::filename_v3() const } else { - filename_size = find_filename_size(m_pathname, root_name_size, size); + filename_size = find_filename_size(p.m_pathname, root_name_size, size); pos = size - filename_size; - if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(m_pathname[pos - 1]) && !is_root_separator(m_pathname, root_dir_pos, pos - 1)) + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) return detail::dot_path(); } - const value_type* p = m_pathname.c_str() + pos; - return path(p, p + filename_size); + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); } -BOOST_FILESYSTEM_DECL string_type::size_type path::find_filename_v4_size() const +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) { - const size_type size = m_pathname.size(); + const size_type size = p.m_pathname.size(); size_type root_name_size = 0; - find_root_directory_start(m_pathname.c_str(), size, root_name_size); - return find_filename_size(m_pathname, root_name_size, size); + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); } -BOOST_FILESYSTEM_DECL path path::stem_v3() const +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) { - path name(filename_v3()); - if (name != detail::dot_path() && name != detail::dot_dot_path()) + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) { - size_type pos = name.m_pathname.rfind(dot); + size_type pos = name.m_pathname.rfind(path::dot); if (pos != string_type::npos) name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); } return name; } -BOOST_FILESYSTEM_DECL path path::stem_v4() const +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) { - path name(filename_v4()); - if (name != detail::dot_path() && name != detail::dot_dot_path()) + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) { - size_type pos = name.m_pathname.rfind(dot); + size_type pos = name.m_pathname.rfind(path::dot); if (pos != 0 && pos != string_type::npos) name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); } return name; } -BOOST_FILESYSTEM_DECL path path::extension_v3() const +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) { - path name(filename_v3()); - if (name == detail::dot_path() || name == detail::dot_dot_path()) + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) return path(); - size_type pos(name.m_pathname.rfind(dot)); + size_type pos(name.m_pathname.rfind(path::dot)); return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); } -BOOST_FILESYSTEM_DECL string_type::size_type path::find_extension_v4_size() const +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) { - const size_type size = m_pathname.size(); + const size_type size = p.m_pathname.size(); size_type root_name_size = 0; - find_root_directory_start(m_pathname.c_str(), size, root_name_size); - size_type filename_size = find_filename_size(m_pathname, root_name_size, size); + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); size_type filename_pos = size - filename_size; if ( filename_size > 0u && // Check for "." and ".." filenames - !(m_pathname[filename_pos] == dot && - (filename_size == 1u || (filename_size == 2u && m_pathname[filename_pos + 1u] == dot))) + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) ) { size_type ext_pos = size; while (ext_pos > filename_pos) { --ext_pos; - if (m_pathname[ext_pos] == dot) + if (p.m_pathname[ext_pos] == path::dot) break; } @@ -611,21 +769,30 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_extension_v4_size() cons return 0u; } -// lexical operations --------------------------------------------------------------// +} // namespace detail -namespace detail { -// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier -// standard libraries didn't, so provide this needed functionality. -inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() { - for (; it1 != it1end && it2 != it2end && *it1 == *it2;) - { - ++it1; - ++it2; - } - return std::make_pair(it1, it2); + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; } -} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const { @@ -637,12 +804,12 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const return detail::dot_path(); std::ptrdiff_t n = 0; - for (; mm.second != base_e; ++mm.second) + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) { path const& p = *mm.second; - if (p == detail::dot_dot_path()) + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) --n; - else if (!p.empty() && p != detail::dot_path()) + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) ++n; } if (n < 0) @@ -652,213 +819,29 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const path tmp; for (; n > 0; --n) - tmp /= detail::dot_dot_path(); - for (; mm.first != e; ++mm.first) - tmp /= *mm.first; + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); return tmp; } -// normal --------------------------------------------------------------------------// - -BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const -{ - const value_type* const pathname = m_pathname.c_str(); - const size_type pathname_size = m_pathname.size(); - size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); - path normal(pathname, pathname + root_name_size); - #if defined(BOOST_WINDOWS_API) - for (size_type i = 0; i < root_name_size; ++i) - { - if (normal.m_pathname[i] == path::separator) - normal.m_pathname[i] = path::preferred_separator; - } -#endif - - size_type root_path_size = root_name_size; - if (root_dir_pos < pathname_size) - { - root_path_size = root_dir_pos + 1; - normal.m_pathname.push_back(preferred_separator); - } - - size_type i = root_path_size; - - // Skip redundant directory separators after the root directory - while (i < pathname_size && detail::is_directory_separator(pathname[i])) - ++i; - - if (i < pathname_size) - { - bool last_element_was_dot = false; - while (true) - { - { - const size_type start_pos = i; - - // Find next separator - i += find_separator(pathname + i, pathname_size - i); - - const size_type size = i - start_pos; - - // Skip dot elements - if (size == 1u && pathname[start_pos] == dot) - { - last_element_was_dot = true; - goto skip_append; - } - - last_element_was_dot = false; - - // Process dot dot elements - if (size == 2u && pathname[start_pos] == dot && pathname[start_pos + 1] == dot && normal.m_pathname.size() > root_path_size) - { - // Don't remove previous dot dot elements - const size_type normal_size = normal.m_pathname.size(); - size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); - size_type pos = normal_size - filename_size; - if (filename_size != 2u || normal.m_pathname[pos] != dot || normal.m_pathname[pos + 1] != dot) - { - if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) - --pos; - normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); - goto skip_append; - } - } - - // Append the element - normal.append_separator_if_needed(); - normal.m_pathname.append(pathname + start_pos, size); - } - - skip_append: - if (i == pathname_size) - break; - - // Skip directory separators, including duplicates - while (i < pathname_size && detail::is_directory_separator(pathname[i])) - ++i; - if (i == pathname_size) - { - // If a path ends with a separator, add a trailing dot element - goto append_trailing_dot; - } - } - - if (normal.empty() || last_element_was_dot) - { - append_trailing_dot: - normal.append_separator_if_needed(); - normal.m_pathname.push_back(dot); - } - } - - return normal; +BOOST_FILESYSTEM_DECL path path::generic_path() const +{ + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp; } -BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const +BOOST_FILESYSTEM_DECL path& path::make_preferred() { - const value_type* const pathname = m_pathname.c_str(); - const size_type pathname_size = m_pathname.size(); - size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); - path normal(pathname, pathname + root_name_size); - -#if defined(BOOST_WINDOWS_API) - for (size_type i = 0; i < root_name_size; ++i) - { - if (normal.m_pathname[i] == path::separator) - normal.m_pathname[i] = path::preferred_separator; - } -#endif - - size_type root_path_size = root_name_size; - if (root_dir_pos < pathname_size) - { - root_path_size = root_dir_pos + 1; - normal.m_pathname.push_back(preferred_separator); - } - - size_type i = root_path_size; - - // Skip redundant directory separators after the root directory - while (i < pathname_size && detail::is_directory_separator(pathname[i])) - ++i; - - if (i < pathname_size) - { - while (true) - { - bool last_element_was_dot = false; - { - const size_type start_pos = i; - - // Find next separator - i += find_separator(pathname + i, pathname_size - i); - - const size_type size = i - start_pos; - - // Skip dot elements - if (size == 1u && pathname[start_pos] == dot) - { - last_element_was_dot = true; - goto skip_append; - } - - // Process dot dot elements - if (size == 2u && pathname[start_pos] == dot && pathname[start_pos + 1] == dot && normal.m_pathname.size() > root_path_size) - { - // Don't remove previous dot dot elements - const size_type normal_size = normal.m_pathname.size(); - size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); - size_type pos = normal_size - filename_size; - if (filename_size != 2u || normal.m_pathname[pos] != dot || normal.m_pathname[pos + 1] != dot) - { - if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) - --pos; - normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); - goto skip_append; - } - } - - // Append the element - normal.append_separator_if_needed(); - normal.m_pathname.append(pathname + start_pos, size); - } - - skip_append: - if (i == pathname_size) - { - // If a path ends with a trailing dot after a directory element, add a trailing separator - if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) - normal.append_separator_if_needed(); - - break; - } - - // Skip directory separators, including duplicates - while (i < pathname_size && detail::is_directory_separator(pathname[i])) - ++i; - - if (i == pathname_size) - { - // If a path ends with a separator, add a trailing separator - if (!normal.empty() && !normal.filename_is_dot_dot()) - normal.append_separator_if_needed(); - break; - } - } - - // If the original path was not empty and normalized ended up being empty, make it a dot - if (normal.empty()) - normal.m_pathname.push_back(dot); - } - - return normal; + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; } +#endif // defined(BOOST_WINDOWS_API) + } // namespace filesystem } // namespace boost @@ -1001,7 +984,13 @@ find_next_separator: return pos; } -// first_element --------------------------------------------------------------------// +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// // sets pos and len of first element, excluding extra separators // if src.empty(), sets pos,len, to 0,0. @@ -1043,225 +1032,153 @@ namespace boost { namespace filesystem { namespace detail { -BOOST_FILESYSTEM_DECL -int lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2) -{ - for (; first1 != last1 && first2 != last2;) - { - if (first1->native() < first2->native()) - return -1; - if (first2->native() < first1->native()) - return 1; - BOOST_ASSERT(first2->native() == first1->native()); - first1.increment_v3(); - first2.increment_v3(); - } - if (first1 == last1 && first2 == last2) - return 0; - return first1 == last1 ? -1 : 1; -} - -BOOST_FILESYSTEM_DECL -int lex_compare_v4(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2) -{ - for (; first1 != last1 && first2 != last2;) - { - if (first1->native() < first2->native()) - return -1; - if (first2->native() < first1->native()) - return 1; - BOOST_ASSERT(first2->native() == first1->native()); - ++first1; - ++first2; - } - if (first1 == last1 && first2 == last2) - return 0; - return first1 == last1 ? -1 : 1; -} - -} // namespace detail - -//--------------------------------------------------------------------------------------// -// // -// class path::iterator implementation // -// // -//--------------------------------------------------------------------------------------// - -BOOST_FILESYSTEM_DECL path::iterator path::begin() const +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) { - iterator itr; - itr.m_path_ptr = this; - - size_type element_size; - first_element(m_pathname, itr.m_pos, element_size); - - if (element_size > 0) - { - itr.m_element = m_pathname.substr(itr.m_pos, element_size); -#ifdef BOOST_WINDOWS_API - if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == preferred_separator) - itr.m_element.m_pathname[0] = separator; -#endif - } - - return itr; -} - -BOOST_FILESYSTEM_DECL path::iterator path::end() const -{ - iterator itr; - itr.m_path_ptr = this; - itr.m_pos = m_pathname.size(); - return itr; -} - -BOOST_FILESYSTEM_DECL void path::iterator::increment_v3() -{ - const size_type size = m_path_ptr->m_pathname.size(); - BOOST_ASSERT_MSG(m_pos < size, "path::iterator increment past end()"); + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); // increment to position past current element; if current element is implicit dot, // this will cause m_pos to represent the end iterator - m_pos += m_element.m_pathname.size(); + it.m_pos += it.m_element.m_pathname.size(); // if the end is reached, we are done - if (m_pos >= size) + if (it.m_pos >= size) { - BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified"); - m_element.clear(); // aids debugging + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging return; } // process separator (Windows drive spec is only case not a separator) - if (detail::is_directory_separator(m_path_ptr->m_pathname[m_pos])) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) { size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); // detect root directory and set iterator value to the separator if it is - if (m_pos == root_dir_pos && m_element.m_pathname.size() == root_name_size) + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) { - m_element.m_pathname = separator; // generic format; see docs + it.m_element.m_pathname = path::separator; // generic format; see docs return; } // skip separators until m_pos points to the start of the next element - while (m_pos != size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos])) + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) { - ++m_pos; + ++it.m_pos; } // detect trailing separator, and treat it as ".", per POSIX spec - if (m_pos == size && - !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1)) + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) { - --m_pos; - m_element = detail::dot_path(); + --it.m_pos; + it.m_element = detail::dot_path(); return; } } // get m_element - size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, m_pos); + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); if (end_pos == string_type::npos) end_pos = size; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p + m_pos, p + end_pos); + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path::iterator::increment_v4() +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) { - const size_type size = m_path_ptr->m_pathname.size(); - BOOST_ASSERT_MSG(m_pos <= size, "path::iterator increment past end()"); + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); - if (m_element.m_pathname.empty() && (m_pos + 1) == size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos])) + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) { // The iterator was pointing to the last empty element of the path; set to end. - m_pos = size; + it.m_pos = size; return; } // increment to position past current element; if current element is implicit dot, // this will cause m_pos to represent the end iterator - m_pos += m_element.m_pathname.size(); + it.m_pos += it.m_element.m_pathname.size(); // if the end is reached, we are done - if (m_pos >= size) + if (it.m_pos >= size) { - BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified"); - m_element.clear(); // aids debugging + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging return; } // process separator (Windows drive spec is only case not a separator) - if (detail::is_directory_separator(m_path_ptr->m_pathname[m_pos])) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) { size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); // detect root directory and set iterator value to the separator if it is - if (m_pos == root_dir_pos && m_element.m_pathname.size() == root_name_size) + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) { - m_element.m_pathname = separator; // generic format; see docs + it.m_element.m_pathname = path::separator; // generic format; see docs return; } // skip separators until m_pos points to the start of the next element - while (m_pos != size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos])) + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) { - ++m_pos; + ++it.m_pos; } // detect trailing separator - if (m_pos == size && - !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1)) + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) { - --m_pos; - m_element.m_pathname.clear(); + --it.m_pos; + it.m_element.m_pathname.clear(); return; } } // get m_element - size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, m_pos); + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); if (end_pos == string_type::npos) end_pos = size; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p + m_pos, p + end_pos); + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3() +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) { - const size_type size = m_path_ptr->m_pathname.size(); - BOOST_ASSERT_MSG(m_pos > 0, "path::iterator decrement past begin()"); - BOOST_ASSERT_MSG(m_pos <= size, "path::iterator decrement after the referenced path was modified"); + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); - if (root_dir_pos < size && m_pos == root_dir_pos) + if (root_dir_pos < size && it.m_pos == root_dir_pos) { // Was pointing at root directory, decrement to root name set_to_root_name: - m_pos = 0u; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p, p + root_name_size); + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); return; } // if at end and there was a trailing non-root '/', return "." - if (m_pos == size && + if (it.m_pos == size && size > 1 && - detail::is_directory_separator(m_path_ptr->m_pathname[m_pos - 1]) && - !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1)) + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) { - --m_pos; - m_element = detail::dot_path(); + --it.m_pos; + it.m_element = detail::dot_path(); return; } // skip separators unless root directory - size_type end_pos = m_pos; + size_type end_pos = it.m_pos; while (end_pos > root_name_size) { --end_pos; @@ -1269,12 +1186,12 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3() if (end_pos == root_dir_pos) { // Decremented to the root directory - m_pos = end_pos; - m_element.m_pathname = separator; // generic format; see docs + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs return; } - if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos])) + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) { ++end_pos; break; @@ -1284,44 +1201,44 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3() if (end_pos <= root_name_size) goto set_to_root_name; - size_type filename_size = find_filename_size(m_path_ptr->m_pathname, root_name_size, end_pos); - m_pos = end_pos - filename_size; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p + m_pos, p + end_pos); + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4() +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) { - const size_type size = m_path_ptr->m_pathname.size(); - BOOST_ASSERT_MSG(m_pos > 0, "path::iterator decrement past begin()"); - BOOST_ASSERT_MSG(m_pos <= size, "path::iterator decrement after the referenced path was modified"); + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); size_type root_name_size = 0; - size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size); + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); - if (root_dir_pos < size && m_pos == root_dir_pos) + if (root_dir_pos < size && it.m_pos == root_dir_pos) { // Was pointing at root directory, decrement to root name set_to_root_name: - m_pos = 0u; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p, p + root_name_size); + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); return; } // if at end and there was a trailing '/', return "" - if (m_pos == size && + if (it.m_pos == size && size > 1 && - detail::is_directory_separator(m_path_ptr->m_pathname[m_pos - 1]) && - !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1)) + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) { - --m_pos; - m_element.m_pathname.clear(); + --it.m_pos; + it.m_element.m_pathname.clear(); return; } // skip separators unless root directory - size_type end_pos = m_pos; + size_type end_pos = it.m_pos; while (end_pos > root_name_size) { --end_pos; @@ -1329,12 +1246,12 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4() if (end_pos == root_dir_pos) { // Decremented to the root directory - m_pos = end_pos; - m_element.m_pathname = separator; // generic format; see docs + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs return; } - if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos])) + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) { ++end_pos; break; @@ -1344,10 +1261,42 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4() if (end_pos <= root_name_size) goto set_to_root_name; - size_type filename_size = find_filename_size(m_path_ptr->m_pathname, root_name_size, end_pos); - m_pos = end_pos - filename_size; - const path::value_type* p = m_path_ptr->m_pathname.c_str(); - m_element.m_pathname.assign(p + m_pos, p + end_pos); + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; } } // namespace filesystem diff --git a/contrib/restricted/boost/filesystem/src/path_traits.cpp b/contrib/restricted/boost/filesystem/src/path_traits.cpp index aa4b8815f7..baed387b4d 100644 --- a/contrib/restricted/boost/filesystem/src/path_traits.cpp +++ b/contrib/restricted/boost/filesystem/src/path_traits.cpp @@ -12,19 +12,19 @@ #include "platform_config.hpp" #include <boost/filesystem/config.hpp> -#include <boost/filesystem/path_traits.hpp> +#include <boost/filesystem/detail/path_traits.hpp> +#include <boost/filesystem/path.hpp> #include <boost/system/system_error.hpp> #include <boost/smart_ptr/scoped_array.hpp> #include <boost/assert.hpp> #include <string> #include <locale> // for codecvt_base::result -#include <cstring> // for strlen -#include <cwchar> // for wcslen +#include <cwchar> // for mbstate_t #include <cstddef> #include <boost/filesystem/detail/header.hpp> // must be the last #include -namespace pt = boost::filesystem::path_traits; +namespace pt = boost::filesystem::detail::path_traits; namespace fs = boost::filesystem; namespace bs = boost::system; @@ -51,12 +51,7 @@ BOOST_CONSTEXPR_OR_CONST std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM // convert_aux const char* to wstring // //--------------------------------------------------------------------------------------// -void convert_aux( - const char* from, - const char* from_end, - wchar_t* to, wchar_t* to_end, - std::wstring& target, - pt::codecvt_type const& cvt) +void convert_aux(const char* from, const char* from_end, wchar_t* to, wchar_t* to_end, std::wstring& target, pt::codecvt_type const& cvt) { //std::cout << std::hex // << " from=" << std::size_t(from) @@ -83,12 +78,7 @@ void convert_aux( // convert_aux const wchar_t* to string // //--------------------------------------------------------------------------------------// -void convert_aux( - const wchar_t* from, - const wchar_t* from_end, - char* to, char* to_end, - std::string& target, - pt::codecvt_type const& cvt) +void convert_aux(const wchar_t* from, const wchar_t* from_end, char* to, char* to_end, std::string& target, pt::codecvt_type const& cvt) { //std::cout << std::hex // << " from=" << std::size_t(from) @@ -119,6 +109,7 @@ void convert_aux( namespace boost { namespace filesystem { +namespace detail { namespace path_traits { //--------------------------------------------------------------------------------------// @@ -126,32 +117,29 @@ namespace path_traits { //--------------------------------------------------------------------------------------// BOOST_FILESYSTEM_DECL -void convert(const char* from, - const char* from_end, // 0 for null terminated MBCS - std::wstring& to, codecvt_type const& cvt) +void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt) { - BOOST_ASSERT(from); - - if (!from_end) // null terminated - { - from_end = from + std::strlen(from); - } - if (from == from_end) return; + BOOST_ASSERT(from != NULL); + BOOST_ASSERT(from_end != NULL); + + if (!cvt) + cvt = &fs::path::codecvt(); + std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK // dynamically allocate a buffer only if source is unusually large if (buf_size > default_codecvt_buf_size) { boost::scoped_array< wchar_t > buf(new wchar_t[buf_size]); - convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, cvt); + convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt); } else { wchar_t buf[default_codecvt_buf_size]; - convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, cvt); + convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt); } } @@ -160,20 +148,17 @@ void convert(const char* from, //--------------------------------------------------------------------------------------// BOOST_FILESYSTEM_DECL -void convert(const wchar_t* from, - const wchar_t* from_end, // 0 for null terminated MBCS - std::string& to, codecvt_type const& cvt) +void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt) { - BOOST_ASSERT(from); - - if (!from_end) // null terminated - { - from_end = from + std::wcslen(from); - } - if (from == from_end) return; + BOOST_ASSERT(from != NULL); + BOOST_ASSERT(from_end != NULL); + + if (!cvt) + cvt = &fs::path::codecvt(); + // The codecvt length functions may not be implemented, and I don't really // understand them either. Thus this code is just a guess; if it turns // out the buffer is too small then an error will be reported and the code @@ -185,16 +170,17 @@ void convert(const wchar_t* from, if (buf_size > default_codecvt_buf_size) { boost::scoped_array< char > buf(new char[buf_size]); - convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, cvt); + convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt); } else { char buf[default_codecvt_buf_size]; - convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, cvt); + convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt); } } } // namespace path_traits +} // namespace detail } // namespace filesystem } // namespace boost diff --git a/contrib/restricted/boost/filesystem/src/windows_tools.hpp b/contrib/restricted/boost/filesystem/src/windows_tools.hpp index 8a2de7f0c9..ca62bfbf7e 100644 --- a/contrib/restricted/boost/filesystem/src/windows_tools.hpp +++ b/contrib/restricted/boost/filesystem/src/windows_tools.hpp @@ -1,7 +1,8 @@ // windows_tools.hpp -----------------------------------------------------------------// -// Copyright 2002-2009, 2014 Beman Dawes // Copyright 2001 Dietmar Kuehl +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2021-2022 Andrey Semashev // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt @@ -23,6 +24,10 @@ #include <boost/filesystem/detail/header.hpp> // must be the last #include +#ifndef IO_REPARSE_TAG_DEDUP +#define IO_REPARSE_TAG_DEDUP (0x80000013L) +#endif + #ifndef IO_REPARSE_TAG_MOUNT_POINT #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) #endif @@ -57,14 +62,14 @@ inline boost::filesystem::perms make_permissions(boost::filesystem::path const& boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read; if ((attr & FILE_ATTRIBUTE_READONLY) == 0u) prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write; - boost::filesystem::path ext = p.extension(); + boost::filesystem::path ext = detail::path_algorithms::extension_v4(p); wchar_t const* q = ext.c_str(); if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD")) prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe; return prms; } -bool is_reparse_point_a_symlink_ioctl(HANDLE h); +ULONG get_reparse_point_tag_ioctl(HANDLE h, boost::filesystem::path const& p, boost::system::error_code* ec); inline bool is_reparse_point_tag_a_symlink(ULONG reparse_point_tag) { @@ -156,6 +161,9 @@ struct object_attributes #ifndef FILE_DIRECTORY_FILE #define FILE_DIRECTORY_FILE 0x00000001 #endif +#ifndef FILE_SYNCHRONOUS_IO_NONALERT +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#endif #ifndef FILE_OPEN_FOR_BACKUP_INTENT #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 #endif diff --git a/contrib/restricted/boost/filesystem/ya.make b/contrib/restricted/boost/filesystem/ya.make index fb19913ed1..bd15cb93a5 100644 --- a/contrib/restricted/boost/filesystem/ya.make +++ b/contrib/restricted/boost/filesystem/ya.make @@ -1,4 +1,4 @@ -# Generated by devtools/yamaker from nixpkgs 22.05. +# Generated by devtools/yamaker from nixpkgs 22.11. LIBRARY() @@ -6,9 +6,9 @@ LICENSE(BSL-1.0) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(1.80.0) +VERSION(1.83.0) -ORIGINAL_SOURCE(https://github.com/boostorg/filesystem/archive/boost-1.80.0.tar.gz) +ORIGINAL_SOURCE(https://github.com/boostorg/filesystem/archive/boost-1.83.0.tar.gz) PEERDIR( contrib/restricted/boost/assert |