Skip to content

Commit

Permalink
Add get_relative_path()
Browse files Browse the repository at this point in the history
We can use this function to get the relative path between a base path
and a filename

Related to aseprite/aseprite#4389
  • Loading branch information
gui-marc authored and dacap committed Jun 18, 2024
1 parent 5b8ffbf commit 36abe03
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
34 changes: 34 additions & 0 deletions base/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,40 @@ 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<std::string> baseDirs;
split_string(base_path, baseDirs, "/\\");

std::vector<std::string> 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)
relativePath = base::join_path(relativePath, "..");

// Append the remaining part of 'toPath'
for (auto it = itTo; it != toParts.end(); ++it)
relativePath = base::join_path(relativePath, *it);

return relativePath;
}

std::string join_path(const std::string& path, const std::string& file)
{
std::string result(path);
Expand Down
3 changes: 3 additions & 0 deletions base/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
17 changes: 17 additions & 0 deletions base/fs_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 36abe03

Please sign in to comment.