From 660d59caa9cd6260fbc980e7da15f806d6d53083 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 17 May 2013 16:40:00 -0700 Subject: [PATCH] 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. --- include/git2/oid.h | 21 ++++++++++++--- src/oid.c | 48 +++++++++++++++++++-------------- tests-clar/object/raw/convert.c | 38 ++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/include/git2/oid.h b/include/git2/oid.h index b20bb221a..018cead4a 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -89,6 +89,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. * @@ -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 e74640c57..a64bd3b0a 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_nfmt(char *str, size_t n, const git_oid *oid) +{ + 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 < 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) { - size_t i; - - for (i = 0; i < sizeof(oid->id); i++) - str = fmt_one(str, oid->id[i]); + 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 (n > GIT_OID_HEXSZ + 1) + n = GIT_OID_HEXSZ + 1; - 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); - } - - 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 74442c153..86f0d74a9 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"); +}