, which removes the filename and directory separators preceding it from the path. This behavior is similar to path::remove_filename in Filesystem v3, but is also usable in v4.
Added path::replace_filename, which replaces filename in a path.
+
Updated implementation of the library version selection to avoid ODR violations. (#279)
1.81.0
diff --git a/include/boost/filesystem/path.hpp b/include/boost/filesystem/path.hpp
index 75a3db6..61278ef 100644
--- a/include/boost/filesystem/path.hpp
+++ b/include/boost/filesystem/path.hpp
@@ -43,6 +43,8 @@
namespace boost {
namespace filesystem {
+class path;
+
namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants
template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
@@ -67,15 +69,83 @@ 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
-{
- std::size_t pos;
- std::size_t size;
-};
+class path_iterator;
+class path_reverse_iterator;
} // namespace path_detail
+namespace detail {
+
+struct path_algorithms
+{
+ // 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;
+ };
+
+ typedef path_traits::path_native_char_type value_type;
+ typedef std::basic_string< value_type > string_type;
+
+ 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);
+
+ 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);
+
+ BOOST_FILESYSTEM_DECL static void remove_filename_v3(path& p);
+ BOOST_FILESYSTEM_DECL static void remove_filename_v4(path& p);
+
+ 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);
+
+ BOOST_FILESYSTEM_DECL static path lexically_normal_v3(path const& p);
+ BOOST_FILESYSTEM_DECL static path lexically_normal_v4(path const& p);
+
+ 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);
+
+ 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
+
//------------------------------------------------------------------------------------//
// //
// class path //
@@ -91,12 +161,16 @@ class path :
#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 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 -----
@@ -245,10 +319,9 @@ private:
};
public:
- class iterator;
- friend class iterator;
+ typedef path_detail::path_iterator iterator;
typedef iterator const_iterator;
- class reverse_iterator;
+ typedef path_detail::path_reverse_iterator reverse_iterator;
typedef reverse_iterator const_reverse_iterator;
public:
@@ -725,11 +798,7 @@ public:
return append(source);
}
- BOOST_FORCEINLINE path& append(path const& p)
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
- return *this;
- }
+ path& append(path const& p);
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
@@ -754,11 +823,7 @@ public:
return *this;
}
- BOOST_FORCEINLINE path& append(path const& p, codecvt_type const&)
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
- return *this;
- }
+ path& append(path const& p, codecvt_type const&);
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
@@ -783,11 +848,7 @@ public:
return *this;
}
- BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end)
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end);
- return *this;
- }
+ path& append(const value_type* begin, const value_type* end);
template< typename InputIterator >
BOOST_FORCEINLINE typename boost::enable_if_c<
@@ -803,11 +864,7 @@ public:
return *this;
}
- BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end, codecvt_type const&)
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end);
- return *this;
- }
+ path& append(const value_type* begin, const value_type* end, codecvt_type const&);
template< typename InputIterator >
BOOST_FORCEINLINE typename boost::enable_if_c<
@@ -835,19 +892,12 @@ public:
#else // BOOST_WINDOWS_API
BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes
#endif
- BOOST_FORCEINLINE path& remove_filename()
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(remove_filename)();
- return *this;
- }
+ path& remove_filename();
BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators();
BOOST_FILESYSTEM_DECL path& remove_trailing_separator();
BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement);
- BOOST_FORCEINLINE path& replace_extension(path const& new_extension = path())
- {
- BOOST_FILESYSTEM_VERSIONED_SYM(replace_extension)(new_extension);
- return *this;
- }
+ path& replace_extension(path const& new_extension = path());
+
void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); }
// ----- observers -----
@@ -953,10 +1003,7 @@ public:
// ----- compare -----
- BOOST_FORCEINLINE int compare(path const& p) const // generic, lexicographical
- {
- return BOOST_FILESYSTEM_VERSIONED_SYM(compare)(p);
- }
+ int compare(path const& p) const; // generic, lexicographical
template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c<
@@ -1002,42 +1049,42 @@ public:
// ----- 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 rel_path = find_relative_path();
+ 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(); }
@@ -1053,7 +1100,7 @@ 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;
@@ -1110,56 +1157,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 remove_filename_v3();
- BOOST_FILESYSTEM_DECL void remove_filename_v4();
-
- 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_FILESYSTEM_DECL int compare_v4(path const& p) const;
-
- 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);
-
- // 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
@@ -1174,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
@@ -1184,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
>
@@ -1198,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
@@ -1227,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())
@@ -1254,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;
}
}
@@ -1273,38 +1264,24 @@ 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
-BOOST_FORCEINLINE bool lexicographical_compare(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2)
-{
- return BOOST_FILESYSTEM_VERSIONED_SYM(detail::lex_compare)(first1, last1, first2, last2) < 0;
-}
-
-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);
-}
-
BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs)
{
return lhs.compare(rhs) == 0;
@@ -1545,6 +1522,41 @@ 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
@@ -1552,6 +1564,21 @@ inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT
// 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);
@@ -1608,7 +1635,7 @@ inline bool path::filename_is_dot_dot() const
#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::lexically_normal() instead")
-inline path& path::normalize()
+BOOST_FORCEINLINE path& path::normalize()
{
path tmp(lexically_normal());
m_pathname.swap(tmp.m_pathname);
@@ -1617,6 +1644,100 @@ inline path& path::normalize()
#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 //
//--------------------------------------------------------------------------------------//
diff --git a/src/directory.cpp b/src/directory.cpp
index 7eeda26..7ec7d12 100644
--- a/src/directory.cpp
+++ b/src/directory.cpp
@@ -1109,7 +1109,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
+ (
+#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;
}
diff --git a/src/operations.cpp b/src/operations.cpp
index 5e5e934..e937ced 100644
--- a/src/operations.cpp
+++ b/src/operations.cpp
@@ -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
@@ -2007,7 +2007,7 @@ 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_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -2393,12 +2393,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;
}
@@ -2445,13 +2445,13 @@ 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)
+ if (path_algorithms::compare_v4(result, root) != 0)
result.remove_filename_and_trailing_separators();
continue;
}
@@ -2467,7 +2467,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"
@@ -2496,10 +2496,10 @@ path canonical(path const& p, path const& base, system::error_code* ec)
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();
@@ -2507,15 +2507,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;
}
@@ -2611,10 +2611,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);
@@ -2650,7 +2650,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);
}
@@ -2705,8 +2709,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;
@@ -3096,9 +3104,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);
@@ -3115,17 +3123,17 @@ bool create_directories(path const& p, system::error_code* ec)
}
}
- --it;
+ 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 = detail::create_directory(parent, NULL, &local_ec);
if (BOOST_UNLIKELY(!!local_ec))
@@ -4318,11 +4326,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)
@@ -4332,7 +4337,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;
@@ -4357,7 +4362,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;
@@ -4403,7 +4408,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())
@@ -4440,7 +4450,7 @@ 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));
if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
@@ -4459,7 +4469,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
}
if (head.empty())
- return p.lexically_normal();
+ return path_algorithms::lexically_normal_v4(p);
path const& dot_p = dot_path();
path const& dot_dot_p = dot_dot_path();
@@ -4482,7 +4492,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
{
BOOST_ASSERT(itr != p_end);
head = *itr;
- ++itr;
+ path_algorithms::increment_v4(itr);
}
if (p.has_root_directory())
@@ -4491,7 +4501,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
// Convert generic separator returned by the iterator for the root directory to
// the preferred separator.
head += path::preferred_separator;
- ++itr;
+ path_algorithms::increment_v4(itr);
}
if (!head.empty())
@@ -4509,22 +4519,22 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (head_status.type() == fs::file_not_found)
{
// If the root path does not exist then no path element exists
- return p.lexically_normal();
+ 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; ++itr)
+ 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 (p_elem == dot_p)
+ if (path_algorithms::compare_v4(p_elem, dot_p) == 0)
continue;
- if (p_elem == dot_dot_p)
+ if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0)
{
if (head.has_relative_path())
head.remove_filename_and_trailing_separators();
@@ -4532,7 +4542,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
continue;
}
- head /= p_elem;
+ 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))
@@ -4552,18 +4562,18 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
}
if (head.empty())
- return p.lexically_normal();
+ return path_algorithms::lexically_normal_v4(p);
#endif
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;
- 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;
}
@@ -4579,11 +4589,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/src/path.cpp b/src/path.cpp
index 5d7b2ba..1d9748c 100644
--- a/src/path.cpp
+++ b/src/path.cpp
@@ -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,458 +150,26 @@ inline void first_element(string_type const& src, size_type& element_pos, size_t
namespace boost {
namespace filesystem {
-
-BOOST_FILESYSTEM_DECL void path::append_v3(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 (!detail::is_directory_separator(*begin))
- append_separator_if_needed();
- m_pathname.append(begin, end);
- }
- else
- {
- // overlapping source
- string_type rhs(begin, end);
- append_v3(rhs.data(), rhs.data() + rhs.size());
- }
- }
-}
-
-BOOST_FILESYSTEM_DECL void path::append_v4(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())))
- {
- const size_type that_size = end - begin;
- size_type that_root_name_size = 0;
- size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size);
-
- // if (p.is_absolute())
- if
- (
-#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE)
- that_root_name_size > 0 &&
-#endif
- that_root_dir_pos < that_size
- )
- {
- return_assign:
- 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);
-
- 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)
- )
- {
- goto return_assign;
- }
-
- 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());
- }
-
- 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);
- }
- else
- {
- // overlapping source
- string_type rhs(begin, end);
- append_v4(rhs.data(), rhs.data() + rhs.size());
- }
- }
- else if (has_filename_v4())
- {
- m_pathname.push_back(preferred_separator);
- }
-}
-
-#ifdef BOOST_WINDOWS_API
-
-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;
-}
-
-#endif // BOOST_WINDOWS_API
-
-BOOST_FILESYSTEM_DECL int path::compare_v3(path const& p) const
-{
- return detail::lex_compare_v3(begin(), end(), p.begin(), p.end());
-}
-
-BOOST_FILESYSTEM_DECL int path::compare_v4(path const& p) const
-{
- return detail::lex_compare_v4(begin(), end(), p.begin(), p.end());
-}
-
-// append_separator_if_needed ----------------------------------------------------//
-
-BOOST_FILESYSTEM_DECL path::string_type::size_type path::append_separator_if_needed()
-{
- if (!m_pathname.empty() &&
-#ifdef BOOST_WINDOWS_API
- *(m_pathname.end() - 1) != colon &&
-#endif
- !detail::is_directory_separator(*(m_pathname.end() - 1)))
- {
- string_type::size_type tmp(m_pathname.size());
- m_pathname += preferred_separator;
- return tmp;
- }
- return 0;
-}
-
-// erase_redundant_separator -----------------------------------------------------//
-
-BOOST_FILESYSTEM_DECL void path::erase_redundant_separator(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
-#ifdef BOOST_WINDOWS_API
- || m_pathname[sep_pos + 1] == preferred_separator // or preferred_separator
-#endif
- ))
- {
- m_pathname.erase(m_pathname.begin() + sep_pos); // erase the added separator
- }
-}
-
-// modifiers -----------------------------------------------------------------------//
-
-#ifdef BOOST_WINDOWS_API
-BOOST_FILESYSTEM_DECL path& path::make_preferred()
-{
- std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
- return *this;
-}
-#endif
-
-BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators()
-{
- size_type end_pos = find_parent_path_size();
- m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end());
- return *this;
-}
-
-BOOST_FILESYSTEM_DECL void path::remove_filename_v3()
-{
- remove_filename_and_trailing_separators();
-}
-
-BOOST_FILESYSTEM_DECL void path::remove_filename_v4()
-{
- size_type filename_size = find_filename_v4_size();
- m_pathname.erase(m_pathname.begin() + (m_pathname.size() - filename_size), 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 path& path::replace_filename(path const& replacement)
-{
- remove_filename_v4();
- append_v4(replacement.m_pathname.c_str(), replacement.m_pathname.c_str() + replacement.m_pathname.size());
- return *this;
-}
-
-BOOST_FILESYSTEM_DECL void path::replace_extension_v3(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());
-
- 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);
- }
-}
-
-BOOST_FILESYSTEM_DECL void path::replace_extension_v4(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());
-
- 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);
- }
-}
-
-// decomposition -------------------------------------------------------------------//
-
-BOOST_FILESYSTEM_DECL size_type path::find_root_name_size() const
-{
- size_type root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size);
- return root_name_size;
-}
-
-BOOST_FILESYSTEM_DECL size_type path::find_root_path_size() const
-{
- 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 size = root_name_size;
- if (root_dir_pos < m_pathname.size())
- size = root_dir_pos + 1;
-
- return size;
-}
-
-BOOST_FILESYSTEM_DECL substring path::find_root_directory() const
-{
- 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());
- return root_dir;
-}
-
-BOOST_FILESYSTEM_DECL substring path::find_relative_path() const
-{
- 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);
-
- // Skip root name, root directory and any duplicate separators
- size_type size = root_name_size;
- if (root_dir_pos < m_pathname.size())
- {
- size = root_dir_pos + 1;
-
- for (size_type n = m_pathname.size(); size < n; ++size)
- {
- if (!detail::is_directory_separator(m_pathname[size]))
- break;
- }
- }
-
- substring rel_path;
- rel_path.pos = size;
- rel_path.size = m_pathname.size() - size;
-
- return rel_path;
-}
-
-BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const
-{
- const size_type size = 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 filename_size = find_filename_size(m_pathname, root_name_size, size);
- size_type end_pos = size - filename_size;
- while (true)
- {
- if (end_pos <= root_name_size)
- {
- // Keep the root name as the parent path if there was a filename
- if (filename_size == 0)
- end_pos = 0u;
- break;
- }
-
- --end_pos;
-
- if (!detail::is_directory_separator(m_pathname[end_pos]))
- {
- ++end_pos;
- break;
- }
-
- if (end_pos == root_dir_pos)
- {
- // Keep the trailing root directory if there was a filename
- end_pos += filename_size > 0;
- break;
- }
- }
-
- return end_pos;
-}
-
-BOOST_FILESYSTEM_DECL path path::filename_v3() const
-{
- const size_type size = 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 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))
- {
- // Return root directory
- pos = root_dir_pos;
- filename_size = 1u;
- }
- else if (root_name_size == size)
- {
- // Return root name
- pos = 0u;
- filename_size = root_name_size;
- }
- else
- {
- filename_size = find_filename_size(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))
- return detail::dot_path();
- }
-
- const value_type* p = m_pathname.c_str() + pos;
- return path(p, p + filename_size);
-}
-
-BOOST_FILESYSTEM_DECL string_type::size_type path::find_filename_v4_size() const
-{
- const size_type size = 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);
-}
-
-BOOST_FILESYSTEM_DECL path path::stem_v3() const
-{
- path name(filename_v3());
- if (name != detail::dot_path() && name != detail::dot_dot_path())
- {
- size_type pos = name.m_pathname.rfind(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
-{
- path name(filename_v4());
- if (name != detail::dot_path() && name != detail::dot_dot_path())
- {
- size_type pos = name.m_pathname.rfind(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
-{
- path name(filename_v3());
- if (name == detail::dot_path() || name == detail::dot_dot_path())
- return path();
- size_type pos(name.m_pathname.rfind(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
-{
- const size_type size = 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);
- 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)))
- )
- {
- size_type ext_pos = size;
- while (ext_pos > filename_pos)
- {
- --ext_pos;
- if (m_pathname[ext_pos] == dot)
- break;
- }
-
- if (ext_pos > filename_pos)
- return size - ext_pos;
- }
-
- return 0u;
-}
-
-// lexical operations --------------------------------------------------------------//
-
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)
{
- for (; it1 != it1end && it2 != it2end && *it1 == *it2;)
+ for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;)
{
- ++it1;
- ++it2;
+ path_algorithms::increment_v4(it1);
+ path_algorithms::increment_v4(it2);
}
return std::make_pair(it1, it2);
}
-} // namespace detail
-
-BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
-{
- path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end();
- std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e);
- if (mm.first == b && mm.second == base_b)
- return path();
- if (mm.first == e && mm.second == base_e)
- return detail::dot_path();
-
- std::ptrdiff_t n = 0;
- for (; mm.second != base_e; ++mm.second)
- {
- path const& p = *mm.second;
- if (p == detail::dot_dot_path())
- --n;
- else if (!p.empty() && p != detail::dot_path())
- ++n;
- }
- if (n < 0)
- return path();
- if (n == 0 && (mm.first == e || mm.first->empty()))
- return detail::dot_path();
-
- path tmp;
- for (; n > 0; --n)
- tmp /= detail::dot_dot_path();
- for (; mm.first != e; ++mm.first)
- tmp /= *mm.first;
- return tmp;
-}
// normal --------------------------------------------------------------------------//
-BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p)
{
- const value_type* const pathname = m_pathname.c_str();
- const size_type pathname_size = m_pathname.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);
@@ -619,7 +186,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
if (root_dir_pos < pathname_size)
{
root_path_size = root_dir_pos + 1;
- normal.m_pathname.push_back(preferred_separator);
+ normal.m_pathname.push_back(path::preferred_separator);
}
size_type i = root_path_size;
@@ -642,7 +209,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
const size_type size = i - start_pos;
// Skip dot elements
- if (size == 1u && pathname[start_pos] == dot)
+ if (size == 1u && pathname[start_pos] == path::dot)
{
last_element_was_dot = true;
goto skip_append;
@@ -651,13 +218,13 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
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)
+ 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] != dot || normal.m_pathname[pos + 1] != dot)
+ 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;
@@ -667,7 +234,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
}
// Append the element
- normal.append_separator_if_needed();
+ path_algorithms::append_separator_if_needed(normal);
normal.m_pathname.append(pathname + start_pos, size);
}
@@ -689,18 +256,18 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
if (normal.empty() || last_element_was_dot)
{
append_trailing_dot:
- normal.append_separator_if_needed();
- normal.m_pathname.push_back(dot);
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.push_back(path::dot);
}
}
return normal;
}
-BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p)
{
- const value_type* const pathname = m_pathname.c_str();
- const size_type pathname_size = m_pathname.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);
@@ -717,7 +284,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
if (root_dir_pos < pathname_size)
{
root_path_size = root_dir_pos + 1;
- normal.m_pathname.push_back(preferred_separator);
+ normal.m_pathname.push_back(path::preferred_separator);
}
size_type i = root_path_size;
@@ -740,20 +307,20 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
const size_type size = i - start_pos;
// Skip dot elements
- if (size == 1u && pathname[start_pos] == dot)
+ 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] == dot && pathname[start_pos + 1] == dot && normal.m_pathname.size() > root_path_size)
+ 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] != dot || normal.m_pathname[pos + 1] != dot)
+ 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;
@@ -763,7 +330,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
}
// Append the element
- normal.append_separator_if_needed();
+ path_algorithms::append_separator_if_needed(normal);
normal.m_pathname.append(pathname + start_pos, size);
}
@@ -772,7 +339,7 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
{
// 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();
+ path_algorithms::append_separator_if_needed(normal);
break;
}
@@ -785,19 +352,496 @@ BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
{
// If a path ends with a separator, add a trailing separator
if (!normal.empty() && !normal.filename_is_dot_dot())
- normal.append_separator_if_needed();
+ path_algorithms::append_separator_if_needed(normal);
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);
+ 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
+ {
+ // overlapping source
+ string_type rhs(begin, end);
+ path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size());
+ }
+ }
+}
+
+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 < 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;
+ size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size);
+
+ // if (p.is_absolute())
+ if
+ (
+#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE)
+ that_root_name_size > 0 &&
+#endif
+ that_root_dir_pos < that_size
+ )
+ {
+ return_assign:
+ p.assign(begin, end);
+ return;
+ }
+
+ size_type this_root_name_size = 0;
+ 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(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0)
+ )
+ {
+ goto return_assign;
+ }
+
+ if (that_root_dir_pos < that_size)
+ {
+ // Remove root directory (if any) and relative path to replace with those from p
+ 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))
+ path_algorithms::append_separator_if_needed(p);
+ p.m_pathname.append(that_path, end);
+ }
+ else
+ {
+ // overlapping source
+ string_type rhs(begin, end);
+ path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size());
+ }
+ }
+ else if (path_algorithms::has_filename_v4(p))
+ {
+ p.m_pathname.push_back(path::preferred_separator);
+ }
+}
+
+// compare -------------------------------------------------------------------------//
+
+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
+)
+{
+ 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;
+}
+
+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_algorithms::compare_v3(path const& left, path const& right)
+{
+ return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end());
+}
+
+BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right)
+{
+ return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end());
+}
+
+// append_separator_if_needed ------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p)
+{
+ if (!p.m_pathname.empty() &&
+#ifdef BOOST_WINDOWS_API
+ *(p.m_pathname.end() - 1) != colon &&
+#endif
+ !detail::is_directory_separator(*(p.m_pathname.end() - 1)))
+ {
+ string_type::size_type tmp(p.m_pathname.size());
+ p.m_pathname.push_back(path::preferred_separator);
+ return tmp;
+ }
+ return 0;
+}
+
+// erase_redundant_separator -------------------------------------------------------//
+
+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 < 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
+ || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator
+#endif
+ ))
+ {
+ p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator
+ }
+}
+
+// modifiers -----------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p)
+{
+ p.remove_filename_and_trailing_separators();
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p)
+{
+ 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 void path_algorithms::replace_extension_v3(path& p, path const& new_extension)
+{
+ // erase existing extension, including the dot, if any
+ 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] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
+ }
+}
+
+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 = 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] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
+ }
+}
+
+// decomposition -------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p)
+{
+ size_type root_name_size = 0;
+ 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_algorithms::find_root_path_size(path const& p)
+{
+ size_type root_name_size = 0;
+ 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 < p.m_pathname.size())
+ size = root_dir_pos + 1;
+
+ return size;
+}
+
+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(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 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(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 < p.m_pathname.size())
+ {
+ size = root_dir_pos + 1;
+
+ for (size_type n = p.m_pathname.size(); size < n; ++size)
+ {
+ if (!detail::is_directory_separator(p.m_pathname[size]))
+ break;
+ }
+ }
+
+ substring rel_path;
+ rel_path.pos = size;
+ rel_path.size = p.m_pathname.size() - size;
+
+ return rel_path;
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ 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(p.m_pathname, root_name_size, size);
+ size_type end_pos = size - filename_size;
+ while (true)
+ {
+ if (end_pos <= root_name_size)
+ {
+ // Keep the root name as the parent path if there was a filename
+ if (filename_size == 0)
+ end_pos = 0u;
+ break;
+ }
+
+ --end_pos;
+
+ if (!detail::is_directory_separator(p.m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+
+ if (end_pos == root_dir_pos)
+ {
+ // Keep the trailing root directory if there was a filename
+ end_pos += filename_size > 0;
+ break;
+ }
+ }
+
+ return end_pos;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ 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(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1))
+ {
+ // Return root directory
+ pos = root_dir_pos;
+ filename_size = 1u;
+ }
+ else if (root_name_size == size)
+ {
+ // Return root name
+ pos = 0u;
+ filename_size = root_name_size;
+ }
+ else
+ {
+ 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(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1))
+ return detail::dot_path();
+ }
+
+ const value_type* ptr = p.m_pathname.c_str() + pos;
+ return path(ptr, ptr + filename_size);
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ 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_algorithms::stem_v3(path const& p)
+{
+ 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(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_algorithms::stem_v4(path const& p)
+{
+ 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(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_algorithms::extension_v3(path const& p)
+{
+ 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(path::dot));
+ return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos);
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ 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
+ !(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 (p.m_pathname[ext_pos] == path::dot)
+ break;
+ }
+
+ if (ext_pos > filename_pos)
+ return size - ext_pos;
+ }
+
+ return 0u;
+}
+
+} // namespace detail
+
+BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators()
+{
+ 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;
+}
+
+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
+{
+ path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end();
+ std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e);
+ if (mm.first == b && mm.second == base_b)
+ return path();
+ if (mm.first == e && mm.second == base_e)
+ return detail::dot_path();
+
+ std::ptrdiff_t n = 0;
+ for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second))
+ {
+ path const& p = *mm.second;
+ if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0)
+ --n;
+ else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0)
+ ++n;
+ }
+ if (n < 0)
+ return path();
+ if (n == 0 && (mm.first == e || mm.first->empty()))
+ return detail::dot_path();
+
+ path tmp;
+ for (; n > 0; --n)
+ 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;
+}
+
+#if defined(BOOST_WINDOWS_API)
+
+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::make_preferred()
+{
+ std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
+ return *this;
+}
+
+#endif // defined(BOOST_WINDOWS_API)
+
} // namespace filesystem
} // namespace boost
@@ -940,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.
@@ -982,49 +1032,244 @@ 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)
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it)
{
- for (; first1 != last1 && first2 != last2;)
+ 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
+ it.m_pos += it.m_element.m_pathname.size();
+
+ // if the end is reached, we are done
+ if (it.m_pos >= size)
{
- 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();
+ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified");
+ it.m_element.clear(); // aids debugging
+ return;
}
- if (first1 == last1 && first2 == last2)
- return 0;
- return first1 == last1 ? -1 : 1;
+
+ // process separator (Windows drive spec is only case not a separator)
+ 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(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 (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
+ {
+ 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 (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ ++it.m_pos;
+ }
+
+ // detect trailing separator, and treat it as ".", per POSIX spec
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element = detail::dot_path();
+ return;
+ }
+ }
+
+ // get m_element
+ 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 = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
}
-BOOST_FILESYSTEM_DECL
-int lex_compare_v4(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2)
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it)
{
- for (; first1 != last1 && first2 != last2;)
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()");
+
+ 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]))
{
- if (first1->native() < first2->native())
- return -1;
- if (first2->native() < first1->native())
- return 1;
- BOOST_ASSERT(first2->native() == first1->native());
- ++first1;
- ++first2;
+ // The iterator was pointing to the last empty element of the path; set to end.
+ it.m_pos = size;
+ return;
}
- if (first1 == last1 && first2 == last2)
- return 0;
- return first1 == last1 ? -1 : 1;
+
+ // increment to position past current element; if current element is implicit dot,
+ // this will cause m_pos to represent the end iterator
+ it.m_pos += it.m_element.m_pathname.size();
+
+ // if the end is reached, we are done
+ if (it.m_pos >= size)
+ {
+ 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(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ size_type root_name_size = 0;
+ 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 (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
+ {
+ 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 (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ ++it.m_pos;
+ }
+
+ // detect trailing separator
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
+ return;
+ }
+ }
+
+ // get m_element
+ 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 = 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_algorithms::decrement_v3(path_detail::path_iterator& it)
+{
+ 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(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
+ {
+ // Was pointing at root directory, decrement to root name
+ set_to_root_name:
+ 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 (it.m_pos == size &&
+ size > 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))
+ {
+ --it.m_pos;
+ it.m_element = detail::dot_path();
+ return;
+ }
+
+ // skip separators unless root directory
+ size_type end_pos = it.m_pos;
+ while (end_pos > root_name_size)
+ {
+ --end_pos;
+
+ if (end_pos == root_dir_pos)
+ {
+ // Decremented to the root directory
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+ }
+
+ if (end_pos <= root_name_size)
+ goto set_to_root_name;
+
+ 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_algorithms::decrement_v4(path_detail::path_iterator& it)
+{
+ 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(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
+ {
+ // Was pointing at root directory, decrement to root name
+ set_to_root_name:
+ 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 (it.m_pos == size &&
+ size > 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))
+ {
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
+ return;
+ }
+
+ // skip separators unless root directory
+ size_type end_pos = it.m_pos;
+ while (end_pos > root_name_size)
+ {
+ --end_pos;
+
+ if (end_pos == root_dir_pos)
+ {
+ // Decremented to the root directory
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+ }
+
+ if (end_pos <= root_name_size)
+ goto set_to_root_name;
+
+ 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
-//--------------------------------------------------------------------------------------//
-// //
-// class path::iterator implementation //
-// //
-//--------------------------------------------------------------------------------------//
+// path iterators ------------------------------------------------------------------//
BOOST_FILESYSTEM_DECL path::iterator path::begin() const
{
@@ -1038,8 +1283,8 @@ BOOST_FILESYSTEM_DECL path::iterator path::begin() const
{
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;
+ 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
}
@@ -1054,241 +1299,6 @@ BOOST_FILESYSTEM_DECL path::iterator path::end() const
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()");
-
- // 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();
-
- // if the end is reached, we are done
- if (m_pos >= size)
- {
- BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified");
- 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]))
- {
- 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);
-
- // 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)
- {
- m_element.m_pathname = 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]))
- {
- ++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))
- {
- --m_pos;
- m_element = detail::dot_path();
- return;
- }
- }
-
- // get m_element
- size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, 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);
-}
-
-BOOST_FILESYSTEM_DECL void path::iterator::increment_v4()
-{
- const size_type size = m_path_ptr->m_pathname.size();
- BOOST_ASSERT_MSG(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]))
- {
- // The iterator was pointing to the last empty element of the path; set to end.
- 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();
-
- // if the end is reached, we are done
- if (m_pos >= size)
- {
- BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified");
- 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]))
- {
- 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);
-
- // 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)
- {
- m_element.m_pathname = 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]))
- {
- ++m_pos;
- }
-
- // detect trailing separator
- if (m_pos == size &&
- !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1))
- {
- --m_pos;
- m_element.m_pathname.clear();
- return;
- }
- }
-
- // get m_element
- size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, 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);
-}
-
-BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3()
-{
- 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");
-
- 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);
-
- if (root_dir_pos < size && 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);
- return;
- }
-
- // if at end and there was a trailing non-root '/', return "."
- if (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))
- {
- --m_pos;
- m_element = detail::dot_path();
- return;
- }
-
- // skip separators unless root directory
- size_type end_pos = m_pos;
- while (end_pos > root_name_size)
- {
- --end_pos;
-
- if (end_pos == root_dir_pos)
- {
- // Decremented to the root directory
- m_pos = end_pos;
- m_element.m_pathname = separator; // generic format; see docs
- return;
- }
-
- if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos]))
- {
- ++end_pos;
- break;
- }
- }
-
- 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);
-}
-
-BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4()
-{
- 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");
-
- 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);
-
- if (root_dir_pos < size && 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);
- return;
- }
-
- // if at end and there was a trailing '/', return ""
- if (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))
- {
- --m_pos;
- m_element.m_pathname.clear();
- return;
- }
-
- // skip separators unless root directory
- size_type end_pos = m_pos;
- while (end_pos > root_name_size)
- {
- --end_pos;
-
- if (end_pos == root_dir_pos)
- {
- // Decremented to the root directory
- m_pos = end_pos;
- m_element.m_pathname = separator; // generic format; see docs
- return;
- }
-
- if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos]))
- {
- ++end_pos;
- break;
- }
- }
-
- 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);
-}
-
} // namespace filesystem
} // namespace boost
diff --git a/src/windows_tools.hpp b/src/windows_tools.hpp
index 0b1d198..122d5cf 100644
--- a/src/windows_tools.hpp
+++ b/src/windows_tools.hpp
@@ -62,7 +62,7 @@ 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;