aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/filesystem/src/path.cpp
diff options
context:
space:
mode:
authorsnaury <snaury@yandex-team.com>2024-10-16 12:16:48 +0300
committersnaury <snaury@yandex-team.com>2024-10-16 12:32:13 +0300
commite0fb25470a47f0c243091ed28bf54a186f732f6a (patch)
treee85dfe628401f4f21749ab95b9d711242e3b49cd /contrib/restricted/boost/filesystem/src/path.cpp
parentb3b4a0b9681eb0981f9958a426c95a53f79169a7 (diff)
downloadydb-e0fb25470a47f0c243091ed28bf54a186f732f6a.tar.gz
ydblib: add jinja2cpp
commit_hash:f3563041f6f6f7443e75fc99acd2c967d0debb04
Diffstat (limited to 'contrib/restricted/boost/filesystem/src/path.cpp')
-rw-r--r--contrib/restricted/boost/filesystem/src/path.cpp1719
1 files changed, 1719 insertions, 0 deletions
diff --git a/contrib/restricted/boost/filesystem/src/path.cpp b/contrib/restricted/boost/filesystem/src/path.cpp
new file mode 100644
index 0000000000..82b2c7d520
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/path.cpp
@@ -0,0 +1,1719 @@
+// filesystem path.cpp ------------------------------------------------------------- //
+
+// Copyright Beman Dawes 2008
+// Copyright Andrey Semashev 2021-2024
+
+// 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
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/detail/path_traits.hpp> // codecvt_error_category()
+#include <boost/system/error_category.hpp> // for BOOST_SYSTEM_HAS_CONSTEXPR
+#include <boost/assert.hpp>
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <string>
+#include <cstddef>
+#include <cstring>
+#include <cstdlib> // std::atexit
+
+#ifdef BOOST_WINDOWS_API
+#include "windows_file_codecvt.hpp"
+#include "windows_tools.hpp"
+#include <windows.h>
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
+#endif
+
+#ifdef BOOST_FILESYSTEM_DEBUG
+#include <iostream>
+#include <iomanip>
+#endif
+
+#include "atomic_tools.hpp"
+#include "private_config.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace fs = boost::filesystem;
+
+using boost::filesystem::path;
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace {
+//------------------------------------------------------------------------------------//
+// miscellaneous class path helpers //
+//------------------------------------------------------------------------------------//
+
+typedef path::value_type value_type;
+typedef path::string_type string_type;
+typedef string_type::size_type size_type;
+
+#ifdef BOOST_WINDOWS_API
+
+const wchar_t dot_path_literal[] = L".";
+const wchar_t dot_dot_path_literal[] = L"..";
+const wchar_t separators[] = L"/\\";
+using boost::filesystem::detail::colon;
+using boost::filesystem::detail::questionmark;
+
+inline bool is_alnum(wchar_t c)
+{
+ return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9');
+}
+
+inline bool is_device_name_char(wchar_t c)
+{
+ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+ // Device names are:
+ //
+ // - PRN
+ // - AUX
+ // - NUL
+ // - CON
+ // - LPT[1-9]
+ // - COM[1-9]
+ // - CONIN$
+ // - CONOUT$
+ return is_alnum(c) || c == L'$';
+}
+
+//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found
+inline size_type find_separator(const wchar_t* p, size_type size) noexcept
+{
+ size_type pos = 0u;
+ for (; pos < size; ++pos)
+ {
+ const wchar_t c = p[pos];
+ if (boost::filesystem::detail::is_directory_separator(c))
+ break;
+ }
+ return pos;
+}
+
+#else // BOOST_WINDOWS_API
+
+const char dot_path_literal[] = ".";
+const char dot_dot_path_literal[] = "..";
+const char separators[] = "/";
+
+//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found
+inline size_type find_separator(const char* p, size_type size) noexcept
+{
+ const char* sep = static_cast< const char* >(std::memchr(p, '/', size));
+ size_type pos = size;
+ if (BOOST_LIKELY(!!sep))
+ pos = sep - p;
+ return pos;
+}
+
+#endif // BOOST_WINDOWS_API
+
+// pos is position of the separator
+bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos);
+
+// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found.
+size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos);
+
+// Returns: starting position of root directory or size if not found. Sets root_name_size to length
+// of the root name if the characters before the returned position (if any) are considered a root name.
+size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size);
+
+// Finds position and size of the first element of the path
+void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size);
+
+// Finds position and size of the first element of the path
+inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size)
+{
+ first_element(src, element_pos, element_size, src.size());
+}
+
+} // unnamed namespace
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+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 && path_algorithms::compare_v4(*it1, *it2) == 0;)
+ {
+ path_algorithms::increment_v4(it1);
+ path_algorithms::increment_v4(it2);
+ }
+ return std::make_pair(it1, it2);
+}
+
+// normal --------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p)
+{
+ 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)
+ {
+ 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)
+ {
+ {
+ 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;
+ }
+ }
+
+ if (normal.empty() || last_element_was_dot)
+ {
+ append_trailing_dot:
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.push_back(path::dot);
+ }
+ }
+
+ return normal;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p)
+{
+ 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);
+
+ 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;
+ {
+ 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;
+ }
+
+ // 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)
+ {
+ // 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;
+ }
+
+ // 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())
+ 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(path::dot);
+ }
+
+ return normal;
+}
+
+// generic_path ---------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v3(path const& p)
+{
+ path tmp;
+ const size_type pathname_size = p.m_pathname.size();
+ tmp.m_pathname.reserve(pathname_size);
+
+ const value_type* const pathname = p.m_pathname.c_str();
+
+ // Don't remove duplicate slashes from the root name
+ size_type root_name_size = 0u;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ if (root_name_size > 0u)
+ {
+ tmp.m_pathname.append(pathname, root_name_size);
+#if defined(BOOST_WINDOWS_API)
+ std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/');
+#endif
+ }
+
+ size_type pos = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ tmp.m_pathname.push_back(path::separator);
+ pos = root_dir_pos + 1u;
+ }
+
+ while (pos < pathname_size)
+ {
+ size_type element_size = find_separator(pathname + pos, pathname_size - pos);
+ if (element_size > 0u)
+ {
+ tmp.m_pathname.append(pathname + pos, element_size);
+
+ pos += element_size;
+ if (pos >= pathname_size)
+ break;
+
+ tmp.m_pathname.push_back(path::separator);
+ }
+
+ ++pos;
+ }
+
+ return tmp;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v4(path const& p)
+{
+ path tmp;
+ const size_type pathname_size = p.m_pathname.size();
+ tmp.m_pathname.reserve(pathname_size);
+
+ const value_type* const pathname = p.m_pathname.c_str();
+
+ // Treat root name specially as it may contain backslashes, duplicate ones too,
+ // in case of UNC paths and Windows-specific prefixes.
+ size_type root_name_size = 0u;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ if (root_name_size > 0u)
+ tmp.m_pathname.append(pathname, root_name_size);
+
+ size_type pos = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ tmp.m_pathname.push_back(path::separator);
+ pos = root_dir_pos + 1u;
+ }
+
+ while (pos < pathname_size)
+ {
+ size_type element_size = find_separator(pathname + pos, pathname_size - pos);
+ if (element_size > 0u)
+ {
+ tmp.m_pathname.append(pathname + pos, element_size);
+
+ pos += element_size;
+ if (pos >= pathname_size)
+ break;
+
+ tmp.m_pathname.push_back(path::separator);
+ }
+
+ ++pos;
+ }
+
+ return tmp;
+}
+
+#if defined(BOOST_WINDOWS_API)
+
+// make_preferred -------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v3(path& p)
+{
+ std::replace(p.m_pathname.begin(), p.m_pathname.end(), L'/', L'\\');
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v4(path& p)
+{
+ const size_type pathname_size = p.m_pathname.size();
+ if (pathname_size > 0u)
+ {
+ value_type* const pathname = &p.m_pathname[0];
+
+ // Avoid converting slashes in the root name
+ size_type root_name_size = 0u;
+ find_root_directory_start(pathname, pathname_size, root_name_size);
+
+ std::replace(pathname + root_name_size, pathname + pathname_size, L'/', L'\\');
+ }
+}
+
+#endif // defined(BOOST_WINDOWS_API)
+
+// 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)
+ 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;
+}
+
+} // namespace filesystem
+} // namespace boost
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path helpers implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace {
+
+// is_root_separator ---------------------------------------------------------------//
+
+// pos is position of the separator
+inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos)
+{
+ BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation");
+
+ // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir
+ while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1]))
+ --pos;
+
+ return pos == root_dir_pos;
+}
+
+// find_filename_size --------------------------------------------------------------//
+
+// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found.
+inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos)
+{
+ size_type pos = end_pos;
+ while (pos > root_name_size)
+ {
+ --pos;
+
+ if (fs::detail::is_directory_separator(str[pos]))
+ {
+ ++pos; // filename starts past the separator
+ break;
+ }
+ }
+
+ return end_pos - pos;
+}
+
+// find_root_directory_start -------------------------------------------------------//
+
+// Returns: starting position of root directory or size if not found
+size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size)
+{
+ root_name_size = 0;
+ if (size == 0)
+ return 0;
+
+ bool parsing_root_name = false;
+ size_type pos = 0;
+
+ // case "//", possibly followed by more characters
+ if (fs::detail::is_directory_separator(path[0]))
+ {
+ if (size >= 2 && fs::detail::is_directory_separator(path[1]))
+ {
+ if (size == 2)
+ {
+ // The whole path is just a pair of separators
+ root_name_size = 2;
+ return 2;
+ }
+#ifdef BOOST_WINDOWS_API
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+ // cases "\\?\" and "\\.\"
+ else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3]))
+ {
+ parsing_root_name = true;
+ pos += 4;
+ }
+#endif
+ else if (fs::detail::is_directory_separator(path[2]))
+ {
+ // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators
+ return 0;
+ }
+ else
+ {
+ // case "//net {/}"
+ parsing_root_name = true;
+ pos += 2;
+ goto find_next_separator;
+ }
+ }
+#ifdef BOOST_WINDOWS_API
+ // https://stackoverflow.com/questions/23041983/path-prefixes-and
+ // case "\??\" (NT path prefix)
+ else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3]))
+ {
+ parsing_root_name = true;
+ pos += 4;
+ }
+#endif
+ else
+ {
+ // The path starts with a separator, possibly followed by a non-separator character
+ return 0;
+ }
+ }
+
+#ifdef BOOST_WINDOWS_API
+ // case "c:" or "prn:"
+ // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:,
+ // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we.
+ if ((size - pos) >= 2 && fs::detail::is_letter(path[pos]))
+ {
+ size_type i = pos + 1;
+ for (; i < size; ++i)
+ {
+ if (!is_device_name_char(path[i]))
+ break;
+ }
+
+ if (i < size && path[i] == colon)
+ {
+ pos = i + 1;
+ root_name_size = pos;
+ parsing_root_name = false;
+
+ if (pos < size && fs::detail::is_directory_separator(path[pos]))
+ return pos;
+ }
+ }
+#endif
+
+ if (!parsing_root_name)
+ return size;
+
+find_next_separator:
+ pos += find_separator(path + pos, size - pos);
+ if (parsing_root_name)
+ root_name_size = pos;
+
+ return pos;
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// 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.
+void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size)
+{
+ element_pos = 0;
+ element_size = 0;
+ if (src.empty())
+ return;
+
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size);
+
+ // First element is the root name, if there is one
+ if (root_name_size > 0)
+ {
+ element_size = root_name_size;
+ return;
+ }
+
+ // Otherwise, the root directory
+ if (root_dir_pos < size)
+ {
+ element_pos = root_dir_pos;
+ element_size = 1u;
+ return;
+ }
+
+ // Otherwise, the first filename or directory name in a relative path
+ size_type end_pos = src.find_first_of(separators);
+ if (end_pos == string_type::npos)
+ end_pos = src.size();
+ element_size = end_pos;
+}
+
+} // unnamed namespace
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it)
+{
+ 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)
+ {
+ 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, 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 void path_algorithms::increment_v4(path_detail::path_iterator& it)
+{
+ 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]))
+ {
+ // The iterator was pointing to the last empty element of the path; set to end.
+ 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
+ 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
+
+// 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
+} // namespace boost
+
+namespace {
+
+//------------------------------------------------------------------------------------//
+// locale helpers //
+//------------------------------------------------------------------------------------//
+
+// Prior versions of these locale and codecvt implementations tried to take advantage
+// of static initialization where possible, kept a local copy of the current codecvt
+// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
+// safe (again for efficiency).
+//
+// This was error prone, and required different implementation techniques depending
+// on the compiler and also whether static or dynamic linking was used. Furthermore,
+// users could not easily provide their multi-threading safe wrappers because the
+// path interface requires the implementation itself to call codecvt() to obtain the
+// default facet, and the initialization of the static within path_locale() could race.
+//
+// The code below is portable to all platforms, is much simpler, and hopefully will be
+// much more robust. Timing tests (on Windows, using a Visual C++ release build)
+// indicated the current code is roughly 9% slower than the previous code, and that
+// seems a small price to pay for better code that is easier to use.
+
+std::locale default_locale()
+{
+#if defined(BOOST_WINDOWS_API)
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt());
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+ // "All BSD system functions expect their string parameters to be in UTF-8 encoding
+ // and nothing else." See
+ // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
+ //
+ // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
+ // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
+ // The right way to deal with it would be to always convert the filename to UTF-8
+ // before trying to open/create a file." See
+ // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
+ //
+ // "How a file name looks at the API level depends on the API. Current Carbon APIs
+ // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
+ // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
+ // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
+ // cases." See
+ // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
+ //
+ // Many thanks to Peter Dimov for digging out the above references!
+
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet());
+#else // Other POSIX
+ // ISO C calls std::locale("") "the locale-specific native environment", and this
+ // locale is the default for many POSIX-based operating systems such as Linux.
+ return std::locale("");
+#endif
+}
+
+std::locale* g_path_locale = nullptr;
+
+void schedule_path_locale_cleanup() noexcept;
+
+// std::locale("") construction, needed on non-Apple POSIX systems, can throw
+// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
+// get_path_locale() provides lazy initialization to ensure that any
+// exceptions occur after main() starts and so can be caught. Furthermore,
+// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves
+// actually called, ensuring that an exception will only be thrown if std::locale("")
+// is really needed.
+inline std::locale& get_path_locale()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< std::locale* > a(g_path_locale);
+ std::locale* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ std::locale* new_p = new std::locale(default_locale());
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ {
+ p = new_p;
+ schedule_path_locale_cleanup();
+ }
+ else
+ {
+ delete new_p;
+ }
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ std::locale* p = g_path_locale;
+ if (BOOST_UNLIKELY(!p))
+ {
+ g_path_locale = p = new std::locale(default_locale());
+ schedule_path_locale_cleanup();
+ }
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+inline std::locale* replace_path_locale(std::locale const& loc)
+{
+ std::locale* new_p = new std::locale(loc);
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel);
+#else
+ std::locale* p = g_path_locale;
+ g_path_locale = new_p;
+#endif
+ if (!p)
+ schedule_path_locale_cleanup();
+ return p;
+}
+
+#if defined(_MSC_VER)
+
+const boost::filesystem::path* g_dot_path = nullptr;
+const boost::filesystem::path* g_dot_dot_path = nullptr;
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path);
+ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal);
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ p = new_p;
+ else
+ delete new_p;
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ const boost::filesystem::path* p = g_dot_path;
+ if (BOOST_UNLIKELY(!p))
+ g_dot_path = p = new boost::filesystem::path(dot_path_literal);
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path);
+ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal);
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ p = new_p;
+ else
+ delete new_p;
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ const boost::filesystem::path* p = g_dot_dot_path;
+ if (BOOST_UNLIKELY(!p))
+ g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal);
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+void __cdecl destroy_path_globals()
+{
+ delete g_dot_dot_path;
+ g_dot_dot_path = nullptr;
+ delete g_dot_path;
+ g_dot_path = nullptr;
+ delete g_path_locale;
+ g_path_locale = nullptr;
+}
+
+BOOST_FILESYSTEM_INIT_FUNC init_path_globals()
+{
+#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR)
+ // codecvt_error_category needs to be called early to dynamic-initialize the error category instance
+ boost::filesystem::codecvt_error_category();
+#endif
+ std::atexit(&destroy_path_globals);
+ return BOOST_FILESYSTEM_INITRETSUCCESS_V;
+}
+
+#if _MSC_VER >= 1400
+
+#pragma section(".CRT$XCM", long, read)
+__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_path_globals = &init_path_globals;
+
+#else // _MSC_VER >= 1400
+
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(push, old_seg)
+#endif
+#pragma data_seg(".CRT$XCM")
+BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_path_globals = &init_path_globals;
+#pragma data_seg()
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(pop, old_seg)
+#endif
+
+#endif // _MSC_VER >= 1400
+
+#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+//! Makes sure the global initializer pointers are referenced and not removed by linker
+struct globals_retainer
+{
+ const init_func_ptr_t* volatile m_p_init_path_globals;
+
+ globals_retainer() { m_p_init_path_globals = &p_init_path_globals; }
+};
+BOOST_ATTRIBUTE_UNUSED
+static const globals_retainer g_globals_retainer;
+#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+
+#else // defined(_MSC_VER)
+
+struct path_locale_deleter
+{
+ ~path_locale_deleter()
+ {
+ delete g_path_locale;
+ g_path_locale = nullptr;
+ }
+};
+
+#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED
+const path_locale_deleter g_path_locale_deleter = {};
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY)
+const boost::filesystem::path g_dot_path(dot_path_literal);
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY)
+const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal);
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+ return g_dot_path;
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+ return g_dot_dot_path;
+}
+
+#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+ BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter;
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+ static const boost::filesystem::path g_dot_path(dot_path_literal);
+ return g_dot_path;
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+ static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal);
+ return g_dot_dot_path;
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+#endif // defined(_MSC_VER)
+
+} // unnamed namespace
+
+//--------------------------------------------------------------------------------------//
+// path::codecvt() and path::imbue() implementation //
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt()
+{
+#ifdef BOOST_FILESYSTEM_DEBUG
+ std::cout << "***** path::codecvt() called" << std::endl;
+#endif
+ return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale());
+}
+
+BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc)
+{
+#ifdef BOOST_FILESYSTEM_DEBUG
+ std::cout << "***** path::imbue() called" << std::endl;
+#endif
+ std::locale* p = replace_path_locale(loc);
+ if (BOOST_LIKELY(p != nullptr))
+ {
+ // Note: copying/moving std::locale does not throw
+ std::locale temp(std::move(*p));
+ delete p;
+ return temp;
+ }
+
+ return default_locale();
+}
+
+namespace detail {
+
+BOOST_FILESYSTEM_DECL path const& dot_path()
+{
+ return get_dot_path();
+}
+
+BOOST_FILESYSTEM_DECL path const& dot_dot_path()
+{
+ return get_dot_dot_path();
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>