From 25635c5cfec87df9338a696b17f1f86fa762781e Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sat, 28 Jan 2023 18:46:35 +0200 Subject: [PATCH] utils: add join_paths + tests --- lib/utils/mu-utils-file.cc | 21 +++++++++++++---- lib/utils/mu-utils-file.hh | 47 +++++++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/lib/utils/mu-utils-file.cc b/lib/utils/mu-utils-file.cc index 9bc8c1d6..24d870f1 100644 --- a/lib/utils/mu-utils-file.cc +++ b/lib/utils/mu-utils-file.cc @@ -78,13 +78,13 @@ Mu::play (const std::string& path) argv[0] = program_path->c_str(); argv[1] = path.c_str(); argv[2] = nullptr; - + GError *err{}; if (!g_spawn_async ({}, (gchar**)&argv, {}, G_SPAWN_SEARCH_PATH, maybe_setsid, {}, {}, &err)) return Err(Error::Code::File, &err/*consumes*/, "failed to open '%s' with '%s'", path. c_str(), program_path->c_str()); - + return Ok(); } @@ -109,7 +109,7 @@ Mu::determine_dtype (const std::string& path, bool use_lstat) { int res; struct stat statbuf{}; - + if (use_lstat) res = ::lstat(path.c_str(), &statbuf); else @@ -257,6 +257,17 @@ test_program_in_path(void) g_assert_true(!!program_in_path("ls")); } +static void +test_join_paths() +{ + + assert_equal(join_paths(), ""); + assert_equal(join_paths("a"), "a"); + assert_equal(join_paths("a", "b"), "a/b"); + assert_equal(join_paths("/a/b///c/d//", "e"), "/a/b/c/d/e"); +} + + int main(int argc, char* argv[]) @@ -272,12 +283,12 @@ main(int argc, char* argv[]) test_check_dir_03); g_test_add_func("/utils/check-dir-04", test_check_dir_04); - g_test_add_func("/utils/determine-dtype-with-lstat", test_determine_dtype_with_lstat); - g_test_add_func("/utils/program-in-path", test_program_in_path); + g_test_add_func("/utils/join-paths", + test_join_paths); return g_test_run(); } diff --git a/lib/utils/mu-utils-file.hh b/lib/utils/mu-utils-file.hh index f47ada5a..b9e6d920 100644 --- a/lib/utils/mu-utils-file.hh +++ b/lib/utils/mu-utils-file.hh @@ -24,8 +24,8 @@ #include #include -#include #include +#include namespace Mu { @@ -43,22 +43,22 @@ namespace Mu { */ Result play(const std::string& path); -/** +/** * Find program in PATH - * + * * @param name the name of the program - * + * * @return either the full path to program, or Nothing if not found. - */ + */ Option program_in_path(const std::string& name); - -/** + +/** * Check if the directory has the given attributes - * + * * @param path path to dir * @param readable is it readable? * @param writeable is it writable? - * + * * @return true if is is a directory with given attributes; false otherwise. */ bool check_dir(const std::string& path, bool readable, bool writeable); @@ -72,8 +72,8 @@ bool check_dir(const std::string& path, bool readable, bool writeable); * @return */ std::string canonicalize_filename(const std::string& path, const std::string& relative_to); - -/* + +/* * for OSs with out support for direntry->d_type, like Solaris */ #ifndef DT_UNKNOWN @@ -108,7 +108,7 @@ enum { * * @return DT_REG, DT_DIR, DT_LNK, or DT_UNKNOWN (other values are not supported * currently) - */ + */ uint8_t determine_dtype(const std::string& path, bool use_lstat); @@ -135,7 +135,28 @@ enum struct RuntimePath { * @return the path name */ std::string runtime_path(RuntimePath path, const std::string& muhome=""); +/** + * Join path components into a path (with '/') + * + * @param s a string-convertible value + * @param args 0 or more string-convertible values + * + * @return the path + */ +static inline std::string join_paths() { return {}; } +template +std::string join_paths(S&& s, Args...args) { + static std::string sepa{"/"}; + auto&& str{std::string{std::forward(s)}}; + if (auto&& rest{join_paths(std::forward(args)...)}; !rest.empty()) + str += (sepa + rest); + + static auto rx = Regex::make("//*").value(); + return rx.replace(str, sepa); } -#endif /* MU_UTILS_FILE_HH__ */ + +} // namespace Mu + +#endif /* MU_UTILS_FILE_HH__ */