Commit 162c996b19398ab1fb5953318f25da8335380f4a

Edward Thomson 2022-01-25T13:43:02

oid: add git_oid_fmt_substr Tidy up `nfmt` / `pathfmt`.

diff --git a/src/libgit2/oid.c b/src/libgit2/oid.c
index d3284bd..7521dd2 100644
--- a/src/libgit2/oid.c
+++ b/src/libgit2/oid.c
@@ -22,8 +22,6 @@ const git_oid git_oid__empty_tree_sha1 =
 	  { 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
 	    0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }};
 
-static char to_hex[] = "0123456789abcdef";
-
 static int oid_error_invalid(const char *msg)
 {
 	git_error_set(GIT_ERROR_INVALID, "unable to parse OID - %s", msg);
@@ -75,16 +73,9 @@ int git_oid_fromstr(git_oid *out, const char *str, git_oid_t type)
 	return git_oid_fromstrn(out, str, git_oid_hexsize(type), type);
 }
 
-GIT_INLINE(char) *fmt_one(char *str, unsigned int val)
-{
-	*str++ = to_hex[val >> 4];
-	*str++ = to_hex[val & 0xf];
-	return str;
-}
-
 int git_oid_nfmt(char *str, size_t n, const git_oid *oid)
 {
-	size_t hex_size, i, max_i;
+	size_t hex_size;
 
 	if (!oid) {
 		memset(str, 0, n);
@@ -99,14 +90,7 @@ int git_oid_nfmt(char *str, size_t n, const git_oid *oid)
 		n = hex_size;
 	}
 
-	max_i = n / 2;
-
-	for (i = 0; i < max_i; i++)
-		str = fmt_one(str, oid->id[i]);
-
-	if (n & 1)
-		*str++ = to_hex[oid->id[i] >> 4];
-
+	git_oid_fmt_substr(str, oid, 0, n);
 	return 0;
 }
 
@@ -117,16 +101,14 @@ int git_oid_fmt(char *str, const git_oid *oid)
 
 int git_oid_pathfmt(char *str, const git_oid *oid)
 {
-	size_t size, i;
+	size_t hex_size;
 
-	if (!(size = git_oid_size(oid->type)))
+	if (!(hex_size = git_oid_hexsize(oid->type)))
 		return oid_error_invalid("unknown type");
 
-	str = fmt_one(str, oid->id[0]);
-	*str++ = '/';
-	for (i = 1; i < size; i++)
-		str = fmt_one(str, oid->id[i]);
-
+	git_oid_fmt_substr(str, oid, 0, 2);
+	str[2] = '/';
+	git_oid_fmt_substr(&str[3], oid, 2, (hex_size - 2));
 	return 0;
 }
 
diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h
index ede9a16..64b6796 100644
--- a/src/libgit2/oid.h
+++ b/src/libgit2/oid.h
@@ -64,6 +64,35 @@ GIT_INLINE(git_hash_algorithm_t) git_oid_algorithm(git_oid_t type)
  */
 char *git_oid_allocfmt(const git_oid *id);
 
+/**
+ * Format the requested nibbles of an object id.
+ *
+ * @param str the string to write into
+ * @param oid the oid structure to format
+ * @param start the starting number of nibbles
+ * @param count the number of nibbles to format
+ */
+GIT_INLINE(void) git_oid_fmt_substr(
+	char *str,
+	const git_oid *oid,
+	size_t start,
+	size_t count)
+{
+	static char hex[] = "0123456789abcdef";
+	size_t i, end = start + count, min = start / 2, max = end / 2;
+
+	if (start & 1)
+		*str++ = hex[oid->id[min++] & 0x0f];
+
+	for (i = min; i < max; i++) {
+		*str++ = hex[oid->id[i] >> 4];
+		*str++ = hex[oid->id[i] & 0x0f];
+	}
+
+	if (end & 1)
+		*str++ = hex[oid->id[i] >> 4];
+}
+
 GIT_INLINE(int) git_oid_raw_ncmp(
 	const unsigned char *sha1,
 	const unsigned char *sha2,
diff --git a/tests/libgit2/core/oid.c b/tests/libgit2/core/oid.c
index ab00db0..f17054d 100644
--- a/tests/libgit2/core/oid.c
+++ b/tests/libgit2/core/oid.c
@@ -151,3 +151,28 @@ void test_core_oid__is_hexstr(void)
 	cl_assert(!git_oid__is_hexstr("zeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", GIT_OID_SHA1));
 	cl_assert(!git_oid__is_hexstr("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef1", GIT_OID_SHA1));
 }
+
+void test_core_oid__fmt_substr_sha1(void)
+{
+	char buf[GIT_OID_MAX_HEXSIZE];
+
+	memset(buf, 0, GIT_OID_MAX_HEXSIZE);
+	git_oid_fmt_substr(buf, &id_sha1, 0, 40);
+	cl_assert_equal_s(buf, str_oid_sha1);
+
+	memset(buf, 0, GIT_OID_MAX_HEXSIZE);
+	git_oid_fmt_substr(buf, &id_sha1, 0, 18);
+	cl_assert_equal_s(buf, str_oid_sha1_p);
+
+	memset(buf, 0, GIT_OID_MAX_HEXSIZE);
+	git_oid_fmt_substr(buf, &id_sha1, 0, 5);
+	cl_assert_equal_s(buf, "ae90f");
+
+	memset(buf, 0, GIT_OID_MAX_HEXSIZE);
+	git_oid_fmt_substr(buf, &id_sha1, 5, 5);
+	cl_assert_equal_s(buf, "12eea");
+
+	memset(buf, 0, GIT_OID_MAX_HEXSIZE);
+	git_oid_fmt_substr(buf, &id_sha1, 5, 6);
+	cl_assert_equal_s(buf, "12eea6");
+}