mirror of
https://git.mirrors.martin98.com/https://github.com/gulrak/filesystem
synced 2025-06-04 11:13:58 +08:00
refs #90, native path backend - stage two, prefix handling repaired and configurable, all tests working on Windows (wchar_t backend will be stage 3)
This commit is contained in:
parent
8fac7e5254
commit
c96b0059c3
@ -234,9 +234,15 @@
|
||||
// instead of replacing them with the unicode replacement character (U+FFFD).
|
||||
// #define GHC_RAISE_UNICODE_ERRORS
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length.
|
||||
// instead of replacing them with the unicode replacement character (U+FFFD).
|
||||
#ifndef GHC_WIN_DISABLE_AUTO_PREFIXES
|
||||
#define GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
#endif // GHC_WIN_DISABLE_AUTO_PREFIXES
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
|
||||
#define GHC_FILESYSTEM_VERSION 10401L
|
||||
#define GHC_FILESYSTEM_VERSION 10499L
|
||||
|
||||
#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
|
||||
#define GHC_WITH_EXCEPTIONS
|
||||
@ -319,6 +325,10 @@ public:
|
||||
struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type
|
||||
{
|
||||
};
|
||||
template <class CharT>
|
||||
struct _is_basic_string<std::basic_string<CharT, std::char_traits<CharT>, std::allocator<CharT>>> : std::true_type
|
||||
{
|
||||
};
|
||||
#ifdef __cpp_lib_string_view
|
||||
template <class CharT>
|
||||
struct _is_basic_string<std::basic_string_view<CharT>> : std::true_type
|
||||
@ -505,15 +515,21 @@ private:
|
||||
};
|
||||
friend void swap(path& lhs, path& rhs) noexcept;
|
||||
friend size_t hash_value(const path& p) noexcept;
|
||||
friend path canonical(const path& p, std::error_code& ec);
|
||||
string_type::size_type root_name_length() const noexcept;
|
||||
static void postprocess_path_with_format(impl_string_type& p, format fmt);
|
||||
void postprocess_path_with_format(format fmt);
|
||||
impl_string_type _path;
|
||||
#ifdef GHC_OS_WINDOWS
|
||||
void handle_prefixes();
|
||||
void check_long_path();
|
||||
friend bool detail::has_executable_extension(const path& p);
|
||||
impl_string_type native_impl() const;
|
||||
mutable string_type _native_cache;
|
||||
#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
string_type::size_type _prefixLength{0 };
|
||||
#else // GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
static const string_type::size_type _prefixLength{0};
|
||||
#endif // GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
#else
|
||||
const impl_string_type& native_impl() const;
|
||||
static const string_type::size_type _prefixLength{0};
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -576,7 +592,7 @@ public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
iterator();
|
||||
iterator(const impl_string_type::const_iterator& first, const impl_string_type::const_iterator& last, const impl_string_type::const_iterator& pos);
|
||||
iterator(const path& p, const impl_string_type::const_iterator& pos);
|
||||
iterator& operator++();
|
||||
iterator operator++(int);
|
||||
iterator& operator--();
|
||||
@ -593,6 +609,7 @@ private:
|
||||
void updateCurrent();
|
||||
impl_string_type::const_iterator _first;
|
||||
impl_string_type::const_iterator _last;
|
||||
impl_string_type::const_iterator _prefix;
|
||||
impl_string_type::const_iterator _root;
|
||||
impl_string_type::const_iterator _iter;
|
||||
path _current;
|
||||
@ -1544,25 +1561,35 @@ inline std::string toUtf8(const charT* unicodeString)
|
||||
|
||||
namespace detail {
|
||||
|
||||
//template <typename strT, typename std::enable_if < path::_is_basic_string<strT>::value >>
|
||||
GHC_INLINE bool startsWith(const std::string& what, const std::string& with)
|
||||
template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
|
||||
GHC_INLINE bool startsWith(const strT& what, const strT& with)
|
||||
{
|
||||
return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());
|
||||
}
|
||||
|
||||
GHC_INLINE bool endsWith(const std::string& what, const std::string& with)
|
||||
template <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>
|
||||
GHC_INLINE bool endsWith(const strT& what, const strT& with)
|
||||
{
|
||||
return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with);
|
||||
return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, path::format fmt)
|
||||
GHC_INLINE void path::check_long_path()
|
||||
{
|
||||
#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type("\\\\?\\"))) {
|
||||
postprocess_path_with_format(native_format);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GHC_INLINE void path::postprocess_path_with_format(path::format fmt)
|
||||
{
|
||||
#ifdef GHC_RAISE_UNICODE_ERRORS
|
||||
if(!detail::validUtf8(p)) {
|
||||
if(!detail::validUtf8(_path)) {
|
||||
path t;
|
||||
t._path = p;
|
||||
t._path = _path;
|
||||
throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
}
|
||||
#endif
|
||||
@ -1571,22 +1598,17 @@ GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, pa
|
||||
case path::native_format:
|
||||
case path::auto_format:
|
||||
case path::generic_format:
|
||||
for (auto& c : p) {
|
||||
for (auto& c : _path) {
|
||||
if (c == generic_separator) {
|
||||
c = internal_separator;
|
||||
}
|
||||
}
|
||||
if (p.length() >= 4 && p[2] == '?') {
|
||||
if (p.length() == 4 || (p.length() >= 6 && p[5] == ':')) {
|
||||
if (detail::startsWith(p, std::string("\\\\?\\"))) {
|
||||
// remove Windows long filename marker for simple paths
|
||||
p.erase(0, 4);
|
||||
}
|
||||
else if (detail::startsWith(p, std::string("\\??\\"))) {
|
||||
p.erase(0, 4);
|
||||
}
|
||||
}
|
||||
#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH
|
||||
if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type("\\\\?\\"))) {
|
||||
_path = "\\\\?\\" + _path;
|
||||
}
|
||||
#endif
|
||||
handle_prefixes();
|
||||
break;
|
||||
#else
|
||||
case path::auto_format:
|
||||
@ -1596,13 +1618,13 @@ GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, pa
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (p.length() > 2 && p[0] == internal_separator && p[1] == internal_separator && p[2] != internal_separator) {
|
||||
std::string::iterator new_end = std::unique(p.begin() + 2, p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == internal_separator; });
|
||||
p.erase(new_end, p.end());
|
||||
if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == internal_separator && _path[_prefixLength + 1] == internal_separator && _path[_prefixLength + 2] != internal_separator) {
|
||||
std::string::iterator new_end = std::unique(_path.begin() + _prefixLength + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == internal_separator; });
|
||||
_path.erase(new_end, _path.end());
|
||||
}
|
||||
else {
|
||||
std::string::iterator new_end = std::unique(p.begin(), p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == internal_separator; });
|
||||
p.erase(new_end, p.end());
|
||||
std::string::iterator new_end = std::unique(_path.begin() + _prefixLength, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == internal_separator; });
|
||||
_path.erase(new_end, _path.end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1612,7 +1634,7 @@ template <class Source, typename>
|
||||
inline path::path(const Source& source, format fmt)
|
||||
: _path(detail::toUtf8(source))
|
||||
{
|
||||
postprocess_path_with_format(_path, fmt);
|
||||
postprocess_path_with_format(fmt);
|
||||
}
|
||||
|
||||
template <class Source, typename>
|
||||
@ -1751,6 +1773,21 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin
|
||||
ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec)
|
||||
{
|
||||
ULONG size = ::GetFullPathNameW(p, 0, 0, 0);
|
||||
if (size) {
|
||||
std::vector<wchar_t> buf(size, 0);
|
||||
ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr);
|
||||
if (s2 && s2 < size) {
|
||||
return path(std::wstring(buf.data(), s2));
|
||||
}
|
||||
}
|
||||
ec = detail::make_system_error();
|
||||
return path();
|
||||
}
|
||||
|
||||
#else
|
||||
GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec)
|
||||
{
|
||||
@ -1864,12 +1901,20 @@ GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
|
||||
if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
|
||||
if (IsReparseTagMicrosoft(reparseData->ReparseTag)) {
|
||||
switch (reparseData->ReparseTag) {
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
result = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
|
||||
case IO_REPARSE_TAG_SYMLINK: {
|
||||
auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR));
|
||||
auto substituteName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
|
||||
if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) {
|
||||
result = printName;
|
||||
}
|
||||
else {
|
||||
result = substituteName;
|
||||
}
|
||||
if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) {
|
||||
result = p.parent_path() / result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
|
||||
break;
|
||||
@ -2122,11 +2167,13 @@ GHC_INLINE path::path() noexcept {}
|
||||
|
||||
GHC_INLINE path::path(const path& p)
|
||||
: _path(p._path)
|
||||
, _prefixLength(p._prefixLength)
|
||||
{
|
||||
}
|
||||
|
||||
GHC_INLINE path::path(path&& p) noexcept
|
||||
: _path(std::move(p._path))
|
||||
, _prefixLength(p._prefixLength)
|
||||
{
|
||||
}
|
||||
|
||||
@ -2137,7 +2184,7 @@ GHC_INLINE path::path(string_type&& source, format fmt)
|
||||
: _path(std::move(source))
|
||||
#endif
|
||||
{
|
||||
postprocess_path_with_format(_path, fmt);
|
||||
postprocess_path_with_format(fmt);
|
||||
}
|
||||
|
||||
#endif // GHC_EXPAND_IMPL
|
||||
@ -2174,12 +2221,14 @@ GHC_INLINE path::~path() {}
|
||||
GHC_INLINE path& path::operator=(const path& p)
|
||||
{
|
||||
_path = p._path;
|
||||
_prefixLength = p._prefixLength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GHC_INLINE path& path::operator=(path&& p) noexcept
|
||||
{
|
||||
_path = std::move(p._path);
|
||||
_prefixLength = p._prefixLength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2195,7 +2244,7 @@ GHC_INLINE path& path::assign(path::string_type&& source)
|
||||
#else
|
||||
_path = std::move(source);
|
||||
#endif
|
||||
postprocess_path_with_format(_path, native_format);
|
||||
postprocess_path_with_format(native_format);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2211,7 +2260,7 @@ template <class Source>
|
||||
inline path& path::assign(const Source& source)
|
||||
{
|
||||
_path.assign(detail::toUtf8(source));
|
||||
postprocess_path_with_format(_path, native_format);
|
||||
postprocess_path_with_format(native_format);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2219,6 +2268,7 @@ template <>
|
||||
inline path& path::assign<path>(const path& source)
|
||||
{
|
||||
_path = source._path;
|
||||
_prefixLength = source._prefixLength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2226,7 +2276,7 @@ template <class InputIterator>
|
||||
inline path& path::assign(InputIterator first, InputIterator last)
|
||||
{
|
||||
_path.assign(first, last);
|
||||
postprocess_path_with_format(_path, native_format);
|
||||
postprocess_path_with_format(native_format);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2266,6 +2316,7 @@ GHC_INLINE path& path::operator/=(const path& p)
|
||||
first = false;
|
||||
_path += (*iter++).string();
|
||||
}
|
||||
check_long_path();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2279,6 +2330,7 @@ GHC_INLINE void path::append_name(const char* name)
|
||||
_path.push_back(path::internal_separator);
|
||||
}
|
||||
_path += name;
|
||||
check_long_path();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2350,6 +2402,7 @@ GHC_INLINE path& path::operator+=(value_type x)
|
||||
_path += x;
|
||||
#endif
|
||||
}
|
||||
check_long_path();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2374,14 +2427,14 @@ inline path& path::concat(const Source& x)
|
||||
{
|
||||
path p(x);
|
||||
_path += p._path;
|
||||
postprocess_path_with_format(p._path, native_format);
|
||||
postprocess_path_with_format(native_format);
|
||||
return *this;
|
||||
}
|
||||
template <class InputIterator>
|
||||
inline path& path::concat(InputIterator first, InputIterator last)
|
||||
{
|
||||
_path.append(first, last);
|
||||
postprocess_path_with_format(_path, native_format);
|
||||
postprocess_path_with_format(native_format);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -2392,6 +2445,7 @@ inline path& path::concat(InputIterator first, InputIterator last)
|
||||
GHC_INLINE void path::clear() noexcept
|
||||
{
|
||||
_path.clear();
|
||||
_prefixLength = 0;
|
||||
}
|
||||
|
||||
GHC_INLINE path& path::make_preferred()
|
||||
@ -2429,46 +2483,11 @@ GHC_INLINE path& path::replace_extension(const path& replacement)
|
||||
GHC_INLINE void path::swap(path& rhs) noexcept
|
||||
{
|
||||
_path.swap(rhs._path);
|
||||
std::swap(_prefixLength, rhs._prefixLength);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 30.10.8.4.6, native format observers
|
||||
#ifdef GHC_OS_WINDOWS
|
||||
GHC_INLINE path::impl_string_type path::native_impl() const
|
||||
{
|
||||
return _path;
|
||||
#if 0
|
||||
impl_string_type result;
|
||||
if (is_absolute() && _path.length() > MAX_PATH - 10) {
|
||||
// expand absolute non namespaced long Windows filenames with marker
|
||||
if (has_root_name() && _path[0] == '/' && _path[1] != '/') {
|
||||
result = "\\\\?\\" + _path.substr(1);
|
||||
}
|
||||
else {
|
||||
result = "\\\\?\\" + _path;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = _path;
|
||||
}
|
||||
/*if (has_root_name() && root_name()._path[0] == '/') {
|
||||
return _path;
|
||||
}*/
|
||||
for (auto& c : result) {
|
||||
if (c == '/') {
|
||||
c = '\\';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
GHC_INLINE const path::impl_string_type& path::native_impl() const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
#endif
|
||||
|
||||
GHC_INLINE const path::string_type& path::native() const noexcept
|
||||
{
|
||||
return _path;
|
||||
@ -2698,15 +2717,27 @@ GHC_INLINE int path::compare(const value_type* s) const
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 30.10.8.4.9, decomposition
|
||||
GHC_INLINE void path::handle_prefixes()
|
||||
{
|
||||
#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)
|
||||
_prefixLength = 0;
|
||||
if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast<unsigned char>(_path[4])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[4])) <= 'Z' && _path[5] == ':') {
|
||||
if(detail::startsWith(_path, impl_string_type("\\\\?\\")) || detail::startsWith(_path, impl_string_type("\\??\\"))) {
|
||||
_prefixLength = 4;
|
||||
}
|
||||
}
|
||||
#endif // GHC_OS_WINDOWS
|
||||
}
|
||||
|
||||
GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept
|
||||
{
|
||||
#ifdef GHC_OS_WINDOWS
|
||||
if (_path.length() >= 2 && std::toupper(static_cast<unsigned char>(_path[0])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[0])) <= 'Z' && _path[1] == ':') {
|
||||
if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') {
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
if (_path.length() > 2 && _path[0] == internal_separator && _path[1] == internal_separator && _path[2] != internal_separator && std::isprint(_path[2])) {
|
||||
impl_string_type::size_type pos = _path.find(internal_separator, 3);
|
||||
if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == internal_separator && _path[_prefixLength + 1] == internal_separator && _path[_prefixLength + 2] != internal_separator && std::isprint(_path[_prefixLength + 2])) {
|
||||
impl_string_type::size_type pos = _path.find(internal_separator, _prefixLength + 3);
|
||||
if (pos == impl_string_type::npos) {
|
||||
return _path.length();
|
||||
}
|
||||
@ -2719,13 +2750,13 @@ GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept
|
||||
|
||||
GHC_INLINE path path::root_name() const
|
||||
{
|
||||
return path(_path.substr(0, root_name_length()), generic_format);
|
||||
return path(_path.substr(_prefixLength, root_name_length()), native_format);
|
||||
}
|
||||
|
||||
GHC_INLINE path path::root_directory() const
|
||||
{
|
||||
if(has_root_directory()) {
|
||||
static const path _root_dir(std::string(1, internal_separator), generic_format);
|
||||
static const path _root_dir(std::string(1, internal_separator), native_format);
|
||||
return _root_dir;
|
||||
}
|
||||
return path();
|
||||
@ -2733,18 +2764,18 @@ GHC_INLINE path path::root_directory() const
|
||||
|
||||
GHC_INLINE path path::root_path() const
|
||||
{
|
||||
return path(root_name().generic_string() + root_directory().generic_string(), generic_format);
|
||||
return path(root_name().string() + root_directory().string(), native_format);
|
||||
}
|
||||
|
||||
GHC_INLINE path path::relative_path() const
|
||||
{
|
||||
auto rootPathLen = root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format);
|
||||
}
|
||||
|
||||
GHC_INLINE path path::parent_path() const
|
||||
{
|
||||
auto rootPathLen = root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
if(rootPathLen < _path.length()) {
|
||||
if (empty() || begin() == --end()) {
|
||||
return path();
|
||||
@ -2755,7 +2786,7 @@ GHC_INLINE path path::parent_path() const
|
||||
if (iter > _path.begin() + static_cast<long>(rootPathLen) && *iter != internal_separator) {
|
||||
--iter;
|
||||
}
|
||||
return path(_path.begin(), iter, format::generic_format);
|
||||
return path(_path.begin(), iter, native_format);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -2765,7 +2796,7 @@ GHC_INLINE path path::parent_path() const
|
||||
|
||||
GHC_INLINE path path::filename() const
|
||||
{
|
||||
return relative_path().empty() ? path() : path(*--end());
|
||||
return !has_relative_path() ? path() : path(*--end());
|
||||
}
|
||||
|
||||
GHC_INLINE path path::stem() const
|
||||
@ -2774,10 +2805,10 @@ GHC_INLINE path path::stem() const
|
||||
if (fn != "." && fn != "..") {
|
||||
impl_string_type::size_type pos = fn.rfind('.');
|
||||
if (pos != impl_string_type::npos && pos > 0) {
|
||||
return path{fn.substr(0, pos), generic_format};
|
||||
return path{fn.substr(0, pos), native_format};
|
||||
}
|
||||
}
|
||||
return path{fn, generic_format};
|
||||
return path{fn, native_format};
|
||||
}
|
||||
|
||||
GHC_INLINE path path::extension() const
|
||||
@ -2787,7 +2818,7 @@ GHC_INLINE path path::extension() const
|
||||
const auto& fn = *--iter;
|
||||
impl_string_type::size_type pos = fn._path.rfind('.');
|
||||
if (pos != std::string::npos && pos > 0) {
|
||||
return path(fn._path.substr(pos), generic_format);
|
||||
return path(fn._path.substr(pos), native_format);
|
||||
}
|
||||
}
|
||||
return path();
|
||||
@ -2828,7 +2859,7 @@ GHC_INLINE bool path::has_root_name() const
|
||||
|
||||
GHC_INLINE bool path::has_root_directory() const
|
||||
{
|
||||
auto rootLen = root_name_length();
|
||||
auto rootLen = _prefixLength + root_name_length();
|
||||
return (_path.length() > rootLen && _path[rootLen] == internal_separator);
|
||||
}
|
||||
|
||||
@ -2839,7 +2870,7 @@ GHC_INLINE bool path::has_root_path() const
|
||||
|
||||
GHC_INLINE bool path::has_relative_path() const
|
||||
{
|
||||
auto rootPathLen = root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);
|
||||
return rootPathLen < _path.length();
|
||||
}
|
||||
|
||||
@ -2957,41 +2988,25 @@ GHC_INLINE path path::lexically_proximate(const path& base) const
|
||||
// 30.10.8.5, iterators
|
||||
GHC_INLINE path::iterator::iterator() {}
|
||||
|
||||
GHC_INLINE path::iterator::iterator(const path::impl_string_type::const_iterator& first, const path::impl_string_type::const_iterator& last, const path::impl_string_type::const_iterator& pos)
|
||||
: _first(first)
|
||||
, _last(last)
|
||||
GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos)
|
||||
: _first(p._path.begin())
|
||||
, _last(p._path.end())
|
||||
, _iter(pos)
|
||||
, _prefix(_first + p._prefixLength)
|
||||
, _root(p.has_root_directory() ? _first + p._prefixLength + p.root_name_length() : _last)
|
||||
{
|
||||
updateCurrent();
|
||||
// find the position of a potential root directory slash
|
||||
#ifdef GHC_OS_WINDOWS
|
||||
if (_last - _first >= 3 && std::toupper(static_cast<unsigned char>(*first)) >= 'A' && std::toupper(static_cast<unsigned char>(*first)) <= 'Z' && *(first + 1) == ':' && *(first + 2) == internal_separator) {
|
||||
_root = _first + 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (_first != _last && *_first == internal_separator) {
|
||||
if (_last - _first >= 2 && *(_first + 1) == internal_separator && !(_last - _first >= 3 && *(_first + 2) == internal_separator)) {
|
||||
_root = increment(_first);
|
||||
}
|
||||
else {
|
||||
_root = _first;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_root = _last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const
|
||||
{
|
||||
path::impl_string_type::const_iterator i = pos;
|
||||
bool fromStart = i == _first;
|
||||
bool fromStart = i == _first || i == _prefix;
|
||||
if (i != _last) {
|
||||
// we can only sit on a slash if it is a network name or a root
|
||||
if (*i++ == internal_separator) {
|
||||
if (fromStart && i == _first && _prefix > _first) {
|
||||
i = _prefix;
|
||||
} else if (*i++ == internal_separator) {
|
||||
// we can only sit on a slash if it is a network name or a root
|
||||
if (i != _last && *i == internal_separator) {
|
||||
if (fromStart && !(i + 1 != _last && *(i + 1) == internal_separator)) {
|
||||
// leadind double slashes detected, treat this and the
|
||||
@ -3115,12 +3130,12 @@ GHC_INLINE path::iterator::pointer path::iterator::operator->() const
|
||||
|
||||
GHC_INLINE path::iterator path::begin() const
|
||||
{
|
||||
return iterator(_path.begin(), _path.end(), _path.begin());
|
||||
return iterator(*this, _path.begin());
|
||||
}
|
||||
|
||||
GHC_INLINE path::iterator path::end() const
|
||||
{
|
||||
return iterator(_path.begin(), _path.end(), _path.end());
|
||||
return iterator(*this, _path.end());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -3371,7 +3386,6 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec)
|
||||
return path();
|
||||
}
|
||||
path work = p.is_absolute() ? p : absolute(p, ec);
|
||||
path root = work.root_path();
|
||||
path result;
|
||||
|
||||
auto fs = status(work, ec);
|
||||
@ -3384,6 +3398,7 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec)
|
||||
}
|
||||
bool redo;
|
||||
do {
|
||||
auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0);
|
||||
redo = false;
|
||||
result.clear();
|
||||
for (auto pe : work) {
|
||||
@ -3394,7 +3409,7 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec)
|
||||
result = result.parent_path();
|
||||
continue;
|
||||
}
|
||||
else if ((result / pe).string().length() <= root.string().length()) {
|
||||
else if ((result / pe).string().length() <= rootPathLen) {
|
||||
result /= pe;
|
||||
continue;
|
||||
}
|
||||
@ -3416,6 +3431,7 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec)
|
||||
result /= target;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
result /= pe;
|
||||
|
@ -2797,8 +2797,8 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na
|
||||
{R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,C:,Windows,notepad.exe"},
|
||||
{R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "\\??", "\\??\\", "/??,/,C:,Windows,notepad.exe"},
|
||||
#else
|
||||
{R"(\\?\C:\Windows\notepad.exe)", R"(C:\Windows\notepad.exe)", "C:", "C:\\", "C:,/,Windows,notepad.exe"},
|
||||
{R"(\??\C:\Windows\notepad.exe)", R"(C:\Windows\notepad.exe)", "C:", "C:\\", "C:,/,Windows,notepad.exe"},
|
||||
{R"(\\?\C:\Windows\notepad.exe)", R"(\\?\C:\Windows\notepad.exe)", "C:", "C:\\", "//?/,C:,/,Windows,notepad.exe"},
|
||||
{R"(\??\C:\Windows\notepad.exe)", R"(\??\C:\Windows\notepad.exe)", "C:", "C:\\", "/??/,C:,/,Windows,notepad.exe"},
|
||||
#endif
|
||||
{R"(\\.\C:\Windows\notepad.exe)", R"(\\.\C:\Windows\notepad.exe)", "\\\\.", "\\\\.\\", "//.,/,C:,Windows,notepad.exe"},
|
||||
{R"(\\?\HarddiskVolume1\Windows\notepad.exe)", R"(\\?\HarddiskVolume1\Windows\notepad.exe)", "\\\\?", "\\\\?\\", "//?,/,HarddiskVolume1,Windows,notepad.exe"},
|
||||
@ -2815,6 +2815,7 @@ TEST_CASE("Windows: path namespace handling", "[filesystem][path][fs.path.win.na
|
||||
INFO("Used path: " + ti._path);
|
||||
auto p = fs::path(ti._path);
|
||||
CHECK(p.string() == ti._string);
|
||||
CHECK(p.is_absolute());
|
||||
CHECK(p.root_name().string() == ti._rootName);
|
||||
CHECK(p.root_path().string() == ti._rootPath);
|
||||
CHECK(iterateResult(p) == ti._iterateResult);
|
||||
|
Loading…
x
Reference in New Issue
Block a user