Add git_oid_nfmt - a flexible OID formatter I frequently want to the the first N digits of an OID formatted as a string and I'd like it to be efficient. This function makes that easy and I could rewrite the OID formatters in terms of it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
diff --git a/include/git2/oid.h b/include/git2/oid.h
index b20bb22..018cead 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -90,6 +90,17 @@ GIT_EXTERN(void) git_oid_fromraw(git_oid *out, const unsigned char *raw);
GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id);
/**
+ * Format a git_oid into a partial hex string.
+ *
+ * @param out output hex string; you say how many bytes to write.
+ * If the number of bytes is > GIT_OID_HEXSZ, extra bytes
+ * will be zeroed; if not, a '\0' terminator is NOT added.
+ * @param n number of characters to write into out string
+ * @param oid oid structure to format.
+ */
+GIT_EXTERN(void) git_oid_nfmt(char *out, size_t n, const git_oid *id);
+
+/**
* Format a git_oid into a loose-object path string.
*
* The resulting string is "aa/...", where "aa" is the first two
@@ -117,10 +128,12 @@ GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *id);
* Format a git_oid into a buffer as a hex format c-string.
*
* If the buffer is smaller than GIT_OID_HEXSZ+1, then the resulting
- * oid c-string will be truncated to n-1 characters. If there are
- * any input parameter errors (out == NULL, n == 0, oid == NULL),
- * then a pointer to an empty string is returned, so that the return
- * value can always be printed.
+ * oid c-string will be truncated to n-1 characters (but will still be
+ * NUL-byte terminated).
+ *
+ * If there are any input parameter errors (out == NULL, n == 0, oid ==
+ * NULL), then a pointer to an empty string is returned, so that the
+ * return value can always be printed.
*
* @param out the buffer into which the oid string is output.
* @param n the size of the out buffer.
diff --git a/src/oid.c b/src/oid.c
index e74640c..a64bd3b 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -68,12 +68,31 @@ GIT_INLINE(char) *fmt_one(char *str, unsigned int val)
return str;
}
-void git_oid_fmt(char *str, const git_oid *oid)
+void git_oid_nfmt(char *str, size_t n, const git_oid *oid)
{
- size_t i;
+ size_t i, max_i;
+
+ if (!oid) {
+ memset(str, 0, n);
+ return;
+ }
+ if (n > GIT_OID_HEXSZ) {
+ memset(&str[GIT_OID_HEXSZ], 0, n - GIT_OID_HEXSZ);
+ n = GIT_OID_HEXSZ;
+ }
+
+ max_i = n / 2;
- for (i = 0; i < sizeof(oid->id); i++)
+ for (i = 0; i < max_i; i++)
str = fmt_one(str, oid->id[i]);
+
+ if (n & 1)
+ *str++ = to_hex[oid->id[i] >> 4];
+}
+
+void git_oid_fmt(char *str, const git_oid *oid)
+{
+ git_oid_nfmt(str, GIT_OID_HEXSZ, oid);
}
void git_oid_pathfmt(char *str, const git_oid *oid)
@@ -91,31 +110,20 @@ char *git_oid_allocfmt(const git_oid *oid)
char *str = git__malloc(GIT_OID_HEXSZ + 1);
if (!str)
return NULL;
- git_oid_fmt(str, oid);
- str[GIT_OID_HEXSZ] = '\0';
+ git_oid_nfmt(str, GIT_OID_HEXSZ + 1, oid);
return str;
}
char *git_oid_tostr(char *out, size_t n, const git_oid *oid)
{
- char str[GIT_OID_HEXSZ];
-
if (!out || n == 0)
return "";
- n--; /* allow room for terminating NUL */
-
- if (oid == NULL)
- n = 0;
-
- if (n > 0) {
- git_oid_fmt(str, oid);
- if (n > GIT_OID_HEXSZ)
- n = GIT_OID_HEXSZ;
- memcpy(out, str, n);
- }
+ if (n > GIT_OID_HEXSZ + 1)
+ n = GIT_OID_HEXSZ + 1;
- out[n] = '\0';
+ git_oid_nfmt(out, n - 1, oid); /* allow room for terminating NUL */
+ out[n - 1] = '\0';
return out;
}
diff --git a/tests-clar/object/raw/convert.c b/tests-clar/object/raw/convert.c
index 74442c1..86f0d74 100644
--- a/tests-clar/object/raw/convert.c
+++ b/tests-clar/object/raw/convert.c
@@ -73,3 +73,41 @@ void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void)
cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+2) == 'Y');
cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+3) == 'Z');
}
+
+static void check_partial_oid(
+ char *buffer, size_t count, const git_oid *oid, const char *expected)
+{
+ git_oid_nfmt(buffer, count, oid);
+ buffer[count] = '\0';
+ cl_assert_equal_s(expected, buffer);
+}
+
+void test_object_raw_convert__convert_oid_partially(void)
+{
+ const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+ git_oid in;
+ char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */
+ char *str;
+
+ cl_git_pass(git_oid_fromstr(&in, exp));
+
+ git_oid_nfmt(big, sizeof(big), &in);
+ cl_assert_equal_s(exp, big);
+
+ git_oid_nfmt(big, GIT_OID_HEXSZ + 1, &in);
+ cl_assert_equal_s(exp, big);
+
+ check_partial_oid(big, 1, &in, "1");
+ check_partial_oid(big, 2, &in, "16");
+ check_partial_oid(big, 3, &in, "16a");
+ check_partial_oid(big, 4, &in, "16a0");
+ check_partial_oid(big, 5, &in, "16a01");
+
+ check_partial_oid(big, GIT_OID_HEXSZ, &in, exp);
+ check_partial_oid(
+ big, GIT_OID_HEXSZ - 1, &in, "16a0123456789abcdef4b775213c23a8bd74f5e");
+ check_partial_oid(
+ big, GIT_OID_HEXSZ - 2, &in, "16a0123456789abcdef4b775213c23a8bd74f5");
+ check_partial_oid(
+ big, GIT_OID_HEXSZ - 3, &in, "16a0123456789abcdef4b775213c23a8bd74f");
+}