diff --git a/src/filesystem.cc b/src/filesystem.cc index 0ae294e..2b523b1 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -211,6 +211,28 @@ boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem:: return canonical_path; } +boost::filesystem::path filesystem::get_normal_path(const boost::filesystem::path &path) noexcept { + boost::filesystem::path normal_path; + + for(auto &e: path) { + if(e==".") + continue; + else if(e=="..") { + auto parent_path=normal_path.parent_path(); + if(!parent_path.empty()) + normal_path=parent_path; + else + normal_path/=e; + } + else if(e.empty()) + continue; + else + normal_path/=e; + } + + return normal_path; +} + boost::filesystem::path filesystem::get_relative_path(const boost::filesystem::path &path, const boost::filesystem::path &base) noexcept { boost::filesystem::path relative_path; diff --git a/src/filesystem.h b/src/filesystem.h index bc4f694..dde58a2 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -34,6 +34,9 @@ public: ///Attempts to get canonical path, if not, return the path parameter static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path) noexcept; + /// Return path with dot, dot-dot and directory separator elements removed + static boost::filesystem::path get_normal_path(const boost::filesystem::path &path) noexcept; + ///Returns empty path on failure static boost::filesystem::path get_relative_path(const boost::filesystem::path &path, const boost::filesystem::path &base) noexcept; }; diff --git a/tests/filesystem_test.cc b/tests/filesystem_test.cc index 02571c6..91571bc 100644 --- a/tests/filesystem_test.cc +++ b/tests/filesystem_test.cc @@ -1,5 +1,6 @@ #include "filesystem.h" #include +#include int main() { { @@ -24,11 +25,24 @@ int main() { g_assert(!filesystem::file_in_path(boost::filesystem::canonical(tests_path/".."/"CMakeLists.txt"), tests_path)); } + auto license_file=boost::filesystem::canonical(tests_path/".."/"LICENSE"); { - auto license_file=boost::filesystem::canonical(tests_path/".."/"LICENSE"); g_assert(filesystem::find_file_in_path_parents("LICENSE", tests_path)==license_file); } + { + g_assert(filesystem::get_normal_path(tests_path/".."/"LICENSE")==license_file); + g_assert(filesystem::get_normal_path("/foo")=="/foo"); + g_assert(filesystem::get_normal_path("/foo/")=="/foo"); + g_assert(filesystem::get_normal_path("/foo/.")=="/foo"); + g_assert(filesystem::get_normal_path("/foo/./bar/..////")=="/foo"); + g_assert(filesystem::get_normal_path("/foo/.///bar/../")=="/foo"); + g_assert(filesystem::get_normal_path("../foo")=="../foo"); + g_assert(filesystem::get_normal_path("../../foo")=="../../foo"); + g_assert(filesystem::get_normal_path("../././foo")=="../foo"); + g_assert(filesystem::get_normal_path("/../foo")=="/../foo"); + } + { boost::filesystem::path relative_path="filesystem_test.cc"; g_assert(filesystem::get_relative_path(tests_path/relative_path, tests_path)==relative_path);