diff --git a/src/path.c b/src/path.c index 1fd14fcb9..4133985a4 100644 --- a/src/path.c +++ b/src/path.c @@ -810,6 +810,20 @@ int git_path_cmp( return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0; } +size_t git_path_common_dirlen(const char *one, const char *two) +{ + const char *p, *q, *dirsep = NULL; + + for (p = one, q = two; *p && *q; p++, q++) { + if (*p == '/' && *q == '/') + dirsep = p; + else if (*p != *q) + break; + } + + return dirsep ? (dirsep - one) + 1 : 0; +} + int git_path_make_relative(git_buf *path, const char *parent) { const char *p, *q, *p_dirsep, *q_dirsep; diff --git a/src/path.h b/src/path.h index 875c8cb7e..f31cacc70 100644 --- a/src/path.h +++ b/src/path.h @@ -202,6 +202,18 @@ extern bool git_path_contains(git_buf *dir, const char *item); */ extern bool git_path_contains_dir(git_buf *parent, const char *subdir); +/** + * Determine the common directory length between two paths, including + * the final path separator. For example, given paths 'a/b/c/1.txt + * and 'a/b/c/d/2.txt', the common directory is 'a/b/c/', and this + * will return the length of the string 'a/b/c/', which is 6. + * + * @param one The first path + * @param two The second path + * @return The length of the common directory + */ +extern size_t git_path_common_dirlen(const char *one, const char *two); + /** * Make the path relative to the given parent path. * diff --git a/tests/core/path.c b/tests/core/path.c index c3e622f02..71c6eda58 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -652,3 +652,23 @@ void test_core_path__15_resolve_relative(void) git_buf_free(&buf); } + +#define assert_common_dirlen(i, p, q) \ + cl_assert_equal_i((i), git_path_common_dirlen((p), (q))); + +void test_core_path__16_resolve_relative(void) +{ + assert_common_dirlen(0, "", ""); + assert_common_dirlen(0, "", "bar.txt"); + assert_common_dirlen(0, "foo.txt", "bar.txt"); + assert_common_dirlen(0, "foo.txt", ""); + assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt"); + assert_common_dirlen(0, "foo/bar.txt", "../foo.txt"); + + assert_common_dirlen(1, "/one.txt", "/two.txt"); + assert_common_dirlen(4, "foo/one.txt", "foo/two.txt"); + assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt"); + + assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt"); + assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt"); +}