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.
This commit is contained in:
Edward Thomson 2015-01-12 15:48:53 -06:00
parent 1d50b3649d
commit 1fbfcdfcd0
4 changed files with 81 additions and 15 deletions

View File

@ -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;

View File

@ -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)
else { return -1;
error = git_buf_sets(path_out, path);
if (root_at) if (root < 0)
*root_at = (root < 0) ? 0 : (ssize_t)root; root = 0;
else if (base)
git_path_equal_or_prefixed(base, path, &root);
} }
return error; if (root_at)
*root_at = root;
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)

View File

@ -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;
} }

View File

@ -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);
}