Commit ba6f86eb2e100ad6f39e70bd52d7144df1b43a1a

Edward Thomson 2016-03-18T17:33:46

Introduce `git_path_common_dirlen`

diff --git a/src/path.c b/src/path.c
index 1fd14fc..4133985 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 875c8cb..f31cacc 100644
--- a/src/path.h
+++ b/src/path.h
@@ -203,6 +203,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.
  *
  * @param path The path to make relative
diff --git a/tests/core/path.c b/tests/core/path.c
index c3e622f..71c6eda 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");
+}