[Base] Fix canonicalize path for rooted paths.
This commit is contained in:
parent
f83809f7a1
commit
85dbb9d451
|
@ -25,6 +25,12 @@ using utf8_criter = utfcpp::iterator<std::string_view::const_reverse_iterator>;
|
||||||
|
|
||||||
namespace xe::utf8 {
|
namespace xe::utf8 {
|
||||||
|
|
||||||
|
std::string to_string(char32_t c) {
|
||||||
|
std::string result;
|
||||||
|
utfcpp::append(c, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t lower_ascii(const uint32_t c) {
|
uint32_t lower_ascii(const uint32_t c) {
|
||||||
return c >= 'A' && c <= 'Z' ? c + 32 : c;
|
return c >= 'A' && c <= 'Z' ? c + 32 : c;
|
||||||
}
|
}
|
||||||
|
@ -358,6 +364,14 @@ std::string_view::size_type find_first_of_case(const std::string_view haystack,
|
||||||
return std::string_view::npos;
|
return std::string_view::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool starts_with(const std::string_view haystack, char32_t needle) {
|
||||||
|
if (haystack.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto [it, end] = make_citer(haystack);
|
||||||
|
return *it == uint32_t(needle);
|
||||||
|
}
|
||||||
|
|
||||||
bool starts_with(const std::string_view haystack,
|
bool starts_with(const std::string_view haystack,
|
||||||
const std::string_view needle) {
|
const std::string_view needle) {
|
||||||
if (needle.empty()) {
|
if (needle.empty()) {
|
||||||
|
@ -616,36 +630,30 @@ std::string canonicalize_path(const std::string_view path, char32_t sep) {
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto is_rooted = starts_with(path, sep);
|
||||||
|
|
||||||
auto parts = split_path(path);
|
auto parts = split_path(path);
|
||||||
|
for (auto it = parts.begin(); it != parts.end();) {
|
||||||
std::vector<std::vector<std::string_view>::size_type> indices(parts.size());
|
const auto& part = *it;
|
||||||
std::iota(indices.begin(), indices.end(), 0);
|
|
||||||
|
|
||||||
for (auto it = indices.begin(); it != indices.end();) {
|
|
||||||
const auto& part = parts[*it];
|
|
||||||
if (part == ".") {
|
if (part == ".") {
|
||||||
// Potential marker for current directory.
|
// Potential marker for current directory.
|
||||||
it = indices.erase(it);
|
it = parts.erase(it);
|
||||||
} else if (part == "..") {
|
} else if (part == "..") {
|
||||||
// Ensure we don't override the device name.
|
// Ensure we don't override the device name.
|
||||||
if (it != indices.begin()) {
|
if (it != parts.begin()) {
|
||||||
auto prev = std::prev(it);
|
auto prev = std::prev(it);
|
||||||
if (!ends_with(parts[*prev], ":")) {
|
if (!ends_with(*prev, ":")) {
|
||||||
it = indices.erase(prev);
|
it = parts.erase(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = indices.erase(it);
|
it = parts.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result;
|
return !is_rooted ? join_paths(parts, sep)
|
||||||
for (auto index : indices) {
|
: to_string(sep) + join_paths(parts, sep);
|
||||||
result = join_paths(result, parts[index], sep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result == "." || result == ".." ? std::string() : result;
|
|
||||||
} // namespace utf8
|
|
||||||
|
|
||||||
} // namespace xe::utf8
|
} // namespace xe::utf8
|
||||||
|
|
Loading…
Reference in New Issue