diff --git a/include/git2/commit.h b/include/git2/commit.h index 84adef596..12646cf58 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -97,12 +97,16 @@ GIT_INLINE(void) git_commit_close(git_commit *commit) GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit); /** - * Get the short (one line) message of a commit. + * Get the encoding for the message of a commit, + * as a string representing a standard encoding name. + * + * The encoding may be NULL if the `encoding` header + * in the commit is missing; in that case UTF-8 is assumed. * * @param commit a previously loaded commit. - * @return the short message of a commit + * @return NULL, or the encoding */ -GIT_EXTERN(const char *) git_commit_message_short(git_commit *commit); +GIT_EXTERN(const char *) git_commit_message_encoding(git_commit *commit); /** * Get the full message of a commit. @@ -213,6 +217,11 @@ GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned i * @param committer Signature representing the committer and the * commit time of this commit * + * @param message_encoding The encoding for the message in the + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. + * * @param message Full message for this commit * * @param tree An instance of a `git_tree` object that will @@ -236,6 +245,7 @@ GIT_EXTERN(int) git_commit_create( const char *update_ref, const git_signature *author, const git_signature *committer, + const char *message_encoding, const char *message, const git_tree *tree, int parent_count, @@ -260,6 +270,7 @@ GIT_EXTERN(int) git_commit_create_v( const char *update_ref, const git_signature *author, const git_signature *committer, + const char *message_encoding, const char *message, const git_tree *tree, int parent_count, diff --git a/src/commit.c b/src/commit.c index 7c0965cb1..00e18b832 100644 --- a/src/commit.c +++ b/src/commit.c @@ -65,7 +65,7 @@ void git_commit__free(git_commit *commit) git_signature_free(commit->committer); free(commit->message); - free(commit->message_short); + free(commit->message_encoding); free(commit); } @@ -80,6 +80,7 @@ int git_commit_create_v( const char *update_ref, const git_signature *author, const git_signature *committer, + const char *message_encoding, const char *message, const git_tree *tree, int parent_count, @@ -97,7 +98,8 @@ int git_commit_create_v( va_end(ap); error = git_commit_create( - oid, repo, update_ref, author, committer, message, + oid, repo, update_ref, author, committer, + message_encoding, message, tree, parent_count, parents); free((void *)parents); @@ -111,6 +113,7 @@ int git_commit_create( const char *update_ref, const git_signature *author, const git_signature *committer, + const char *message_encoding, const char *message, const git_tree *tree, int parent_count, @@ -136,6 +139,9 @@ int git_commit_create( git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); + if (message_encoding != NULL) + git_buf_printf(&commit, "encoding %s\n", message_encoding); + git_buf_putc(&commit, '\n'); git_buf_puts(&commit, message); @@ -210,42 +216,36 @@ int commit_parse_buffer(git_commit *commit, const void *data, size_t len) commit->author = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n')) < GIT_SUCCESS) - return git__rethrow(error, "Failed to parse buffer"); + return git__rethrow(error, "Failed to parse commit"); /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < GIT_SUCCESS) - return git__rethrow(error, "Failed to parse buffer"); + return git__rethrow(error, "Failed to parse commit"); + + if (git__prefixcmp(buffer, "encoding ") == 0) { + const char *encoding_end; + buffer += STRLEN("encoding "); + + encoding_end = buffer; + while (encoding_end < buffer_end && *encoding_end != '\n') + encoding_end++; + + commit->message_encoding = git__strndup(buffer, encoding_end - buffer); + if (!commit->message_encoding) + return GIT_ENOMEM; + + buffer = encoding_end; + } /* parse commit message */ - while (buffer <= buffer_end && *buffer == '\n') + while (buffer < buffer_end && *buffer == '\n') buffer++; if (buffer < buffer_end) { - const char *line_end; - unsigned int i; - size_t message_len; - - /* Long message */ - message_len = buffer_end - buffer; - commit->message = git__malloc(message_len + 1); - memcpy(commit->message, buffer, message_len); - commit->message[message_len] = 0; - - /* Short message */ - if((line_end = strstr(buffer, "\n\n")) == NULL) { - /* Cut the last '\n' if there is one */ - if (message_len && buffer[message_len - 1] == '\n') - line_end = buffer_end - 1; - else - line_end = buffer_end; - } - message_len = line_end - buffer; - commit->message_short = git__malloc(message_len + 1); - for (i = 0; i < message_len; ++i) { - commit->message_short[i] = (buffer[i] == '\n') ? ' ' : buffer[i]; - } - commit->message_short[message_len] = 0; + commit->message = git__strndup(buffer, buffer_end - buffer); + if (!commit->message) + return GIT_ENOMEM; } return GIT_SUCCESS; @@ -267,7 +267,7 @@ int git_commit__parse(git_commit *commit, git_odb_object *obj) GIT_COMMIT_GETTER(const git_signature *, author, commit->author) GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) GIT_COMMIT_GETTER(const char *, message, commit->message) -GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) +GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding) GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) diff --git a/src/commit.h b/src/commit.h index 3d15c5044..ff2f28248 100644 --- a/src/commit.h +++ b/src/commit.h @@ -17,8 +17,8 @@ struct git_commit { git_signature *author; git_signature *committer; + char *message_encoding; char *message; - char *message_short; }; void git_commit__free(git_commit *c); diff --git a/tests/t04-commit.c b/tests/t04-commit.c index bb5171dd6..a8617ed6a 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -578,7 +578,7 @@ BEGIN_TEST(details0, "query the details on a parsed commit") git_commit *commit; const git_signature *author, *committer; - const char *message, *message_short; + const char *message; git_time_t commit_time; unsigned int parents, p; git_commit *parent = NULL, *old_parent = NULL; @@ -588,7 +588,6 @@ BEGIN_TEST(details0, "query the details on a parsed commit") must_pass(git_commit_lookup(&commit, repo, &id)); message = git_commit_message(commit); - message_short = git_commit_message_short(commit); author = git_commit_author(commit); committer = git_commit_committer(commit); commit_time = git_commit_time(commit); @@ -599,7 +598,6 @@ BEGIN_TEST(details0, "query the details on a parsed commit") must_be_true(strcmp(committer->name, "Scott Chacon") == 0); must_be_true(strcmp(committer->email, "schacon@gmail.com") == 0); must_be_true(strchr(message, '\n') != NULL); - must_be_true(strchr(message_short, '\n') == NULL); must_be_true(commit_time > 0); must_be_true(parents <= 2); for (p = 0;p < parents;p++) { @@ -655,6 +653,7 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk") NULL, /* do not update the HEAD */ author, committer, + NULL, COMMIT_MESSAGE, tree, 1, parent)); @@ -727,6 +726,7 @@ BEGIN_TEST(root0, "create a root commit") "HEAD", author, committer, + NULL, ROOT_COMMIT_MESSAGE, tree, 0));