106c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include <__config> 1006c3fb27SDimitry Andric #include <filesystem> 1106c3fb27SDimitry Andric #include <vector> 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #include "error.h" 1406c3fb27SDimitry Andric #include "path_parser.h" 1506c3fb27SDimitry Andric 1606c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 1706c3fb27SDimitry Andric 1806c3fb27SDimitry Andric using detail::ErrorHandler; 1906c3fb27SDimitry Andric using parser::createView; 2006c3fb27SDimitry Andric using parser::PathParser; 2106c3fb27SDimitry Andric using parser::string_view_t; 2206c3fb27SDimitry Andric 2306c3fb27SDimitry Andric /////////////////////////////////////////////////////////////////////////////// 2406c3fb27SDimitry Andric // path definitions 2506c3fb27SDimitry Andric /////////////////////////////////////////////////////////////////////////////// 2606c3fb27SDimitry Andric 2706c3fb27SDimitry Andric constexpr path::value_type path::preferred_separator; 2806c3fb27SDimitry Andric 2906c3fb27SDimitry Andric path& path::replace_extension(path const& replacement) { 3006c3fb27SDimitry Andric path p = extension(); 3106c3fb27SDimitry Andric if (not p.empty()) { 3206c3fb27SDimitry Andric __pn_.erase(__pn_.size() - p.native().size()); 3306c3fb27SDimitry Andric } 3406c3fb27SDimitry Andric if (!replacement.empty()) { 3506c3fb27SDimitry Andric if (replacement.native()[0] != '.') { 3606c3fb27SDimitry Andric __pn_ += PATHSTR("."); 3706c3fb27SDimitry Andric } 3806c3fb27SDimitry Andric __pn_.append(replacement.__pn_); 3906c3fb27SDimitry Andric } 4006c3fb27SDimitry Andric return *this; 4106c3fb27SDimitry Andric } 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric /////////////////////////////////////////////////////////////////////////////// 4406c3fb27SDimitry Andric // path.decompose 4506c3fb27SDimitry Andric 4606c3fb27SDimitry Andric string_view_t path::__root_name() const { 4706c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 48*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_InRootName) 4906c3fb27SDimitry Andric return *PP; 5006c3fb27SDimitry Andric return {}; 5106c3fb27SDimitry Andric } 5206c3fb27SDimitry Andric 5306c3fb27SDimitry Andric string_view_t path::__root_directory() const { 5406c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 55*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_InRootName) 5606c3fb27SDimitry Andric ++PP; 57*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_InRootDir) 5806c3fb27SDimitry Andric return *PP; 5906c3fb27SDimitry Andric return {}; 6006c3fb27SDimitry Andric } 6106c3fb27SDimitry Andric 6206c3fb27SDimitry Andric string_view_t path::__root_path_raw() const { 6306c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 64*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_InRootName) { 6506c3fb27SDimitry Andric auto NextCh = PP.peek(); 6606c3fb27SDimitry Andric if (NextCh && isSeparator(*NextCh)) { 6706c3fb27SDimitry Andric ++PP; 6806c3fb27SDimitry Andric return createView(__pn_.data(), &PP.RawEntry.back()); 6906c3fb27SDimitry Andric } 7006c3fb27SDimitry Andric return PP.RawEntry; 7106c3fb27SDimitry Andric } 72*0fca6ea1SDimitry Andric if (PP.State_ == PathParser::PS_InRootDir) 7306c3fb27SDimitry Andric return *PP; 7406c3fb27SDimitry Andric return {}; 7506c3fb27SDimitry Andric } 7606c3fb27SDimitry Andric 7706c3fb27SDimitry Andric static bool ConsumeRootName(PathParser* PP) { 78cb14a3feSDimitry Andric static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2, "Values for enums are incorrect"); 79*0fca6ea1SDimitry Andric while (PP->State_ <= PathParser::PS_InRootName) 8006c3fb27SDimitry Andric ++(*PP); 81*0fca6ea1SDimitry Andric return PP->State_ == PathParser::PS_AtEnd; 8206c3fb27SDimitry Andric } 8306c3fb27SDimitry Andric 8406c3fb27SDimitry Andric static bool ConsumeRootDir(PathParser* PP) { 85cb14a3feSDimitry Andric static_assert(PathParser::PS_BeforeBegin == 1 && PathParser::PS_InRootName == 2 && PathParser::PS_InRootDir == 3, 86cb14a3feSDimitry Andric "Values for enums are incorrect"); 87*0fca6ea1SDimitry Andric while (PP->State_ <= PathParser::PS_InRootDir) 8806c3fb27SDimitry Andric ++(*PP); 89*0fca6ea1SDimitry Andric return PP->State_ == PathParser::PS_AtEnd; 9006c3fb27SDimitry Andric } 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric string_view_t path::__relative_path() const { 9306c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 9406c3fb27SDimitry Andric if (ConsumeRootDir(&PP)) 9506c3fb27SDimitry Andric return {}; 9606c3fb27SDimitry Andric return createView(PP.RawEntry.data(), &__pn_.back()); 9706c3fb27SDimitry Andric } 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric string_view_t path::__parent_path() const { 10006c3fb27SDimitry Andric if (empty()) 10106c3fb27SDimitry Andric return {}; 10206c3fb27SDimitry Andric // Determine if we have a root path but not a relative path. In that case 10306c3fb27SDimitry Andric // return *this. 10406c3fb27SDimitry Andric { 10506c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 10606c3fb27SDimitry Andric if (ConsumeRootDir(&PP)) 10706c3fb27SDimitry Andric return __pn_; 10806c3fb27SDimitry Andric } 10906c3fb27SDimitry Andric // Otherwise remove a single element from the end of the path, and return 11006c3fb27SDimitry Andric // a string representing that path 11106c3fb27SDimitry Andric { 11206c3fb27SDimitry Andric auto PP = PathParser::CreateEnd(__pn_); 11306c3fb27SDimitry Andric --PP; 11406c3fb27SDimitry Andric if (PP.RawEntry.data() == __pn_.data()) 11506c3fb27SDimitry Andric return {}; 11606c3fb27SDimitry Andric --PP; 11706c3fb27SDimitry Andric return createView(__pn_.data(), &PP.RawEntry.back()); 11806c3fb27SDimitry Andric } 11906c3fb27SDimitry Andric } 12006c3fb27SDimitry Andric 12106c3fb27SDimitry Andric string_view_t path::__filename() const { 12206c3fb27SDimitry Andric if (empty()) 12306c3fb27SDimitry Andric return {}; 12406c3fb27SDimitry Andric { 12506c3fb27SDimitry Andric PathParser PP = PathParser::CreateBegin(__pn_); 12606c3fb27SDimitry Andric if (ConsumeRootDir(&PP)) 12706c3fb27SDimitry Andric return {}; 12806c3fb27SDimitry Andric } 12906c3fb27SDimitry Andric return *(--PathParser::CreateEnd(__pn_)); 13006c3fb27SDimitry Andric } 13106c3fb27SDimitry Andric 132cb14a3feSDimitry Andric string_view_t path::__stem() const { return parser::separate_filename(__filename()).first; } 13306c3fb27SDimitry Andric 134cb14a3feSDimitry Andric string_view_t path::__extension() const { return parser::separate_filename(__filename()).second; } 13506c3fb27SDimitry Andric 13606c3fb27SDimitry Andric //////////////////////////////////////////////////////////////////////////// 13706c3fb27SDimitry Andric // path.gen 13806c3fb27SDimitry Andric 139cb14a3feSDimitry Andric enum PathPartKind : unsigned char { PK_None, PK_RootSep, PK_Filename, PK_Dot, PK_DotDot, PK_TrailingSep }; 14006c3fb27SDimitry Andric 14106c3fb27SDimitry Andric static PathPartKind ClassifyPathPart(string_view_t Part) { 14206c3fb27SDimitry Andric if (Part.empty()) 14306c3fb27SDimitry Andric return PK_TrailingSep; 14406c3fb27SDimitry Andric if (Part == PATHSTR(".")) 14506c3fb27SDimitry Andric return PK_Dot; 14606c3fb27SDimitry Andric if (Part == PATHSTR("..")) 14706c3fb27SDimitry Andric return PK_DotDot; 14806c3fb27SDimitry Andric if (Part == PATHSTR("/")) 14906c3fb27SDimitry Andric return PK_RootSep; 15006c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 15106c3fb27SDimitry Andric if (Part == PATHSTR("\\")) 15206c3fb27SDimitry Andric return PK_RootSep; 15306c3fb27SDimitry Andric #endif 15406c3fb27SDimitry Andric return PK_Filename; 15506c3fb27SDimitry Andric } 15606c3fb27SDimitry Andric 15706c3fb27SDimitry Andric path path::lexically_normal() const { 15806c3fb27SDimitry Andric if (__pn_.empty()) 15906c3fb27SDimitry Andric return *this; 16006c3fb27SDimitry Andric 16106c3fb27SDimitry Andric using PartKindPair = pair<string_view_t, PathPartKind>; 16206c3fb27SDimitry Andric vector<PartKindPair> Parts; 16306c3fb27SDimitry Andric // Guess as to how many elements the path has to avoid reallocating. 16406c3fb27SDimitry Andric Parts.reserve(32); 16506c3fb27SDimitry Andric 16606c3fb27SDimitry Andric // Track the total size of the parts as we collect them. This allows the 16706c3fb27SDimitry Andric // resulting path to reserve the correct amount of memory. 16806c3fb27SDimitry Andric size_t NewPathSize = 0; 16906c3fb27SDimitry Andric auto AddPart = [&](PathPartKind K, string_view_t P) { 17006c3fb27SDimitry Andric NewPathSize += P.size(); 17106c3fb27SDimitry Andric Parts.emplace_back(P, K); 17206c3fb27SDimitry Andric }; 17306c3fb27SDimitry Andric auto LastPartKind = [&]() { 17406c3fb27SDimitry Andric if (Parts.empty()) 17506c3fb27SDimitry Andric return PK_None; 17606c3fb27SDimitry Andric return Parts.back().second; 17706c3fb27SDimitry Andric }; 17806c3fb27SDimitry Andric 17906c3fb27SDimitry Andric bool MaybeNeedTrailingSep = false; 18006c3fb27SDimitry Andric // Build a stack containing the remaining elements of the path, popping off 18106c3fb27SDimitry Andric // elements which occur before a '..' entry. 18206c3fb27SDimitry Andric for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) { 18306c3fb27SDimitry Andric auto Part = *PP; 18406c3fb27SDimitry Andric PathPartKind Kind = ClassifyPathPart(Part); 18506c3fb27SDimitry Andric switch (Kind) { 18606c3fb27SDimitry Andric case PK_Filename: 18706c3fb27SDimitry Andric case PK_RootSep: { 18806c3fb27SDimitry Andric // Add all non-dot and non-dot-dot elements to the stack of elements. 18906c3fb27SDimitry Andric AddPart(Kind, Part); 19006c3fb27SDimitry Andric MaybeNeedTrailingSep = false; 19106c3fb27SDimitry Andric break; 19206c3fb27SDimitry Andric } 19306c3fb27SDimitry Andric case PK_DotDot: { 19406c3fb27SDimitry Andric // Only push a ".." element if there are no elements preceding the "..", 19506c3fb27SDimitry Andric // or if the preceding element is itself "..". 19606c3fb27SDimitry Andric auto LastKind = LastPartKind(); 19706c3fb27SDimitry Andric if (LastKind == PK_Filename) { 19806c3fb27SDimitry Andric NewPathSize -= Parts.back().first.size(); 19906c3fb27SDimitry Andric Parts.pop_back(); 20006c3fb27SDimitry Andric } else if (LastKind != PK_RootSep) 20106c3fb27SDimitry Andric AddPart(PK_DotDot, PATHSTR("..")); 20206c3fb27SDimitry Andric MaybeNeedTrailingSep = LastKind == PK_Filename; 20306c3fb27SDimitry Andric break; 20406c3fb27SDimitry Andric } 20506c3fb27SDimitry Andric case PK_Dot: 20606c3fb27SDimitry Andric case PK_TrailingSep: { 20706c3fb27SDimitry Andric MaybeNeedTrailingSep = true; 20806c3fb27SDimitry Andric break; 20906c3fb27SDimitry Andric } 21006c3fb27SDimitry Andric case PK_None: 21106c3fb27SDimitry Andric __libcpp_unreachable(); 21206c3fb27SDimitry Andric } 21306c3fb27SDimitry Andric } 21406c3fb27SDimitry Andric // [fs.path.generic]p6.8: If the path is empty, add a dot. 21506c3fb27SDimitry Andric if (Parts.empty()) 21606c3fb27SDimitry Andric return PATHSTR("."); 21706c3fb27SDimitry Andric 21806c3fb27SDimitry Andric // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any 21906c3fb27SDimitry Andric // trailing directory-separator. 22006c3fb27SDimitry Andric bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename; 22106c3fb27SDimitry Andric 22206c3fb27SDimitry Andric path Result; 22306c3fb27SDimitry Andric Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep); 22406c3fb27SDimitry Andric for (auto& PK : Parts) 22506c3fb27SDimitry Andric Result /= PK.first; 22606c3fb27SDimitry Andric 22706c3fb27SDimitry Andric if (NeedTrailingSep) 22806c3fb27SDimitry Andric Result /= PATHSTR(""); 22906c3fb27SDimitry Andric 23006c3fb27SDimitry Andric Result.make_preferred(); 23106c3fb27SDimitry Andric return Result; 23206c3fb27SDimitry Andric } 23306c3fb27SDimitry Andric 23406c3fb27SDimitry Andric static int DetermineLexicalElementCount(PathParser PP) { 23506c3fb27SDimitry Andric int Count = 0; 23606c3fb27SDimitry Andric for (; PP; ++PP) { 23706c3fb27SDimitry Andric auto Elem = *PP; 23806c3fb27SDimitry Andric if (Elem == PATHSTR("..")) 23906c3fb27SDimitry Andric --Count; 24006c3fb27SDimitry Andric else if (Elem != PATHSTR(".") && Elem != PATHSTR("")) 24106c3fb27SDimitry Andric ++Count; 24206c3fb27SDimitry Andric } 24306c3fb27SDimitry Andric return Count; 24406c3fb27SDimitry Andric } 24506c3fb27SDimitry Andric 24606c3fb27SDimitry Andric path path::lexically_relative(const path& base) const { 24706c3fb27SDimitry Andric { // perform root-name/root-directory mismatch checks 24806c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 24906c3fb27SDimitry Andric auto PPBase = PathParser::CreateBegin(base.__pn_); 25006c3fb27SDimitry Andric auto CheckIterMismatchAtBase = [&]() { 251*0fca6ea1SDimitry Andric return PP.State_ != PPBase.State_ && (PP.inRootPath() || PPBase.inRootPath()); 25206c3fb27SDimitry Andric }; 25306c3fb27SDimitry Andric if (PP.inRootName() && PPBase.inRootName()) { 25406c3fb27SDimitry Andric if (*PP != *PPBase) 25506c3fb27SDimitry Andric return {}; 25606c3fb27SDimitry Andric } else if (CheckIterMismatchAtBase()) 25706c3fb27SDimitry Andric return {}; 25806c3fb27SDimitry Andric 25906c3fb27SDimitry Andric if (PP.inRootPath()) 26006c3fb27SDimitry Andric ++PP; 26106c3fb27SDimitry Andric if (PPBase.inRootPath()) 26206c3fb27SDimitry Andric ++PPBase; 26306c3fb27SDimitry Andric if (CheckIterMismatchAtBase()) 26406c3fb27SDimitry Andric return {}; 26506c3fb27SDimitry Andric } 26606c3fb27SDimitry Andric 26706c3fb27SDimitry Andric // Find the first mismatching element 26806c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 26906c3fb27SDimitry Andric auto PPBase = PathParser::CreateBegin(base.__pn_); 270*0fca6ea1SDimitry Andric while (PP && PPBase && PP.State_ == PPBase.State_ && *PP == *PPBase) { 27106c3fb27SDimitry Andric ++PP; 27206c3fb27SDimitry Andric ++PPBase; 27306c3fb27SDimitry Andric } 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric // If there is no mismatch, return ".". 27606c3fb27SDimitry Andric if (!PP && !PPBase) 27706c3fb27SDimitry Andric return "."; 27806c3fb27SDimitry Andric 27906c3fb27SDimitry Andric // Otherwise, determine the number of elements, 'n', which are not dot or 28006c3fb27SDimitry Andric // dot-dot minus the number of dot-dot elements. 28106c3fb27SDimitry Andric int ElemCount = DetermineLexicalElementCount(PPBase); 28206c3fb27SDimitry Andric if (ElemCount < 0) 28306c3fb27SDimitry Andric return {}; 28406c3fb27SDimitry Andric 28506c3fb27SDimitry Andric // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise 28606c3fb27SDimitry Andric if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR(""))) 28706c3fb27SDimitry Andric return PATHSTR("."); 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric // return a path constructed with 'n' dot-dot elements, followed by the 29006c3fb27SDimitry Andric // elements of '*this' after the mismatch. 29106c3fb27SDimitry Andric path Result; 29206c3fb27SDimitry Andric // FIXME: Reserve enough room in Result that it won't have to re-allocate. 29306c3fb27SDimitry Andric while (ElemCount--) 29406c3fb27SDimitry Andric Result /= PATHSTR(".."); 29506c3fb27SDimitry Andric for (; PP; ++PP) 29606c3fb27SDimitry Andric Result /= *PP; 29706c3fb27SDimitry Andric return Result; 29806c3fb27SDimitry Andric } 29906c3fb27SDimitry Andric 30006c3fb27SDimitry Andric //////////////////////////////////////////////////////////////////////////// 30106c3fb27SDimitry Andric // path.comparisons 30206c3fb27SDimitry Andric static int CompareRootName(PathParser* LHS, PathParser* RHS) { 30306c3fb27SDimitry Andric if (!LHS->inRootName() && !RHS->inRootName()) 30406c3fb27SDimitry Andric return 0; 30506c3fb27SDimitry Andric 306cb14a3feSDimitry Andric auto GetRootName = [](PathParser* Parser) -> string_view_t { return Parser->inRootName() ? **Parser : PATHSTR(""); }; 30706c3fb27SDimitry Andric int res = GetRootName(LHS).compare(GetRootName(RHS)); 30806c3fb27SDimitry Andric ConsumeRootName(LHS); 30906c3fb27SDimitry Andric ConsumeRootName(RHS); 31006c3fb27SDimitry Andric return res; 31106c3fb27SDimitry Andric } 31206c3fb27SDimitry Andric 31306c3fb27SDimitry Andric static int CompareRootDir(PathParser* LHS, PathParser* RHS) { 31406c3fb27SDimitry Andric if (!LHS->inRootDir() && RHS->inRootDir()) 31506c3fb27SDimitry Andric return -1; 31606c3fb27SDimitry Andric else if (LHS->inRootDir() && !RHS->inRootDir()) 31706c3fb27SDimitry Andric return 1; 31806c3fb27SDimitry Andric else { 31906c3fb27SDimitry Andric ConsumeRootDir(LHS); 32006c3fb27SDimitry Andric ConsumeRootDir(RHS); 32106c3fb27SDimitry Andric return 0; 32206c3fb27SDimitry Andric } 32306c3fb27SDimitry Andric } 32406c3fb27SDimitry Andric 32506c3fb27SDimitry Andric static int CompareRelative(PathParser* LHSPtr, PathParser* RHSPtr) { 32606c3fb27SDimitry Andric auto& LHS = *LHSPtr; 32706c3fb27SDimitry Andric auto& RHS = *RHSPtr; 32806c3fb27SDimitry Andric 32906c3fb27SDimitry Andric int res; 33006c3fb27SDimitry Andric while (LHS && RHS) { 33106c3fb27SDimitry Andric if ((res = (*LHS).compare(*RHS)) != 0) 33206c3fb27SDimitry Andric return res; 33306c3fb27SDimitry Andric ++LHS; 33406c3fb27SDimitry Andric ++RHS; 33506c3fb27SDimitry Andric } 33606c3fb27SDimitry Andric return 0; 33706c3fb27SDimitry Andric } 33806c3fb27SDimitry Andric 33906c3fb27SDimitry Andric static int CompareEndState(PathParser* LHS, PathParser* RHS) { 34006c3fb27SDimitry Andric if (LHS->atEnd() && !RHS->atEnd()) 34106c3fb27SDimitry Andric return -1; 34206c3fb27SDimitry Andric else if (!LHS->atEnd() && RHS->atEnd()) 34306c3fb27SDimitry Andric return 1; 34406c3fb27SDimitry Andric return 0; 34506c3fb27SDimitry Andric } 34606c3fb27SDimitry Andric 34706c3fb27SDimitry Andric int path::__compare(string_view_t __s) const { 34806c3fb27SDimitry Andric auto LHS = PathParser::CreateBegin(__pn_); 34906c3fb27SDimitry Andric auto RHS = PathParser::CreateBegin(__s); 35006c3fb27SDimitry Andric int res; 35106c3fb27SDimitry Andric 35206c3fb27SDimitry Andric if ((res = CompareRootName(&LHS, &RHS)) != 0) 35306c3fb27SDimitry Andric return res; 35406c3fb27SDimitry Andric 35506c3fb27SDimitry Andric if ((res = CompareRootDir(&LHS, &RHS)) != 0) 35606c3fb27SDimitry Andric return res; 35706c3fb27SDimitry Andric 35806c3fb27SDimitry Andric if ((res = CompareRelative(&LHS, &RHS)) != 0) 35906c3fb27SDimitry Andric return res; 36006c3fb27SDimitry Andric 36106c3fb27SDimitry Andric return CompareEndState(&LHS, &RHS); 36206c3fb27SDimitry Andric } 36306c3fb27SDimitry Andric 36406c3fb27SDimitry Andric //////////////////////////////////////////////////////////////////////////// 36506c3fb27SDimitry Andric // path.nonmembers 36606c3fb27SDimitry Andric size_t hash_value(const path& __p) noexcept { 36706c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__p.native()); 36806c3fb27SDimitry Andric size_t hash_value = 0; 36906c3fb27SDimitry Andric hash<string_view_t> hasher; 37006c3fb27SDimitry Andric while (PP) { 37106c3fb27SDimitry Andric hash_value = __hash_combine(hash_value, hasher(*PP)); 37206c3fb27SDimitry Andric ++PP; 37306c3fb27SDimitry Andric } 37406c3fb27SDimitry Andric return hash_value; 37506c3fb27SDimitry Andric } 37606c3fb27SDimitry Andric 37706c3fb27SDimitry Andric //////////////////////////////////////////////////////////////////////////// 37806c3fb27SDimitry Andric // path.itr 37906c3fb27SDimitry Andric path::iterator path::begin() const { 38006c3fb27SDimitry Andric auto PP = PathParser::CreateBegin(__pn_); 38106c3fb27SDimitry Andric iterator it; 38206c3fb27SDimitry Andric it.__path_ptr_ = this; 383*0fca6ea1SDimitry Andric it.__state_ = static_cast<path::iterator::_ParserState>(PP.State_); 38406c3fb27SDimitry Andric it.__entry_ = PP.RawEntry; 38506c3fb27SDimitry Andric it.__stashed_elem_.__assign_view(*PP); 38606c3fb27SDimitry Andric return it; 38706c3fb27SDimitry Andric } 38806c3fb27SDimitry Andric 38906c3fb27SDimitry Andric path::iterator path::end() const { 39006c3fb27SDimitry Andric iterator it{}; 39106c3fb27SDimitry Andric it.__state_ = path::iterator::_AtEnd; 39206c3fb27SDimitry Andric it.__path_ptr_ = this; 39306c3fb27SDimitry Andric return it; 39406c3fb27SDimitry Andric } 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric path::iterator& path::iterator::__increment() { 39706c3fb27SDimitry Andric PathParser PP(__path_ptr_->native(), __entry_, __state_); 39806c3fb27SDimitry Andric ++PP; 399*0fca6ea1SDimitry Andric __state_ = static_cast<_ParserState>(PP.State_); 40006c3fb27SDimitry Andric __entry_ = PP.RawEntry; 40106c3fb27SDimitry Andric __stashed_elem_.__assign_view(*PP); 40206c3fb27SDimitry Andric return *this; 40306c3fb27SDimitry Andric } 40406c3fb27SDimitry Andric 40506c3fb27SDimitry Andric path::iterator& path::iterator::__decrement() { 40606c3fb27SDimitry Andric PathParser PP(__path_ptr_->native(), __entry_, __state_); 40706c3fb27SDimitry Andric --PP; 408*0fca6ea1SDimitry Andric __state_ = static_cast<_ParserState>(PP.State_); 40906c3fb27SDimitry Andric __entry_ = PP.RawEntry; 41006c3fb27SDimitry Andric __stashed_elem_.__assign_view(*PP); 41106c3fb27SDimitry Andric return *this; 41206c3fb27SDimitry Andric } 41306c3fb27SDimitry Andric 41406c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API) 41506c3fb27SDimitry Andric //////////////////////////////////////////////////////////////////////////// 41606c3fb27SDimitry Andric // Windows path conversions 41706c3fb27SDimitry Andric size_t __wide_to_char(const wstring& str, char* out, size_t outlen) { 41806c3fb27SDimitry Andric if (str.empty()) 41906c3fb27SDimitry Andric return 0; 42006c3fb27SDimitry Andric ErrorHandler<size_t> err("__wide_to_char", nullptr); 42106c3fb27SDimitry Andric UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; 42206c3fb27SDimitry Andric BOOL used_default = FALSE; 423cb14a3feSDimitry Andric int ret = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, outlen, nullptr, &used_default); 42406c3fb27SDimitry Andric if (ret <= 0 || used_default) 42506c3fb27SDimitry Andric return err.report(errc::illegal_byte_sequence); 42606c3fb27SDimitry Andric return ret; 42706c3fb27SDimitry Andric } 42806c3fb27SDimitry Andric 42906c3fb27SDimitry Andric size_t __char_to_wide(const string& str, wchar_t* out, size_t outlen) { 43006c3fb27SDimitry Andric if (str.empty()) 43106c3fb27SDimitry Andric return 0; 43206c3fb27SDimitry Andric ErrorHandler<size_t> err("__char_to_wide", nullptr); 43306c3fb27SDimitry Andric UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; 434cb14a3feSDimitry Andric int ret = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), str.size(), out, outlen); 43506c3fb27SDimitry Andric if (ret <= 0) 43606c3fb27SDimitry Andric return err.report(errc::illegal_byte_sequence); 43706c3fb27SDimitry Andric return ret; 43806c3fb27SDimitry Andric } 43906c3fb27SDimitry Andric #endif 44006c3fb27SDimitry Andric 44106c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM 442