summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2015-01-16 18:33:23 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2015-01-16 18:49:59 -0500
commitfc478d2d01b52c5d82568291109cfc4f7d31843d (patch)
treef9f38f95936cf0547bbf7e146b05d913d4a87037
parentaf769f485648e9f01630a5f901bb22ac043c8f4c (diff)
downloadlibgit2-fc478d2d01b52c5d82568291109cfc4f7d31843d.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.c2
-rw-r--r--src/path.c27
-rw-r--r--src/path.h20
-rw-r--r--tests/path/core.c47
4 files changed, 81 insertions, 15 deletions
diff --git a/src/checkout.c b/src/checkout.c
index da8c1b6a9..a59919de5 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1044,7 +1044,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 9f6970b7f..12f7bc6a8 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 444337b32..bb692cff4 100644
--- a/src/path.h
+++ b/src/path.h
@@ -377,21 +377,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 8a29004ce..ff9d29883 100644
--- a/tests/path/core.c
+++ b/tests/path/core.c
@@ -239,3 +239,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);
+}