diff options
author | Edward Thomson <ethomson@microsoft.com> | 2015-01-12 15:48:53 -0600 |
---|---|---|
committer | Edward Thomson <ethomson@microsoft.com> | 2015-01-20 17:12:35 -0600 |
commit | 1fbfcdfcd0f3b87e95cea15b3c90808ccd5f9a79 (patch) | |
tree | d09ceb1287f8661fc04f434ce469835a4d1c1a48 | |
parent | 1d50b3649d578f12918b7996ad7b98a438bc0616 (diff) | |
download | libgit2-1fbfcdfcd0f3b87e95cea15b3c90808ccd5f9a79.tar.gz |
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.
-rw-r--r-- | src/checkout.c | 2 | ||||
-rw-r--r-- | src/path.c | 27 | ||||
-rw-r--r-- | src/path.h | 20 | ||||
-rw-r--r-- | tests/path/core.c | 47 |
4 files changed, 81 insertions, 15 deletions
diff --git a/src/checkout.c b/src/checkout.c index 1074fe6bb..aad17f8b1 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1102,7 +1102,7 @@ static int checkout_conflicts_mark_directoryfile( 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) continue; diff --git a/src/path.c b/src/path.c index 0bad96242..58d71921b 100644 --- a/src/path.c +++ b/src/path.c @@ -263,26 +263,31 @@ int git_path_root(const char *path) int git_path_join_unrooted( git_buf *path_out, const char *path, const char *base, ssize_t *root_at) { - int error, root; + ssize_t root; assert(path && path_out); - root = git_path_root(path); + root = (ssize_t)git_path_root(path); 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_at = (ssize_t)strlen(base); - } - else { - error = git_buf_sets(path_out, path); + root = (ssize_t)strlen(base); + } else { + if (git_buf_sets(path_out, path) < 0) + return -1; - if (root_at) - *root_at = (root < 0) ? 0 : (ssize_t)root; + if (root < 0) + 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) diff --git a/src/path.h b/src/path.h index b753140b2..440b5420c 100644 --- a/src/path.h +++ b/src/path.h @@ -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( const char *parent, - const char *child) + const char *child, + ssize_t *prefixlen) { const char *p = parent, *c = child; + int lastslash = 0; while (*p && *c) { + lastslash = (*p == '/'); + if (*p++ != *c++) return GIT_PATH_NOTEQUAL; } if (*p != '\0') return GIT_PATH_NOTEQUAL; - if (*c == '\0') + + if (*c == '\0') { + if (prefixlen) + *prefixlen = p - parent; + return GIT_PATH_EQUAL; - if (*c == '/') + } + + if (*c == '/' || lastslash) { + if (prefixlen) + *prefixlen = (p - parent) - lastslash; + return GIT_PATH_PREFIX; + } return GIT_PATH_NOTEQUAL; } diff --git a/tests/path/core.c b/tests/path/core.c index 5b110f611..064f1492a 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -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\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); +} |