Commit 5ae2f0c0135758020c46091491068a009e8ac10b

Vicent Marti 2011-08-12T16:24:19

commit: Add support for Encoding header

diff --git a/include/git2/commit.h b/include/git2/commit.h
index 84adef5..12646cf 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 7c0965c..00e18b8 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 3d15c50..ff2f282 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 bb5171d..a8617ed 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));