Skip to content

Commit 7d3359d

Browse files
committed
add CombinePaths functions
1 parent d9160f8 commit 7d3359d

3 files changed

Lines changed: 94 additions & 0 deletions

File tree

beam_utils/include/beam_utils/filesystem.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,31 @@ bool HasExtension(const std::string& input, const std::string& extension);
4848
*/
4949
std::string LibbeamRoot();
5050

51+
/**
52+
* @brief remove duplicate file separators in a string filepath
53+
*
54+
* @param path
55+
* @return std::string
56+
*/
57+
std::string RemoveDuplicateFileSeparators(const std::string& path);
58+
59+
/**
60+
* @brief safe way (for all OSs) of combining paths. Uses std::filesystem
61+
*
62+
* @param path1 first path to add
63+
* @param path2 second path to add
64+
* @return std::string
65+
*/
66+
std::string CombinePaths(const std::string& path1, const std::string& path2);
67+
68+
/**
69+
* @brief safe way (for all OSs) of combining paths. Uses std::filesystem
70+
*
71+
* @param paths vector of paths to combine in order
72+
* @return std::string
73+
*/
74+
std::string CombinePaths(const std::vector<std::string>& paths);
75+
5176
/**
5277
* @brief get a vector of absolute paths to files in a directory
5378
* @param directory absolute path to directory to search in

beam_utils/src/filesystem.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,42 @@ std::string LibbeamRoot() {
3636
return root_location;
3737
}
3838

39+
std::string CleanupPath(const std::string& path) {
40+
namespace fs = boost::filesystem;
41+
if (path.size() < 3) { return path; }
42+
std::string return_path;
43+
for (uint32_t i = 0; i < path.size() - 1; i++) {
44+
return_path += path[i];
45+
if (path[i] == fs::path::preferred_separator &&
46+
path[i + 1] == fs::path::preferred_separator) {
47+
i++;
48+
}
49+
}
50+
51+
// add last character only if not a file separator
52+
if (path[path.size() - 1] != fs::path::preferred_separator) {
53+
return_path += path[path.size() - 1];
54+
}
55+
return return_path;
56+
}
57+
std::string CombinePaths(const std::string& path1, const std::string& path2) {
58+
namespace fs = boost::filesystem;
59+
fs::path p1(path1);
60+
fs::path p2(path2);
61+
fs::path p = p1 / p2;
62+
return CleanupPath(p.string());
63+
}
64+
65+
std::string CombinePaths(const std::vector<std::string>& paths) {
66+
namespace fs = boost::filesystem;
67+
fs::path p;
68+
for (uint32_t i = 0; i < paths.size(); i++) {
69+
fs::path p_add(paths[i]);
70+
p = p / p_add;
71+
}
72+
return CleanupPath(p.string());
73+
}
74+
3975
std::vector<std::string> GetFiles(const std::string& directory,
4076
const std::string& extension,
4177
bool recursive) {

beam_utils/tests/filesystem_test.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <fstream>
22
#include <iostream>
3+
#include <sys/utsname.h>
34

45
#include <boost/filesystem.hpp>
56
#include <catch2/catch.hpp>
@@ -99,6 +100,38 @@ TEST_CASE("LibbeamRoot tests", "[filesystem.hpp]") {
99100
REQUIRE(this_file_true_location == this_file_expected_location);
100101
}
101102

103+
TEST_CASE("CombinePaths tests", "[filesystem.hpp]") {
104+
std::string p_root1 = "/home/nick";
105+
std::string p_root2 = "/home/nick/";
106+
std::string p_add1 = "/test.cpp";
107+
std::string p_add2 = "test.cpp";
108+
std::string p_add3 = "test";
109+
std::string p_add4 = "/test/";
110+
111+
struct utsname os_name;
112+
uname(&os_name);
113+
if (std::string(os_name.sysname) == "Linux") {
114+
std::cout << "Linux OS detected, running CombinePaths tests\n";
115+
REQUIRE(beam::CombinePaths(p_root1, p_add1) == "/home/nick/test.cpp");
116+
REQUIRE(beam::CombinePaths(p_root1, p_add2) == "/home/nick/test.cpp");
117+
REQUIRE(beam::CombinePaths(p_root2, p_add1) == "/home/nick/test.cpp");
118+
REQUIRE(beam::CombinePaths(p_root2, p_add2) == "/home/nick/test.cpp");
119+
REQUIRE(beam::CombinePaths(p_root1, p_add3) == "/home/nick/test");
120+
REQUIRE(beam::CombinePaths(p_root1, p_add4) == "/home/nick/test");
121+
122+
std::string combined1 = beam::CombinePaths(p_root1, p_add4);
123+
REQUIRE(beam::CombinePaths(combined1, p_add1) ==
124+
"/home/nick/test/test.cpp");
125+
REQUIRE(beam::CombinePaths(std::vector<std::string>{
126+
p_root1, p_add3, p_add1}) == "/home/nick/test/test.cpp");
127+
REQUIRE(beam::CombinePaths(std::vector<std::string>{p_root1, p_add1}) ==
128+
"/home/nick/test.cpp");
129+
} else {
130+
std::cout << "Cannot run CombinePaths tests which only work for Linux\n";
131+
REQUIRE(true);
132+
}
133+
}
134+
102135
TEST_CASE("StringToNumericValues", "[filesystem.hpp]") {
103136
std::string deliminator_1{","};
104137
std::string deliminator_2{" "};

0 commit comments

Comments
 (0)