v4: Avoid converting slashes in path root name in path::make_preferred.

Similarly to other methods, make_preferred is only supposed to affect
directory separators and not the slashes that are part of the path
root name.
This commit is contained in:
Andrey Semashev 2024-01-04 00:59:21 +03:00
parent 0f890633c3
commit b87d2790e7
5 changed files with 47 additions and 21 deletions

View File

@ -42,7 +42,7 @@
<h2>1.85.0</h2>
<ul>
<li><code>path::generic_path</code> and <code>path::generic_string</code> methods now remove duplicate directory separators in the returned paths.</li>
<li><b>v4:</b> <code>path::generic_path</code>, <code>path::generic_string</code> and <code>path::lexically_normal</code> avoid converting between backslashes and forward slashes in path root names. For example, on Windows, <code>path("\\\\?\\c:\\foo").generic_string()</code> now returns "\\?\c:/foo" instead of "//?/c:/foo". Similarly, <code>path("\\\\host/share/foo/..").lexically_normal()</code> now returns "\\host\share".</li>
<li><b>v4:</b> <code>path::generic_path</code>, <code>path::generic_string</code>, <code>path::make_preferred</code> and <code>path::lexically_normal</code> avoid converting between backslashes and forward slashes in path root names. For example, on Windows, <code>path("\\\\?\\c:\\foo").generic_string()</code> now returns "\\?\c:/foo" instead of "//?/c:/foo". Similarly, <code>path("\\\\host/share/foo/..").lexically_normal()</code> now returns "\\host\share".</li>
</ul>
<h2>1.84.0</h2>

View File

@ -51,7 +51,7 @@ It removes the features that were <a href="deprecated.html">deprecated</a> in Ve
<li><a href="reference.html#path-stem"><code>path::stem</code></a> and <a href="reference.html#path-extension"><code>path::extension</code></a> no longer treat a filename that starts with a dot and has no other dots as an extension. Filenames starting with a dot are commonly treated as filenames with an empty extension. The leading dot is used to indicate a hidden file on most UNIX-like systems.</li>
<li><a href="reference.html#path-filename"><code>path::filename</code></a> and <a href="reference.html#path-iterators"><code>path::iterator</code></a> no longer return an implicit trailing dot (".") element if the path ends with a directory separator. Instead, an empty path is returned, similar to C++17 std::filesystem. This also affects other methods that are defined in terms of iterators or filename, such as <code>path::stem</code>, <code>path::compare</code> or <code>lexicographical_compare</code>. For example, <code>path("a/b/") == path("a/b/.")</code> no longer holds true.</li>
<li><a href="reference.html#lexically_normal"><code>path::lexically_normal</code></a> no longer produces a trailing dot (".") element and omits a directory separator after a trailing dot-dot ("..") element in the normalized paths.</li>
<li><a href="reference.html#lexically_normal"><code>path::lexically_normal</code></a>, <a href="reference.html#path-generic-format-observers"><code>path::generic_string</code></a> and similar methods no longer convert between forward and backward slashes in root names of the returned paths.</li>
<li><a href="reference.html#lexically_normal"><code>path::lexically_normal</code></a>, <a href="reference.html#path-make_preferred"><code>path::make_preferred</code></a>, <a href="reference.html#path-generic-format-observers"><code>path::generic_string</code></a> and similar methods no longer convert between forward and backward slashes in root names of the returned paths.</li>
<li><a href="reference.html#path-appends"><code>path</code> appends</a> consider root name and root directory of the appended path. If the appended path is absolute, or root name is present and differs from the source path, the resulting path is equivalent to the appended path. If root directory is present, the result is the root directory and relative path rebased on top of the root name of the source path. Otherwise, the behavior is similar to v3. This behavior is similar to C++17 std::filesystem.</li>
<li><code>path</code> no longer supports construction, assignment or appending from containers of characters. Use string types or iterators as the source for these opereations instead.</li>
<li><a href="reference.html#path-remove_filename"><code>path::remove_filename</code></a> preserves the trailing directory separator, so that <code>path::has_filename</code> returns <code>false</code> after a successful call to <code>path::remove_filename</code>.</li>

View File

@ -110,6 +110,11 @@ struct path_algorithms
BOOST_FILESYSTEM_DECL static path generic_path_v3(path const& p);
BOOST_FILESYSTEM_DECL static path generic_path_v4(path const& p);
#if defined(BOOST_WINDOWS_API)
BOOST_FILESYSTEM_DECL static void make_preferred_v3(path& p);
BOOST_FILESYSTEM_DECL static void make_preferred_v4(path& p);
#endif
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);
@ -886,15 +891,7 @@ public:
// ----- modifiers -----
void clear() BOOST_NOEXCEPT { m_pathname.clear(); }
#ifdef BOOST_POSIX_API
path& make_preferred()
{
// No effect on POSIX
return *this;
}
#else // BOOST_WINDOWS_API
BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes
#endif
path& make_preferred();
path& remove_filename();
BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators();
BOOST_FILESYSTEM_DECL path& remove_trailing_separator();
@ -1741,6 +1738,15 @@ BOOST_FORCEINLINE path path::generic_path() const
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::generic_path)(*this);
}
BOOST_FORCEINLINE path& path::make_preferred()
{
// No effect on POSIX
#if defined(BOOST_WINDOWS_API)
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::make_preferred)(*this);
#endif
return *this;
}
namespace path_detail {
BOOST_FORCEINLINE void path_iterator::increment()

View File

@ -447,6 +447,32 @@ BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v4(path const& p)
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)
@ -907,16 +933,6 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
return tmp;
}
#if defined(BOOST_WINDOWS_API)
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

View File

@ -2610,7 +2610,11 @@ void make_preferred_tests()
if (platform == "Windows")
{
#if BOOST_FILESYSTEM_VERSION == 3
BOOST_TEST(path("//abc\\def/ghi").make_preferred().native() == path("\\\\abc\\def\\ghi").native());
#else
BOOST_TEST(path("//abc\\def/ghi").make_preferred().native() == path("//abc\\def\\ghi").native());
#endif
}
else
{