diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | include/git2/commit.h | 11 | ||||
-rw-r--r-- | src/commit.c | 55 | ||||
-rw-r--r-- | tests/commit/parse.c | 38 |
4 files changed, 107 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a8e3e18ac..eb7ae842b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,6 +140,9 @@ support for HTTPS connections insead of OpenSSL. * `git_filter_list_contains` will indicate whether a particular filter will be run in the given filter list. +* `git_commit_header_field()` has been added, which allows retrieving + the contents of an arbitrary header field. + ### API removals * `git_remote_save()` and `git_remote_clear_refspecs()` have been diff --git a/include/git2/commit.h b/include/git2/commit.h index fb53a701b..04711c1fa 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -240,6 +240,17 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( unsigned int n); /** + * Get an arbitrary header field + * + * @param out the buffer to fill + * @param commit the commit to look in + * @param field the header field to return + * @return 0 on succeess, GIT_ENOTFOUND if the field does not exist, + * or an error code + */ +GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit, const char *field); + +/** * Create new commit in the repository from a list of `git_object` pointers * * The message will **not** be cleaned up automatically. You can do that diff --git a/src/commit.c b/src/commit.c index ce13bdb85..616f947db 100644 --- a/src/commit.c +++ b/src/commit.c @@ -518,3 +518,58 @@ int git_commit_nth_gen_ancestor( *ancestor = parent; return 0; } + +int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field) +{ + const char *buf = commit->raw_header; + const char *h, *eol; + + git_buf_sanitize(out); + while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') { + h++; + if (git__prefixcmp(h, field)) { + buf = h; + continue; + } + + h += strlen(field); + eol = strchr(h, '\n'); + if (h[0] != ' ') { + buf = h; + continue; + } + if (!eol) + goto malformed; + + h++; /* skip the SP */ + + git_buf_put(out, h, eol - h); + if (git_buf_oom(out)) + goto oom; + + /* If the next line starts with SP, it's multi-line, we must continue */ + while (eol[1] == ' ') { + git_buf_putc(out, '\n'); + h = eol + 2; + eol = strchr(h, '\n'); + if (!eol) + goto malformed; + + git_buf_put(out, h, eol - h); + } + + if (git_buf_oom(out)) + goto oom; + + return 0; + } + + return GIT_ENOTFOUND; + +malformed: + giterr_set(GITERR_OBJECT, "malformed header"); + return -1; +oom: + giterr_set_oom(); + return -1; +} diff --git a/tests/commit/parse.c b/tests/commit/parse.c index fa079f470..388da078a 100644 --- a/tests/commit/parse.c +++ b/tests/commit/parse.c @@ -418,3 +418,41 @@ committer Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\ cl_assert_equal_s(raw_message, git_commit_message_raw(commit)); git_commit__free(commit); } + +void test_commit_parse__arbitrary_field(void) +{ + git_commit *commit; + git_buf buf = GIT_BUF_INIT; + const char *gpgsig = "-----BEGIN PGP SIGNATURE-----\n\ +Version: GnuPG v1.4.12 (Darwin)\n\ +\n\ +iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n\ +o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8\n\ +JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq\n\ +AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq\n\ +SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW\n\ +who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok\n\ +6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG\n\ +cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu\n\ +c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9\n\ +ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J\n\ +7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc\n\ +cpxtDQQMGYFpXK/71stq\n\ +=ozeK\n\ +-----END PGP SIGNATURE-----"; + + cl_git_pass(parse_commit(&commit, passing_commit_cases[4])); + + cl_git_pass(git_commit_header_field(&buf, commit, "parent")); + cl_assert_equal_s("34734e478d6cf50c27c9d69026d93974d052c454", buf.ptr); + git_buf_clear(&buf); + + cl_git_pass(git_commit_header_field(&buf, commit, "gpgsig")); + cl_assert_equal_s(gpgsig, buf.ptr); + + cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "awesomeness")); + cl_git_fail_with(GIT_ENOTFOUND, git_commit_header_field(&buf, commit, "par")); + + git_buf_free(&buf); + git_commit__free(commit); +} |