Index: libcxx/include/filesystem =================================================================== --- libcxx/include/filesystem +++ libcxx/include/filesystem @@ -568,9 +568,21 @@ template typename enable_if<__can_convert_char<_ECharT>::value, bool>::type __is_separator(_ECharT __e) { +#if defined(_LIBCPP_WIN32API) + return __e == _ECharT('/') || __e == _ECharT('\\'); +#else return __e == _ECharT('/'); +#endif } +#ifndef _LIBCPP_NO_HAS_CHAR8_T +typedef char8_t __u8_value; +typedef u8string __u8_string; +#else +typedef char __u8_value; +typedef string __u8_string; +#endif + struct _NullSentinel {}; template @@ -672,6 +684,14 @@ template struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {}; +#if defined(_LIBCPP_WIN32API) +typedef wstring __path_string; +typedef wchar_t __path_value; +#else +typedef string __path_string; +typedef char __path_value; +#endif + template struct _PathCVT; @@ -682,24 +702,40 @@ "Char type not convertible"); typedef __narrow_to_utf8 _Narrower; +#if defined(_LIBCPP_WIN32API) + typedef __widen_from_utf8 _Widener; +#endif - static void __append_range(string& __dest, _ECharT const* __b, + static void __append_range(__path_string& __dest, _ECharT const* __b, _ECharT const* __e) { +#if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __b, __e); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +#else _Narrower()(back_inserter(__dest), __b, __e); +#endif } template - static void __append_range(string& __dest, _Iter __b, _Iter __e) { + static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); if (__b == __e) return; basic_string<_ECharT> __tmp(__b, __e); +#if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __tmp.data(), + __tmp.data() + __tmp.length()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +#else _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length()); +#endif } template - static void __append_range(string& __dest, _Iter __b, _NullSentinel) { + static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); const _ECharT __sentinel = _ECharT{}; if (*__b == __sentinel) @@ -707,12 +743,19 @@ basic_string<_ECharT> __tmp; for (; *__b != __sentinel; ++__b) __tmp.push_back(*__b); +#if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __tmp.data(), + __tmp.data() + __tmp.length()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +#else _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length()); +#endif } template - static void __append_source(string& __dest, _Source const& __s) { + static void __append_source(__path_string& __dest, _Source const& __s) { using _Traits = __is_pathable<_Source>; __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); @@ -721,36 +764,79 @@ #endif // !_LIBCPP_HAS_NO_LOCALIZATION template <> -struct _PathCVT { +struct _PathCVT<__path_value> { template static typename enable_if<__is_exactly_cpp17_input_iterator<_Iter>::value>::type - __append_range(string& __dest, _Iter __b, _Iter __e) { + __append_range(__path_string& __dest, _Iter __b, _Iter __e) { for (; __b != __e; ++__b) __dest.push_back(*__b); } template static typename enable_if<__is_cpp17_forward_iterator<_Iter>::value>::type - __append_range(string& __dest, _Iter __b, _Iter __e) { + __append_range(__path_string& __dest, _Iter __b, _Iter __e) { __dest.__append_forward_unsafe(__b, __e); } template - static void __append_range(string& __dest, _Iter __b, _NullSentinel) { + static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { const char __sentinel = char{}; for (; *__b != __sentinel; ++__b) __dest.push_back(*__b); } template - static void __append_source(string& __dest, _Source const& __s) { + static void __append_source(__path_string& __dest, _Source const& __s) { using _Traits = __is_pathable<_Source>; __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); } }; +#if defined(_LIBCPP_WIN32API) +template +struct _PathExport { + typedef __narrow_to_utf8 _Narrower; + typedef __widen_from_utf8 _Widener; + + template + static void __append(_Str& __dest, const __path_string& __src) { + string __utf8; + _Narrower()(back_inserter(__utf8), __src.data(), __src.data() + __src.size()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); + } +}; + +template <> +struct _PathExport { + template + static void __append(_Str& __dest, const __path_string& __src) { + __dest.append(__src.begin(), __src.end()); + } +}; + +template <> +struct _PathExport { + template + static void __append(_Str& __dest, const __path_string& __src) { + __dest.append(__src.begin(), __src.end()); + } +}; + +#ifndef _LIBCPP_NO_HAS_CHAR8_T +template <> +struct _PathExport { + typedef __narrow_to_utf8 _Narrower; + + template + static void __append(_Str& __dest, const __path_string& __src) { + _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size()); + } +}; +#endif +#endif + class _LIBCPP_TYPE_VIS path { template using _EnableIfPathable = @@ -763,10 +849,15 @@ using _SourceCVT = _PathCVT<_SourceChar<_Tp> >; public: +#if defined(_LIBCPP_WIN32API) + typedef wchar_t value_type; + static constexpr value_type preferred_separator = '\\'; +#else typedef char value_type; - typedef basic_string string_type; - typedef _VSTD::string_view __string_view; static constexpr value_type preferred_separator = '/'; +#endif + typedef basic_string string_type; + typedef basic_string_view __string_view; enum class _LIBCPP_ENUM_VIS format : unsigned char { auto_format, @@ -1001,6 +1092,52 @@ _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; } +#if defined(_LIBCPP_WIN32API) + _LIBCPP_INLINE_VISIBILITY std::wstring wstring() const { return __pn_; } + + std::wstring generic_wstring() const { return __pn_; } + +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + template , + class _Allocator = allocator<_ECharT> > + basic_string<_ECharT, _Traits, _Allocator> + string(const _Allocator& __a = _Allocator()) const { + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s(__a); + __s.reserve(__pn_.size()); + _PathExport<_ECharT>::__append(__s, __pn_); + return __s; + } + + _LIBCPP_INLINE_VISIBILITY std::string string() const { + return string(); + } + _LIBCPP_INLINE_VISIBILITY __u8_string u8string() const { + return string<__u8_value>(); + } + + _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const { + return string(); + } + _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { + return string(); + } + + // generic format observers + template , + class _Allocator = allocator<_ECharT> > + basic_string<_ECharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const { + return string<_ECharT, _Traits, _Allocator>(__a); + } + + std::string generic_string() const { return generic_string(); } + std::u16string generic_u16string() const { return generic_string(); } + std::u32string generic_u32string() const { return generic_string(); } + __u8_string generic_u8string() const { return u8string(); } +#endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ +#else /* !_WIN32 */ + _LIBCPP_INLINE_VISIBILITY std::string string() const { return __pn_; } #ifndef _LIBCPP_NO_HAS_CHAR8_T _LIBCPP_INLINE_VISIBILITY std::u8string u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); } @@ -1030,7 +1167,7 @@ _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const { return string(); } -#endif +#endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ // generic format observers std::string generic_string() const { return __pn_; } @@ -1051,7 +1188,8 @@ std::wstring generic_wstring() const { return string(); } std::u16string generic_u16string() const { return string(); } std::u32string generic_u32string() const { return string(); } -#endif +#endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ +#endif /* !_LIBCPP_WIN32API */ private: int __compare(__string_view) const; @@ -1158,7 +1296,7 @@ #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) template _LIBCPP_INLINE_VISIBILITY friend - typename enable_if::value && + typename enable_if::value && is_same<_Traits, char_traits >::value, basic_ostream<_CharT, _Traits>&>::type operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { @@ -1168,7 +1306,7 @@ template _LIBCPP_INLINE_VISIBILITY friend - typename enable_if::value || + typename enable_if::value || !is_same<_Traits, char_traits >::value, basic_ostream<_CharT, _Traits>&>::type operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { Index: libcxx/src/filesystem/filesystem_common.h =================================================================== --- libcxx/src/filesystem/filesystem_common.h +++ libcxx/src/filesystem/filesystem_common.h @@ -38,6 +38,12 @@ #pragma GCC diagnostic ignored "-Wunused-function" #endif +#if defined(_LIBCPP_WIN32API) +#define PS(x) (L##x) +#else +#define PS(x) (x) +#endif + _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM namespace detail { @@ -94,8 +100,8 @@ return result; } -const char* unwrap(string const& s) { return s.c_str(); } -const char* unwrap(path const& p) { return p.native().c_str(); } +const path::value_type* unwrap(path::string_type const& s) { return s.c_str(); } +const path::value_type* unwrap(path const& p) { return p.native().c_str(); } template Arg const& unwrap(Arg const& a) { static_assert(!is_class::value, "cannot pass class here"); Index: libcxx/src/filesystem/operations.cpp =================================================================== --- libcxx/src/filesystem/operations.cpp +++ libcxx/src/filesystem/operations.cpp @@ -171,11 +171,11 @@ switch (State) { case PS_BeforeBegin: case PS_AtEnd: - return ""; + return PS(""); case PS_InRootDir: - return "/"; + return PS("/"); case PS_InTrailingSep: - return ""; + return PS(""); case PS_InRootName: case PS_InFilenames: return RawEntry; @@ -283,8 +283,8 @@ }; string_view_pair separate_filename(string_view_t const& s) { - if (s == "." || s == ".." || s.empty()) - return string_view_pair{s, ""}; + if (s == PS(".") || s == PS("..") || s.empty()) + return string_view_pair{s, PS("")}; auto pos = s.find_last_of('.'); if (pos == string_view_t::npos || pos == 0) return string_view_pair{s, string_view_t{}}; @@ -495,19 +495,25 @@ filesystem_error::~filesystem_error() {} +#if defined(_LIBCPP_WIN32API) +#define PS_FMT "%ls" +#else +#define PS_FMT "%s" +#endif + void filesystem_error::__create_what(int __num_paths) { const char* derived_what = system_error::what(); __storage_->__what_ = [&]() -> string { - const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str(); - const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str(); + const path::value_type* p1 = path1().native().empty() ? PS("\"\"") : path1().c_str(); + const path::value_type* p2 = path2().native().empty() ? PS("\"\"") : path2().c_str(); switch (__num_paths) { default: return detail::format_string("filesystem error: %s", derived_what); case 1: - return detail::format_string("filesystem error: %s [%s]", derived_what, + return detail::format_string("filesystem error: %s [" PS_FMT "]", derived_what, p1); case 2: - return detail::format_string("filesystem error: %s [%s] [%s]", + return detail::format_string("filesystem error: %s [" PS_FMT "] [" PS_FMT "]", derived_what, p1, p2); } }(); @@ -1204,10 +1210,10 @@ error_code m_ec; file_status st = detail::posix_stat(p, &m_ec); if (!status_known(st)) - return err.report(m_ec, "cannot access path \"%s\"", p); + return err.report(m_ec, "cannot access path \"" PS_FMT "\"", p); if (!exists(st) || !is_directory(st)) - return err.report(errc::not_a_directory, "path \"%s\" is not a directory", + return err.report(errc::not_a_directory, "path \"" PS_FMT "\" is not a directory", p); return p; @@ -1263,7 +1269,7 @@ } if (!replacement.empty()) { if (replacement.native()[0] != '.') { - __pn_ += "."; + __pn_ += PS("."); } __pn_.append(replacement.__pn_); } @@ -1385,11 +1391,11 @@ static PathPartKind ClassifyPathPart(string_view_t Part) { if (Part.empty()) return PK_TrailingSep; - if (Part == ".") + if (Part == PS(".")) return PK_Dot; - if (Part == "..") + if (Part == PS("..")) return PK_DotDot; - if (Part == "/") + if (Part == PS("/")) return PK_RootSep; return PK_Filename; } @@ -1438,7 +1444,7 @@ NewPathSize -= Parts.back().first.size(); Parts.pop_back(); } else if (LastKind != PK_RootSep) - AddPart(PK_DotDot, ".."); + AddPart(PK_DotDot, PS("..")); MaybeNeedTrailingSep = LastKind == PK_Filename; break; } @@ -1453,7 +1459,7 @@ } // [fs.path.generic]p6.8: If the path is empty, add a dot. if (Parts.empty()) - return "."; + return PS("."); // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any // trailing directory-separator. @@ -1465,7 +1471,7 @@ Result /= PK.first; if (NeedTrailingSep) - Result /= ""; + Result /= PS(""); return Result; } @@ -1474,9 +1480,9 @@ int Count = 0; for (; PP; ++PP) { auto Elem = *PP; - if (Elem == "..") + if (Elem == PS("..")) --Count; - else if (Elem != "." && Elem != "") + else if (Elem != PS(".") && Elem != PS("")) ++Count; } return Count; @@ -1523,15 +1529,15 @@ return {}; // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise - if (ElemCount == 0 && (PP.atEnd() || *PP == "")) - return "."; + if (ElemCount == 0 && (PP.atEnd() || *PP == PS(""))) + return PS("."); // return a path constructed with 'n' dot-dot elements, followed by the the // elements of '*this' after the mismatch. path Result; // FIXME: Reserve enough room in Result that it won't have to re-allocate. while (ElemCount--) - Result /= ".."; + Result /= PS(".."); for (; PP; ++PP) Result /= *PP; return Result; @@ -1544,7 +1550,7 @@ return 0; auto GetRootName = [](PathParser *Parser) -> string_view_t { - return Parser->inRootName() ? **Parser : ""; + return Parser->inRootName() ? **Parser : PS(""); }; int res = GetRootName(LHS).compare(GetRootName(RHS)); ConsumeRootName(LHS);