diff --git a/base/fs.cpp b/base/fs.cpp index 5769a87a2..d5e25e741 100644 --- a/base/fs.cpp +++ b/base/fs.cpp @@ -210,6 +210,47 @@ std::string get_file_title_with_path(const std::string& filename) return filename; } +std::string get_relative_path(const std::string& filename, const std::string& base_path) +{ + std::vector baseDirs; + split_string(base_path, baseDirs, "/\\"); + + std::vector toParts; + split_string(filename, toParts, "/\\"); + + // Find the common prefix + auto itFrom = baseDirs.begin(); + auto itTo = toParts.begin(); + + while (itFrom != baseDirs.end() && itTo != toParts.end() && *itFrom == *itTo) { + ++itFrom; + ++itTo; + } + + if (itFrom == baseDirs.begin() && itTo == toParts.begin()) { + // No common prefix + return filename; + } + + // Calculate the number of directories to go up from base path + std::string relativePath; + for (auto it = itFrom; it != baseDirs.end(); ++it) { + std::string upDir(".."); + upDir.push_back(base::path_separator); + relativePath += upDir; + } + + // Append the remaining part of 'toPath' + for (auto it = itTo; it != toParts.end(); ++it) { + relativePath += *it; + if (it + 1 != toParts.end()) { + relativePath.push_back(base::path_separator); + } + } + + return relativePath; +} + std::string join_path(const std::string& path, const std::string& file) { std::string result(path); diff --git a/base/fs.h b/base/fs.h index b4b898790..d031168eb 100644 --- a/base/fs.h +++ b/base/fs.h @@ -77,6 +77,9 @@ namespace base { std::string get_file_title(const std::string& filename); std::string get_file_title_with_path(const std::string& filename); + // Returns the relative path of the given filename from the base_path. + std::string get_relative_path(const std::string& filename, const std::string& base_path); + // Joins two paths or a path and a file name with a path-separator. std::string join_path(const std::string& path, const std::string& file); diff --git a/base/fs_tests.cpp b/base/fs_tests.cpp index 21b261238..e87dd8f1a 100644 --- a/base/fs_tests.cpp +++ b/base/fs_tests.cpp @@ -174,6 +174,23 @@ TEST(FS, GetFileTitleWithPath) EXPECT_EQ("C:\\", get_file_title_with_path("C:\\.cpp")); } +TEST(FS, GetRelativePath) +{ + EXPECT_EQ("C:\\foo\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "D:\\another\\disk")); + +#if LAF_WINDOWS + EXPECT_EQ("bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo")); + EXPECT_EQ("C:\\foo\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "D:\\another\\disk")); + EXPECT_EQ("..\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo\\another")); + EXPECT_EQ("..\\..\\bar\\test.file", get_relative_path("C:\\foo\\bar\\test.file", "C:\\foo\\a\\b")); +#else + EXPECT_EQ("bar/test.file", get_relative_path("C:/foo/bar/test.file", "C:/foo")); + EXPECT_EQ("C:/foo/bar/test.file", get_relative_path("C:/foo/bar/test.file", "D:/another/disk")); + EXPECT_EQ("../bar/test.file", get_relative_path("/foo/bar/test.file", "/foo/another")); + EXPECT_EQ("../../bar/test.file", get_relative_path("/foo/bar/test.file", "/foo/a/b")); +#endif +} + TEST(FS, JoinPath) { std::string sep;