From eaab86a5c3a02adbc9b9f1d9346a433698b17b8d Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Wed, 19 Feb 2020 19:18:01 +0100 Subject: [PATCH] C++-ify common_dir_prefix_length --- src/Util.cpp | 27 +++++++++++++++++++++++++++ src/Util.hpp | 5 +++++ src/legacy_util.cpp | 25 +------------------------ src/legacy_util.hpp | 1 - unittest/test_Util.cpp | 18 ++++++++++++++++++ unittest/test_legacy_util.cpp | 14 -------------- 6 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/Util.cpp b/src/Util.cpp index b75e3d47e..e3bf60c36 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -112,6 +112,33 @@ change_extension(string_view path, string_view new_ext) return std::string(without_ext).append(new_ext.data(), new_ext.length()); } +size_t +common_dir_prefix_length(string_view dir, string_view path) +{ + if (dir.empty() || path.empty() || dir == "/" || path == "/") { + return 0; + } + + const size_t limit = std::min(dir.length(), path.length()); + size_t i = 0; + + while (i < limit && dir[i] == path[i]) { + ++i; + } + + if ((i == dir.length() && i == path.length()) + || (i == dir.length() && path[i] == '/') + || (i == path.length() && dir[i] == '/')) { + return i; + } + + do { + --i; + } while (i > 0 && i != string_view::npos && dir[i] != '/' && path[i] != '/'); + + return i; +} + bool create_dir(string_view dir) { diff --git a/src/Util.hpp b/src/Util.hpp index 2797f914b..3f6b3be45 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -77,6 +77,11 @@ big_endian_to_int(const uint8_t* buffer, uint8_t& value) std::string change_extension(nonstd::string_view path, nonstd::string_view new_ext); +// Compute the length of the longest directory path that is common to paths +// `dir` (a directory) and `path` (any path). +size_t common_dir_prefix_length(nonstd::string_view dir, + nonstd::string_view path); + // Create a directory if needed, including its parents if needed. // // Returns true if the directory exists or could be created, otherwise false. diff --git a/src/legacy_util.cpp b/src/legacy_util.cpp index f7c43b324..1b89a1805 100644 --- a/src/legacy_util.cpp +++ b/src/legacy_util.cpp @@ -708,29 +708,6 @@ same_executable_name(const char* s1, const char* s2) #endif } -// Compute the length of the longest directory path that is common to two -// paths. s1 is assumed to be the path to a directory. -size_t -common_dir_prefix_length(const char* s1, const char* s2) -{ - const char* p1 = s1; - const char* p2 = s2; - - while (*p1 && *p2 && *p1 == *p2) { - ++p1; - ++p2; - } - while ((*p1 && *p1 != '/') || (*p2 && *p2 != '/')) { - p1--; - p2--; - } - if (!*p1 && !*p2 && p2 == s2 + 1) { - // Special case for s1 and s2 both being "/". - return 0; - } - return p1 - s1; -} - // Compute a relative path from from (an absolute path to a directory) to to (a // path). Assumes that both from and to are well-formed and canonical. Caller // frees. @@ -762,7 +739,7 @@ get_relative_path(const char* from, const char* to) #endif result = x_strdup(""); - common_prefix_len = common_dir_prefix_length(from, to); + common_prefix_len = Util::common_dir_prefix_length(from, to); if (common_prefix_len > 0 || !str_eq(from, "/")) { const char* p; for (p = from + common_prefix_len; *p; p++) { diff --git a/src/legacy_util.hpp b/src/legacy_util.hpp index 9acd09781..329d26ffd 100644 --- a/src/legacy_util.hpp +++ b/src/legacy_util.hpp @@ -54,7 +54,6 @@ int create_tmp_fd(char** fname); FILE* create_tmp_file(char** fname, const char* mode); const char* get_home_directory(); bool same_executable_name(const char* s1, const char* s2); -size_t common_dir_prefix_length(const char* s1, const char* s2); char* get_relative_path(const char* from, const char* to); bool is_full_path(const char* path); void update_mtime(const char* path); diff --git a/unittest/test_Util.cpp b/unittest/test_Util.cpp index c6de9eda9..97e8cc5bf 100644 --- a/unittest/test_Util.cpp +++ b/unittest/test_Util.cpp @@ -86,6 +86,24 @@ TEST_CASE("Util::change_extension") CHECK(Util::change_extension("foo.bar.txt", ".o") == "foo.bar.o"); } +TEST_CASE("Util::common_dir_prefix_length") +{ + CHECK(Util::common_dir_prefix_length("", "") == 0); + CHECK(Util::common_dir_prefix_length("/", "") == 0); + CHECK(Util::common_dir_prefix_length("", "/") == 0); + CHECK(Util::common_dir_prefix_length("/", "/") == 0); + CHECK(Util::common_dir_prefix_length("/", "/b") == 0); + CHECK(Util::common_dir_prefix_length("/a", "/") == 0); + CHECK(Util::common_dir_prefix_length("/a", "/b") == 0); + CHECK(Util::common_dir_prefix_length("/a", "/a") == 2); + CHECK(Util::common_dir_prefix_length("/a", "/a/b") == 2); + CHECK(Util::common_dir_prefix_length("/a/b", "/a") == 2); + CHECK(Util::common_dir_prefix_length("/a/b", "/a/c") == 2); + CHECK(Util::common_dir_prefix_length("/a/b", "/a/b") == 4); + CHECK(Util::common_dir_prefix_length("/a/bc", "/a/b") == 2); + CHECK(Util::common_dir_prefix_length("/a/b", "/a/bc") == 2); +} + TEST_CASE("Util::create_dir") { CHECK(Util::create_dir("/")); diff --git a/unittest/test_legacy_util.cpp b/unittest/test_legacy_util.cpp index dad59f16b..3dc7338ba 100644 --- a/unittest/test_legacy_util.cpp +++ b/unittest/test_legacy_util.cpp @@ -35,20 +35,6 @@ TEST(x_dirname) CHECK_STR_EQ_FREE2("dir1/dir2", x_dirname("dir1/dir2/")); } -TEST(common_dir_prefix_length) -{ - CHECK_INT_EQ(0, common_dir_prefix_length("", "")); - CHECK_INT_EQ(0, common_dir_prefix_length("/", "/")); - CHECK_INT_EQ(0, common_dir_prefix_length("/", "/b")); - CHECK_INT_EQ(0, common_dir_prefix_length("/a", "/b")); - CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a")); - CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a/b")); - CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/c")); - CHECK_INT_EQ(4, common_dir_prefix_length("/a/b", "/a/b")); - CHECK_INT_EQ(2, common_dir_prefix_length("/a/bc", "/a/b")); - CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/bc")); -} - TEST(get_relative_path) { #ifdef _WIN32 -- 2.47.2