Skip to content

Commit

Permalink
[libcxx] Implement parsing of root_name for paths on windows
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D91176
  • Loading branch information
mstorsjo committed Feb 17, 2021
1 parent 8ddfcec commit 929f0bc
Showing 1 changed file with 85 additions and 7 deletions.
92 changes: 85 additions & 7 deletions libcxx/src/filesystem/operations.cpp
Expand Up @@ -64,6 +64,10 @@ bool isSeparator(path::value_type C) {
return false;
}

bool isDriveLetter(path::value_type C) {
return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z');
}

namespace parser {

using string_view_t = path::__string_view;
Expand Down Expand Up @@ -120,6 +124,12 @@ struct PathParser {

switch (State) {
case PS_BeforeBegin: {
PosPtr TkEnd = consumeRootName(Start, End);
if (TkEnd)
return makeState(PS_InRootName, Start, TkEnd);
}
_LIBCPP_FALLTHROUGH();
case PS_InRootName: {
PosPtr TkEnd = consumeSeparator(Start, End);
if (TkEnd)
return makeState(PS_InRootDir, Start, TkEnd);
Expand All @@ -142,7 +152,6 @@ struct PathParser {
case PS_InTrailingSep:
return makeState(PS_AtEnd);

case PS_InRootName:
case PS_AtEnd:
_LIBCPP_UNREACHABLE();
}
Expand All @@ -160,9 +169,15 @@ struct PathParser {
if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
PosPtr TkStart = consumeRootName(SepEnd, REnd);
if (TkStart == REnd)
return makeState(PS_InRootDir, RStart, RStart + 1);
return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
} else {
PosPtr TkStart = consumeName(RStart, REnd);
PosPtr TkStart = consumeRootName(RStart, REnd);
if (TkStart == REnd)
return makeState(PS_InRootName, TkStart + 1, RStart + 1);
TkStart = consumeName(RStart, REnd);
return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
}
}
Expand All @@ -173,11 +188,17 @@ struct PathParser {
PosPtr SepEnd = consumeSeparator(RStart, REnd);
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
PosPtr TkEnd = consumeName(SepEnd, REnd);
return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd);
if (TkStart == REnd) {
if (SepEnd)
return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);
return makeState(PS_InRootName, TkStart + 1, RStart + 1);
}
TkStart = consumeName(SepEnd, REnd);
return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1);
}
case PS_InRootDir:
// return makeState(PS_InRootName, Path.data(), RStart + 1);
return makeState(PS_InRootName, Path.data(), RStart + 1);
case PS_InRootName:
case PS_BeforeBegin:
_LIBCPP_UNREACHABLE();
Expand Down Expand Up @@ -284,7 +305,7 @@ struct PathParser {
}

PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
if (P == End || !isSeparator(*P))
if (P == nullptr || P == End || !isSeparator(*P))
return nullptr;
const int Inc = P < End ? 1 : -1;
P += Inc;
Expand All @@ -293,15 +314,72 @@ struct PathParser {
return P;
}

// Consume exactly N separators, or return nullptr.
PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept {
PosPtr Ret = consumeSeparator(P, End);
if (Ret == nullptr)
return nullptr;
if (P < End) {
if (Ret == P + N)
return Ret;
} else {
if (Ret == P - N)
return Ret;
}
return nullptr;
}

PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
if (P == End || isSeparator(*P))
PosPtr Start = P;
if (P == nullptr || P == End || isSeparator(*P))
return nullptr;
const int Inc = P < End ? 1 : -1;
P += Inc;
while (P != End && !isSeparator(*P))
P += Inc;
if (P == End && Inc < 0) {
// Iterating backwards and consumed all the rest of the input.
// Check if the start of the string would have been considered
// a root name.
PosPtr RootEnd = consumeRootName(End + 1, Start);
if (RootEnd)
return RootEnd - 1;
}
return P;
}

PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept {
if (P == End)
return nullptr;
if (P < End) {
if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':')
return nullptr;
return P + 2;
} else {
if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':')
return nullptr;
return P - 2;
}
}

PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept {
if (P == End)
return nullptr;
if (P < End)
return consumeName(consumeNSeparators(P, End, 2), End);
else
return consumeNSeparators(consumeName(P, End), End, 2);
}

PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept {
#if defined(_LIBCPP_WIN32API)
if (PosPtr Ret = consumeDriveLetter(P, End))
return Ret;
if (PosPtr Ret = consumeNetworkRoot(P, End))
return Ret;
#endif
return nullptr;
}
};

string_view_pair separate_filename(string_view_t const& s) {
Expand Down

0 comments on commit 929f0bc

Please sign in to comment.