Commit f55eca167c2d08045dff929adb8ad8b81d8ccc86

Carlos Martín Nieto 2016-02-09T07:17:26

commit: also match the first header field when searching We were searching only past the first header field, which meant we were unable to find e.g. `tree` which is the first field. While here, make sure to set an error message in case we cannot find the field.

diff --git a/src/commit.c b/src/commit.c
index 81aae48..87301e0 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -564,41 +564,45 @@ int git_commit_nth_gen_ancestor(
 
 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;
+	const char *eol, *buf = commit->raw_header;
 
 	git_buf_sanitize(out);
-	while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') {
-		h++;
-		if (git__prefixcmp(h, field)) {
-			buf = h;
+
+	while ((eol = strchr(buf, '\n')) && eol[1] != '\0') {
+		/* We can skip continuations here */
+		if (buf[0] == ' ') {
+			buf = eol + 1;
+			continue;
+		}
+
+		/* Skip until we find the field we're after */
+		if (git__prefixcmp(buf, field)) {
+			buf = eol + 1;
 			continue;
 		}
 
-		h += strlen(field);
-		eol = strchr(h, '\n');
-		if (h[0] != ' ') {
-			buf = h;
+		buf += strlen(field);
+		/* Check that we're not matching a prefix but the field itself */
+		if (buf[0] != ' ') {
+			buf = eol + 1;
 			continue;
 		}
-		if (!eol)
-			goto malformed;
 
-		h++; /* skip the SP */
+		buf++; /* skip the SP */
 
-		git_buf_put(out, h, eol - h);
+		git_buf_put(out, buf, eol - buf);
 		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');
+			buf = eol + 2;
+			eol = strchr(buf, '\n');
 			if (!eol)
 				goto malformed;
 
-			git_buf_put(out, h, eol - h);
+			git_buf_put(out, buf, eol - buf);
 		}
 
 		if (git_buf_oom(out))
@@ -607,6 +611,7 @@ int git_commit_header_field(git_buf *out, const git_commit *commit, const char *
 		return 0;
 	}
 
+	giterr_set(GITERR_OBJECT, "no such field '%s'", field);
 	return GIT_ENOTFOUND;
 
 malformed:
diff --git a/tests/commit/parse.c b/tests/commit/parse.c
index 388da07..7c7264b 100644
--- a/tests/commit/parse.c
+++ b/tests/commit/parse.c
@@ -443,6 +443,10 @@ cpxtDQQMGYFpXK/71stq\n\
 
 	cl_git_pass(parse_commit(&commit, passing_commit_cases[4]));
 
+	cl_git_pass(git_commit_header_field(&buf, commit, "tree"));
+	cl_assert_equal_s("6b79e22d69bf46e289df0345a14ca059dfc9bdf6", buf.ptr);
+	git_buf_clear(&buf);
+
 	cl_git_pass(git_commit_header_field(&buf, commit, "parent"));
 	cl_assert_equal_s("34734e478d6cf50c27c9d69026d93974d052c454", buf.ptr);
 	git_buf_clear(&buf);