From b1740bf7eb895f07167d49921f72146f320815d6 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 5 Feb 2025 14:56:45 +0300 Subject: [PATCH] update io::path::normalized() --- src/io/path.cpp | 72 +++++++++++++++++++++++++++++++++++++----------- src/io/path.hpp | 8 +----- test/io/path.cpp | 6 ++++ 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/io/path.cpp b/src/io/path.cpp index 08333c34..4dfdfa61 100644 --- a/src/io/path.cpp +++ b/src/io/path.cpp @@ -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 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 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; } diff --git a/src/io/path.hpp b/src/io/path.hpp index 4c35d824..5abc110e 100644 --- a/src/io/path.hpp +++ b/src/io/path.hpp @@ -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; diff --git a/test/io/path.cpp b/test/io/path.cpp index 86d5efe3..100d10b9 100644 --- a/test/io/path.cpp +++ b/test/io/path.cpp @@ -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")); +}