return std::string(without_ext).append(new_ext.data(), new_ext.length());
}
+size_t
+common_dir_prefix_length(string_view dir, string_view path)
+{
+ if (dir.empty() || path.empty() || dir == "/" || path == "/") {
+ return 0;
+ }
+
+ const size_t limit = std::min(dir.length(), path.length());
+ size_t i = 0;
+
+ while (i < limit && dir[i] == path[i]) {
+ ++i;
+ }
+
+ if ((i == dir.length() && i == path.length())
+ || (i == dir.length() && path[i] == '/')
+ || (i == path.length() && dir[i] == '/')) {
+ return i;
+ }
+
+ do {
+ --i;
+ } while (i > 0 && i != string_view::npos && dir[i] != '/' && path[i] != '/');
+
+ return i;
+}
+
bool
create_dir(string_view dir)
{
std::string change_extension(nonstd::string_view path,
nonstd::string_view new_ext);
+// Compute the length of the longest directory path that is common to paths
+// `dir` (a directory) and `path` (any path).
+size_t common_dir_prefix_length(nonstd::string_view dir,
+ nonstd::string_view path);
+
// Create a directory if needed, including its parents if needed.
//
// Returns true if the directory exists or could be created, otherwise false.
#endif
}
-// Compute the length of the longest directory path that is common to two
-// paths. s1 is assumed to be the path to a directory.
-size_t
-common_dir_prefix_length(const char* s1, const char* s2)
-{
- const char* p1 = s1;
- const char* p2 = s2;
-
- while (*p1 && *p2 && *p1 == *p2) {
- ++p1;
- ++p2;
- }
- while ((*p1 && *p1 != '/') || (*p2 && *p2 != '/')) {
- p1--;
- p2--;
- }
- if (!*p1 && !*p2 && p2 == s2 + 1) {
- // Special case for s1 and s2 both being "/".
- return 0;
- }
- return p1 - s1;
-}
-
// Compute a relative path from from (an absolute path to a directory) to to (a
// path). Assumes that both from and to are well-formed and canonical. Caller
// frees.
#endif
result = x_strdup("");
- common_prefix_len = common_dir_prefix_length(from, to);
+ common_prefix_len = Util::common_dir_prefix_length(from, to);
if (common_prefix_len > 0 || !str_eq(from, "/")) {
const char* p;
for (p = from + common_prefix_len; *p; p++) {
FILE* create_tmp_file(char** fname, const char* mode);
const char* get_home_directory();
bool same_executable_name(const char* s1, const char* s2);
-size_t common_dir_prefix_length(const char* s1, const char* s2);
char* get_relative_path(const char* from, const char* to);
bool is_full_path(const char* path);
void update_mtime(const char* path);
CHECK(Util::change_extension("foo.bar.txt", ".o") == "foo.bar.o");
}
+TEST_CASE("Util::common_dir_prefix_length")
+{
+ CHECK(Util::common_dir_prefix_length("", "") == 0);
+ CHECK(Util::common_dir_prefix_length("/", "") == 0);
+ CHECK(Util::common_dir_prefix_length("", "/") == 0);
+ CHECK(Util::common_dir_prefix_length("/", "/") == 0);
+ CHECK(Util::common_dir_prefix_length("/", "/b") == 0);
+ CHECK(Util::common_dir_prefix_length("/a", "/") == 0);
+ CHECK(Util::common_dir_prefix_length("/a", "/b") == 0);
+ CHECK(Util::common_dir_prefix_length("/a", "/a") == 2);
+ CHECK(Util::common_dir_prefix_length("/a", "/a/b") == 2);
+ CHECK(Util::common_dir_prefix_length("/a/b", "/a") == 2);
+ CHECK(Util::common_dir_prefix_length("/a/b", "/a/c") == 2);
+ CHECK(Util::common_dir_prefix_length("/a/b", "/a/b") == 4);
+ CHECK(Util::common_dir_prefix_length("/a/bc", "/a/b") == 2);
+ CHECK(Util::common_dir_prefix_length("/a/b", "/a/bc") == 2);
+}
+
TEST_CASE("Util::create_dir")
{
CHECK(Util::create_dir("/"));
CHECK_STR_EQ_FREE2("dir1/dir2", x_dirname("dir1/dir2/"));
}
-TEST(common_dir_prefix_length)
-{
- CHECK_INT_EQ(0, common_dir_prefix_length("", ""));
- CHECK_INT_EQ(0, common_dir_prefix_length("/", "/"));
- CHECK_INT_EQ(0, common_dir_prefix_length("/", "/b"));
- CHECK_INT_EQ(0, common_dir_prefix_length("/a", "/b"));
- CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a"));
- CHECK_INT_EQ(2, common_dir_prefix_length("/a", "/a/b"));
- CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/c"));
- CHECK_INT_EQ(4, common_dir_prefix_length("/a/b", "/a/b"));
- CHECK_INT_EQ(2, common_dir_prefix_length("/a/bc", "/a/b"));
- CHECK_INT_EQ(2, common_dir_prefix_length("/a/b", "/a/bc"));
-}
-
TEST(get_relative_path)
{
#ifdef _WIN32