determine_author_info(): reuse parsing functions

Rather than parsing the header manually to find the "author" field, and then parsing its sub-parts, let's use find_commit_header and split_ident_line. This is shorter and easier to read, and should do a more careful parsing job. For example, the current parser could find the end-of-email right-bracket across a newline (for a malformed commit), and calculate a bogus gigantic length for the date (by using "eol - rb"). As a bonus, this also plugs a memory leak when we pull the date field from an existing commit (we still leak the name and email buffers, which will be fixed in a later commit). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Aug 27, 2014 at 03:57 UTC f0f9662ae9d1c7f58a95397d1c6d5f31760b14be
1 file changed +21 -28
builtin/commit.c
+21 -28
@@ -546,42 +546,35 @@ static void determine_author_info(struct strbuf *author_ident)
546 date = getenv("GIT_AUTHOR_DATE");
547
548 if (author_message) {
549 - const char *a, *lb, *rb, *eol;
549 + struct ident_split ident;
550 size_t len;
551 + const char *a;
552
552 - a = strstr(author_message_buffer, "\nauthor ");
553 + a = find_commit_header(author_message_buffer, "author", &len);
554 if (!a)
554 - die(_("invalid commit: %s"), author_message);
555 -
556 - lb = strchrnul(a + strlen("\nauthor "), '<');
557 - rb = strchrnul(lb, '>');
558 - eol = strchrnul(rb, '\n');
559 - if (!*lb || !*rb || !*eol)
560 - die(_("invalid commit: %s"), author_message);
561 -
562 - if (lb == a + strlen("\nauthor "))
563 - /* \nauthor <foo@example.com> */
564 - name = xcalloc(1, 1);
565 - else
566 - name = xmemdupz(a + strlen("\nauthor "),
567 - (lb - strlen(" ") -
568 - (a + strlen("\nauthor "))));
569 - email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
570 - len = eol - (rb + strlen("> "));
571 - date = xmalloc(len + 2);
572 - *date = '@';
573 - memcpy(date + 1, rb + strlen("> "), len);
574 - date[len + 1] = '\0';
555 + die(_("commit '%s' lacks author header"), author_message);
556 + if (split_ident_line(&ident, a, len) < 0)
557 + die(_("commit '%s' has malformed author line"), author_message);
558 +
559 + name = xmemdupz(ident.name_begin, ident.name_end - ident.name_begin);
560 + email = xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin);
561 + if (ident.date_begin) {
562 + strbuf_reset(&date_buf);
563 + strbuf_addch(&date_buf, '@');
564 + strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin);
565 + strbuf_addch(&date_buf, ' ');
566 + strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin);
567 + date = date_buf.buf;
568 + }
569 }
570
571 if (force_author) {
578 - const char *lb = strstr(force_author, " <");
579 - const char *rb = strchr(force_author, '>');
572 + struct ident_split ident;
573
581 - if (!lb || !rb)
574 + if (split_ident_line(&ident, force_author, strlen(force_author)) < 0)
575 die(_("malformed --author parameter"));
583 - name = xstrndup(force_author, lb - force_author);
584 - email = xstrndup(lb + 2, rb - (lb + 2));
576 + name = xmemdupz(ident.name_begin, ident.name_end - ident.name_begin);
577 + email = xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin);
578 }
579
580 if (force_date) {