Commit 1ca7fa94 by Edward Thomson

git_path_join_unrooted: return base len

The documentation for `git_path_join_unrooted` states that the base
length will be returned, so that consumers like checkout know where
to start creating directories instead of always creating directories
at the directory root.
parent bd0e8814
...@@ -1102,7 +1102,7 @@ static int checkout_conflicts_mark_directoryfile( ...@@ -1102,7 +1102,7 @@ static int checkout_conflicts_mark_directoryfile(
goto done; goto done;
} }
prefixed = git_path_equal_or_prefixed(path, entry->path); prefixed = git_path_equal_or_prefixed(path, entry->path, NULL);
if (prefixed == GIT_PATH_EQUAL) if (prefixed == GIT_PATH_EQUAL)
continue; continue;
......
...@@ -263,26 +263,31 @@ int git_path_root(const char *path) ...@@ -263,26 +263,31 @@ int git_path_root(const char *path)
int git_path_join_unrooted( int git_path_join_unrooted(
git_buf *path_out, const char *path, const char *base, ssize_t *root_at) git_buf *path_out, const char *path, const char *base, ssize_t *root_at)
{ {
int error, root; ssize_t root;
assert(path && path_out); assert(path && path_out);
root = git_path_root(path); root = (ssize_t)git_path_root(path);
if (base != NULL && root < 0) { if (base != NULL && root < 0) {
error = git_buf_joinpath(path_out, base, path); if (git_buf_joinpath(path_out, base, path) < 0)
return -1;
if (root_at) root = (ssize_t)strlen(base);
*root_at = (ssize_t)strlen(base); } else {
if (git_buf_sets(path_out, path) < 0)
return -1;
if (root < 0)
root = 0;
else if (base)
git_path_equal_or_prefixed(base, path, &root);
} }
else {
error = git_buf_sets(path_out, path);
if (root_at) if (root_at)
*root_at = (root < 0) ? 0 : (ssize_t)root; *root_at = root;
}
return error; return 0;
} }
int git_path_prettify(git_buf *path_out, const char *path, const char *base) int git_path_prettify(git_buf *path_out, const char *path, const char *base)
......
...@@ -396,21 +396,35 @@ enum { GIT_PATH_NOTEQUAL = 0, GIT_PATH_EQUAL = 1, GIT_PATH_PREFIX = 2 }; ...@@ -396,21 +396,35 @@ enum { GIT_PATH_NOTEQUAL = 0, GIT_PATH_EQUAL = 1, GIT_PATH_PREFIX = 2 };
*/ */
GIT_INLINE(int) git_path_equal_or_prefixed( GIT_INLINE(int) git_path_equal_or_prefixed(
const char *parent, const char *parent,
const char *child) const char *child,
ssize_t *prefixlen)
{ {
const char *p = parent, *c = child; const char *p = parent, *c = child;
int lastslash = 0;
while (*p && *c) { while (*p && *c) {
lastslash = (*p == '/');
if (*p++ != *c++) if (*p++ != *c++)
return GIT_PATH_NOTEQUAL; return GIT_PATH_NOTEQUAL;
} }
if (*p != '\0') if (*p != '\0')
return GIT_PATH_NOTEQUAL; return GIT_PATH_NOTEQUAL;
if (*c == '\0')
if (*c == '\0') {
if (prefixlen)
*prefixlen = p - parent;
return GIT_PATH_EQUAL; return GIT_PATH_EQUAL;
if (*c == '/') }
if (*c == '/' || lastslash) {
if (prefixlen)
*prefixlen = (p - parent) - lastslash;
return GIT_PATH_PREFIX; return GIT_PATH_PREFIX;
}
return GIT_PATH_NOTEQUAL; return GIT_PATH_NOTEQUAL;
} }
......
...@@ -305,3 +305,50 @@ void test_path_core__isvalid_dotgit_with_hfs_ignorables(void) ...@@ -305,3 +305,50 @@ void test_path_core__isvalid_dotgit_with_hfs_ignorables(void)
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", GIT_PATH_REJECT_DOT_GIT_HFS)); cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\x80\xbf", GIT_PATH_REJECT_DOT_GIT_HFS));
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", GIT_PATH_REJECT_DOT_GIT_HFS)); cl_assert_equal_b(true, git_path_isvalid(NULL, ".git\xe2\xab\x81", GIT_PATH_REJECT_DOT_GIT_HFS));
} }
static void test_join_unrooted(
const char *expected_result,
ssize_t expected_rootlen,
const char *path,
const char *base)
{
git_buf result = GIT_BUF_INIT;
ssize_t root_at;
cl_git_pass(git_path_join_unrooted(&result, path, base, &root_at));
cl_assert_equal_s(expected_result, result.ptr);
cl_assert_equal_i(expected_rootlen, root_at);
git_buf_free(&result);
}
void test_path_core__join_unrooted(void)
{
git_buf out = GIT_BUF_INIT;
test_join_unrooted("foo", 0, "foo", NULL);
test_join_unrooted("foo/bar", 0, "foo/bar", NULL);
/* Relative paths have base prepended */
test_join_unrooted("/foo/bar", 4, "bar", "/foo");
test_join_unrooted("/foo/bar/foobar", 4, "bar/foobar", "/foo");
test_join_unrooted("c:/foo/bar/foobar", 6, "bar/foobar", "c:/foo");
test_join_unrooted("c:/foo/bar/foobar", 10, "foobar", "c:/foo/bar");
/* Absolute paths are not prepended with base */
test_join_unrooted("/foo", 0, "/foo", "/asdf");
test_join_unrooted("/foo/bar", 0, "/foo/bar", "/asdf");
/* Drive letter is given as root length on Windows */
test_join_unrooted("c:/foo", 2, "c:/foo", "c:/asdf");
test_join_unrooted("c:/foo/bar", 2, "c:/foo/bar", "c:/asdf");
/* Base is returned when it's provided and is the prefix */
test_join_unrooted("c:/foo/bar/foobar", 6, "c:/foo/bar/foobar", "c:/foo");
test_join_unrooted("c:/foo/bar/foobar", 10, "c:/foo/bar/foobar", "c:/foo/bar");
/* Trailing slash in the base is ignored */
test_join_unrooted("c:/foo/bar/foobar", 6, "c:/foo/bar/foobar", "c:/foo/");
git_buf_free(&out);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment