Add routines to convert git_oid to hex strings [sp: Credit for some of this implementation goes to Pieter, I started off a patch he proposed for libgit2 but reworked enough of it that I don't want to blame him for any bugs.] Suggested-by: Pieter de Bie <pdebie@ai.rug.nl> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
diff --git a/src/git/oid.h b/src/git/oid.h
index 9e90ed0..6c1a2d8 100644
--- a/src/git/oid.h
+++ b/src/git/oid.h
@@ -13,11 +13,17 @@
*/
GIT_BEGIN_DECL
+/** Size (in bytes) of a raw/binary oid */
+#define GIT_OID_RAWSZ 20
+
+/** Size (in bytes) of a hex formatted oid */
+#define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2)
+
/** Unique identity of any object (commit, tree, blob, tag). */
typedef struct
{
/** raw binary formatted id */
- unsigned char id[20];
+ unsigned char id[GIT_OID_RAWSZ];
} git_oid;
/**
@@ -41,6 +47,40 @@ GIT_INLINE(void) git_oid_mkraw(git_oid *out, const unsigned char *raw)
}
/**
+ * Format a git_oid into a hex string.
+ * @param str output hex string; must be pointing at the start of
+ * the hex sequence and have at least the number of bytes
+ * needed for an oid encoded in hex (40 bytes). Only the
+ * oid digits are written; a '\0' terminator must be added
+ * by the caller if it is required.
+ * @param oid oid structure to format.
+ */
+GIT_EXTERN(void) git_oid_fmt(char *str, const git_oid *oid);
+
+/**
+ * Format a git_oid into a loose-object path string.
+ * <p>
+ * The resulting string is "aa/...", where "aa" is the first two
+ * hex digitis of the oid and "..." is the remaining 38 digits.
+ *
+ * @param str output hex string; must be pointing at the start of
+ * the hex sequence and have at least the number of bytes
+ * needed for an oid encoded in hex (41 bytes). Only the
+ * oid digits are written; a '\0' terminator must be added
+ * by the caller if it is required.
+ * @param oid oid structure to format.
+ */
+GIT_EXTERN(void) git_oid_pathfmt(char *str, const git_oid *oid);
+
+/**
+ * Format a gid_oid into a newly allocated c-string.
+ * @param oid theoid structure to format
+ * @return the c-string; NULL if memory is exhausted. Caller must
+ * deallocate the string with free().
+ */
+GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *oid);
+
+/**
* Copy an oid from one structure to another.
* @param out oid structure the result is written into.
* @param src oid structure to copy from.
diff --git a/src/oid.c b/src/oid.c
index e235f89..5f34085 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -44,6 +44,7 @@ static signed char from_hex[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */
};
+static char to_hex[] = "0123456789abcdef";
int git_oid_mkstr(git_oid *out, const char *str)
{
@@ -57,3 +58,38 @@ int git_oid_mkstr(git_oid *out, const char *str)
}
return GIT_SUCCESS;
}
+
+static inline char *fmt_one(char *str, unsigned int val)
+{
+ *str++ = to_hex[val >> 4];
+ *str++ = to_hex[val & 0xf];
+ return str;
+}
+
+void git_oid_fmt(char *str, const git_oid *oid)
+{
+ int i;
+
+ for (i = 0; i < sizeof(oid->id); i++)
+ str = fmt_one(str, oid->id[i]);
+}
+
+void git_oid_pathfmt(char *str, const git_oid *oid)
+{
+ int i;
+
+ str = fmt_one(str, oid->id[0]);
+ *str++ = '/';
+ for (i = 1; i < sizeof(oid->id); i++)
+ str = fmt_one(str, oid->id[i]);
+}
+
+char *git_oid_allocfmt(const git_oid *oid)
+{
+ char *str = malloc(GIT_OID_HEXSZ + 1);
+ if (!str)
+ return NULL;
+ git_oid_fmt(str, oid);
+ str[GIT_OID_HEXSZ] = '\0';
+ return str;
+}
diff --git a/tests/t0000-oid.c b/tests/t0000-oid.c
index 6249655..e682310 100644
--- a/tests/t0000-oid.c
+++ b/tests/t0000-oid.c
@@ -1,6 +1,14 @@
#include "test_lib.h"
#include <git/oid.h>
+BEGIN_TEST(oid_szs)
+ git_oid out;
+ must_be_true(20 == GIT_OID_RAWSZ);
+ must_be_true(40 == GIT_OID_HEXSZ);
+ must_be_true(sizeof(out) == GIT_OID_RAWSZ);
+ must_be_true(sizeof(out.id) == GIT_OID_RAWSZ);
+END_TEST
+
BEGIN_TEST(empty_string)
git_oid out;
must_fail(git_oid_mkstr(&out, ""));
@@ -150,3 +158,51 @@ BEGIN_TEST(cmp_oid_gt)
git_oid_mkraw(&b, b_in);
must_be_true(git_oid_cmp(&a, &b) > 0);
END_TEST
+
+BEGIN_TEST(cmp_oid_fmt)
+ const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+ git_oid in;
+ char out[GIT_OID_HEXSZ + 1];
+
+ must_pass(git_oid_mkstr(&in, exp));
+
+ /* Format doesn't touch the last byte */
+ out[GIT_OID_HEXSZ] = 'Z';
+ git_oid_fmt(out, &in);
+ must_be_true(out[GIT_OID_HEXSZ] == 'Z');
+
+ /* Format produced the right result */
+ out[GIT_OID_HEXSZ] = '\0';
+ must_pass(strcmp(exp, out));
+END_TEST
+
+BEGIN_TEST(cmp_oid_allocfmt)
+ const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+ git_oid in;
+ char *out;
+
+ must_pass(git_oid_mkstr(&in, exp));
+
+ out = git_oid_allocfmt(&in);
+ must_be_true(out);
+ must_pass(strcmp(exp, out));
+END_TEST
+
+BEGIN_TEST(cmp_oid_pathfmt)
+ const char *exp1 = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+ const char *exp2 = "16/a0123456789abcdef4b775213c23a8bd74f5e0";
+ git_oid in;
+ char out[GIT_OID_HEXSZ + 2];
+
+ must_pass(git_oid_mkstr(&in, exp1));
+
+ /* Format doesn't touch the last byte */
+ out[GIT_OID_HEXSZ + 1] = 'Z';
+ git_oid_pathfmt(out, &in);
+ must_be_true(out[GIT_OID_HEXSZ + 1] == 'Z');
+
+ /* Format produced the right result */
+ out[GIT_OID_HEXSZ + 1] = '\0';
+ must_pass(strcmp(exp2, out));
+END_TEST
+