diff --git a/doc/reference.html b/doc/reference.html
index bd46bacf3..09d3e0ec2 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -1582,7 +1582,8 @@
-The string returned by all generic format observers is in the generic pathname format.
+The string returned by all generic format observers is in the generic pathname format.
+The returned strings use a single forward slash ('/') as directory separators.
template <class String>
String generic_string(const codecvt_type& cvt=codecvt()) const;
diff --git a/doc/release_history.html b/doc/release_history.html
index 3893f3fc3..6f5c070a6 100644
--- a/doc/release_history.html
+++ b/doc/release_history.html
@@ -39,6 +39,11 @@
+1.85.0
+
+ path::generic_path
and path::generic_string
methods now remove duplicate directory separators in the returned paths. The methods also avoid converting backslashes to forward slashes in root names of the paths. For example, on Windows, path("\\\\?\\c:\\foo").generic_string()
now returns "\\?\c:/foo" instead of "//?/c:/foo". Similarly, path("\\\\host\\share").generic_string()
now returns "\\host/share".
+
+
1.84.0
- As was announced in Boost 1.82.0, C++03 is no longer supported. A C++11 or later compiler is required.
diff --git a/include/boost/filesystem/path.hpp b/include/boost/filesystem/path.hpp
index 5172d29f1..2e321064e 100644
--- a/include/boost/filesystem/path.hpp
+++ b/include/boost/filesystem/path.hpp
@@ -976,11 +976,7 @@ class path :
// Experimental generic function returning generic formatted path (i.e. separators
// are forward slashes). Motivation: simpler than a family of generic_*string
// functions.
-#ifdef BOOST_WINDOWS_API
BOOST_FILESYSTEM_DECL path generic_path() const;
-#else
- path generic_path() const;
-#endif
template< typename String >
String generic_string() const;
@@ -988,18 +984,10 @@ class path :
template< typename String >
String generic_string(codecvt_type const& cvt) const;
-#ifdef BOOST_WINDOWS_API
std::string generic_string() const { return generic_path().string(); }
std::string generic_string(codecvt_type const& cvt) const { return generic_path().string(cvt); }
std::wstring generic_wstring() const { return generic_path().wstring(); }
- std::wstring generic_wstring(codecvt_type const&) const { return generic_wstring(); }
-#else // BOOST_POSIX_API
- // On POSIX-like systems, the generic format is the same as the native format
- std::string const& generic_string() const { return m_pathname; }
- std::string const& generic_string(codecvt_type const&) const { return m_pathname; }
- std::wstring generic_wstring() const { return this->wstring(); }
- std::wstring generic_wstring(codecvt_type const& cvt) const { return this->wstring(cvt); }
-#endif
+ std::wstring generic_wstring(codecvt_type const& cvt) const { return generic_path().wstring(cvt); }
// ----- compare -----
@@ -1629,13 +1617,6 @@ BOOST_FORCEINLINE path& path::operator/=(path const& p)
return append(p);
}
-#if !defined(BOOST_WINDOWS_API)
-inline path path::generic_path() const
-{
- return path(*this);
-}
-#endif
-
inline path path::lexically_proximate(path const& base) const
{
path tmp(lexically_relative(base));
diff --git a/src/path.cpp b/src/path.cpp
index d5c39f3c4..91e345c68 100644
--- a/src/path.cpp
+++ b/src/path.cpp
@@ -825,15 +825,50 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
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'/');
+ path tmp;
+ const size_type size = m_pathname.size();
+ tmp.m_pathname.reserve(size);
+
+ const value_type* const 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(p, size, root_name_size);
+ if (root_name_size > 0u)
+ tmp.m_pathname.append(p, root_name_size);
+
+ size_type pos = root_name_size;
+ if (root_dir_pos < size)
+ {
+ tmp.m_pathname.push_back(path::separator);
+ pos = root_dir_pos + 1u;
+ }
+
+ while (pos < size)
+ {
+ size_type element_size = find_separator(p + pos, size - pos);
+ if (element_size > 0u)
+ {
+ tmp.m_pathname.append(p + pos, element_size);
+
+ pos += element_size;
+ if (pos >= size)
+ break;
+
+ tmp.m_pathname.push_back(path::separator);
+ }
+
+ ++pos;
+ }
+
return tmp;
}
+#if defined(BOOST_WINDOWS_API)
+
BOOST_FILESYSTEM_DECL path& path::make_preferred()
{
std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
diff --git a/test/path_test.cpp b/test/path_test.cpp
index cd3503798..625c8c675 100644
--- a/test/path_test.cpp
+++ b/test/path_test.cpp
@@ -2618,6 +2618,46 @@ void make_preferred_tests()
}
}
+// generic_path_tests --------------------------------------------------------------//
+
+void generic_path_tests()
+{
+ std::cout << "generic_path_tests..." << std::endl;
+
+ BOOST_TEST_EQ(path("").generic_path().string(), std::string(""));
+ BOOST_TEST_EQ(path("/").generic_path().string(), std::string("/"));
+ BOOST_TEST_EQ(path("//").generic_path().string(), std::string("//"));
+ BOOST_TEST_EQ(path("///").generic_path().string(), std::string("/"));
+
+ BOOST_TEST_EQ(path("foo").generic_path().string(), std::string("foo"));
+ BOOST_TEST_EQ(path("foo/bar").generic_path().string(), std::string("foo/bar"));
+ BOOST_TEST_EQ(path("..").generic_path().string(), std::string(".."));
+ BOOST_TEST_EQ(path("../..").generic_path().string(), std::string("../.."));
+ BOOST_TEST_EQ(path("/..").generic_path().string(), std::string("/.."));
+ BOOST_TEST_EQ(path("../foo").generic_path().string(), std::string("../foo"));
+ BOOST_TEST_EQ(path("foo/..").generic_path().string(), std::string("foo/.."));
+ BOOST_TEST_EQ(path("foo/../").generic_path().string(), std::string("foo/../"));
+
+ BOOST_TEST_EQ(path("foo//bar").generic_path().string(), std::string("foo/bar"));
+
+ BOOST_TEST_EQ(path("//net//foo//bar").generic_path().string(), std::string("//net/foo/bar"));
+
+ if (platform == "Windows")
+ {
+ BOOST_TEST_EQ(path("c:\\foo\\bar").generic_path().string(), std::string("c:/foo/bar"));
+ BOOST_TEST_EQ(path("c:\\\\foo\\\\bar//zoo").generic_path().string(), std::string("c:/foo/bar/zoo"));
+
+ BOOST_TEST_EQ(path("c:foo\\\\bar//zoo").generic_path().string(), std::string("c:foo/bar/zoo"));
+
+ BOOST_TEST_EQ(path("\\\\net\\foo\\bar").generic_path().string(), std::string("\\\\net/foo/bar"));
+ BOOST_TEST_EQ(path("\\\\net\\\\foo\\/bar//zoo").generic_path().string(), std::string("\\\\net/foo/bar/zoo"));
+
+ BOOST_TEST_EQ(path("\\\\?\\c:\\\\foo\\\\bar//zoo").generic_path().string(), std::string("\\\\?\\c:/foo/bar/zoo"));
+ BOOST_TEST_EQ(path("\\\\.\\c:\\\\foo\\\\bar//zoo").generic_path().string(), std::string("\\\\.\\c:/foo/bar/zoo"));
+ BOOST_TEST_EQ(path("\\??\\c:\\\\foo\\\\bar//zoo").generic_path().string(), std::string("\\??\\c:/foo/bar/zoo"));
+ }
+}
+
// lexically_normal_tests ----------------------------------------------------------//
void lexically_normal_tests()
@@ -2864,6 +2904,7 @@ int cpp_main(int, char*[])
name_function_tests();
replace_extension_tests();
make_preferred_tests();
+ generic_path_tests();
lexically_normal_tests();
compare_tests();