update io::path::normalized()

This commit is contained in:
MihailRis 2025-02-05 14:56:45 +03:00
parent 596132ebe2
commit b1740bf7eb
3 changed files with 63 additions and 23 deletions

View File

@ -10,29 +10,69 @@ void path::checkValid() const {
}
}
path path::parent() const {
size_t length = str.length();
while (length && str[length-1] == '/') {
length--;
}
size_t slashpos = length;
slashpos = str.rfind('/', slashpos-1);
if (length >= 2 && str.rfind("..") == length - 2) {
return normalized().parent();
}
if (slashpos == std::string::npos) {
return colonPos == std::string::npos ? "" : str.substr(0, colonPos+1);
}
while (slashpos && str[slashpos-1] == '/') {
slashpos--;
}
return str.substr(0, slashpos);
}
path path::normalized() const {
io::path path = pathPart();
std::stack<std::string> parts;
do {
parts.push(path.name());
path.str = path.parent().string();
} while (!path.empty());
while (!parts.empty()) {
const std::string part = parts.top();
parts.pop();
if (part == ".") {
std::stack<io::path> parts;
int64_t pos = 0;
int64_t prev = pos-1;
while (pos < path.str.length()) {
pos = path.str.find('/', pos);
if (pos == std::string::npos) {
parts.push(path.str.substr(prev + 1));
break;
}
if (pos - prev == 0) {
prev = pos;
pos = prev + 1;
continue;
}
if (part == "..") {
throw access_error("entry point reached");
auto token = path.str.substr(prev + 1, pos - (prev + 1));
prev = pos;
if (token == ".") {
continue;
} else if (token == "..") {
if (parts.empty()) {
throw access_error("entry-point reached");
}
parts.pop();
continue;
}
path = path / part;
parts.push(std::move(token));
}
if (path.colonPos != std::string::npos) {
path = path.entryPoint() + ":" + path.string();
bool started = false;
path = "";
while (!parts.empty()) {
const auto& token = parts.top();
if (path.empty()) {
path = token;
} else {
path = token / path;
}
parts.pop();
}
if (colonPos != std::string::npos) {
path = str.substr(0, colonPos+1) + path.string();
}
return path;
}

View File

@ -115,13 +115,7 @@ namespace io {
}
/// @brief Get parent path
path parent() const {
size_t slashpos = str.rfind('/');
if (slashpos == std::string::npos) {
return colonPos == std::string::npos ? "" : str;
}
return str.substr(0, slashpos);
}
path parent() const;
path normalized() const;

View File

@ -12,3 +12,9 @@ TEST(Path, Path) {
EXPECT_EQ(p / "child", "entry_point:path/file.ext/child");
EXPECT_EQ(p.parent(), "entry_point:path");
}
TEST(Path, DotElements) {
io::path p("entry_point:a/b/c/../../d/e/../");
EXPECT_EQ(p.normalized(), "entry_point:a/d");
EXPECT_EQ(io::path("test:a///b//////c/").parent(), io::path("test:a///b"));
}