commit: fix a segfault when displaying a commit with unreachable parents
[gitweb.git] / log-tree.c
index 3a6c84dab559cc0904ba6c339fdb97edba7e7983..fbe139920ab0eada09dc921c152236d9676da44c 100644 (file)
@@ -12,28 +12,86 @@ static void show_parents(struct commit *commit, int abbrev)
        }
 }
 
+/*
+ * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches
+ * Signed-off-by: and Acked-by: lines.
+ */
+static int detect_any_signoff(char *letter, int size)
+{
+       char ch, *cp;
+       int seen_colon = 0;
+       int seen_at = 0;
+       int seen_name = 0;
+       int seen_head = 0;
+
+       cp = letter + size;
+       while (letter <= --cp && (ch = *cp) == '\n')
+               continue;
+
+       while (letter <= cp) {
+               ch = *cp--;
+               if (ch == '\n')
+                       break;
+
+               if (!seen_at) {
+                       if (ch == '@')
+                               seen_at = 1;
+                       continue;
+               }
+               if (!seen_colon) {
+                       if (ch == '@')
+                               return 0;
+                       else if (ch == ':')
+                               seen_colon = 1;
+                       else
+                               seen_name = 1;
+                       continue;
+               }
+               if (('A' <= ch && ch <= 'Z') ||
+                   ('a' <= ch && ch <= 'z') ||
+                   ch == '-') {
+                       seen_head = 1;
+                       continue;
+               }
+               /* no empty last line doesn't match */
+               return 0;
+       }
+       return seen_head && seen_name;
+}
+
 static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
 {
-       int signoff_len = strlen(signoff);
        static const char signed_off_by[] = "Signed-off-by: ";
+       int signoff_len = strlen(signoff);
+       int has_signoff = 0;
        char *cp = buf;
 
        /* Do we have enough space to add it? */
-       if (buf_sz - at <= strlen(signed_off_by) + signoff_len + 2)
+       if (buf_sz - at <= strlen(signed_off_by) + signoff_len + 3)
                return at;
 
        /* First see if we already have the sign-off by the signer */
-       while (1) {
-               cp = strstr(cp, signed_off_by);
-               if (!cp)
-                       break;
+       while ((cp = strstr(cp, signed_off_by))) {
+
+               has_signoff = 1;
+
                cp += strlen(signed_off_by);
-               if ((cp + signoff_len < buf + at) &&
-                   !strncmp(cp, signoff, signoff_len) &&
-                   isspace(cp[signoff_len]))
-                       return at; /* we already have him */
+               if (cp + signoff_len >= buf + at)
+                       break;
+               if (strncmp(cp, signoff, signoff_len))
+                       continue;
+               if (!isspace(cp[signoff_len]))
+                       continue;
+               /* we already have him */
+               return at;
        }
 
+       if (!has_signoff)
+               has_signoff = detect_any_signoff(buf, at);
+
+       if (!has_signoff)
+               buf[at++] = '\n';
+
        strcpy(buf + at, signed_off_by);
        at += strlen(signed_off_by);
        strcpy(buf + at, signoff);
@@ -59,7 +117,7 @@ void show_log(struct rev_info *opt, const char *sep)
                fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
                if (opt->parents)
                        show_parents(commit, abbrev_commit);
-               putchar('\n');
+               putchar(opt->diffopt.line_termination);
                return;
        }
 
@@ -97,6 +155,11 @@ void show_log(struct rev_info *opt, const char *sep)
                        subject = "Subject: ";
 
                printf("From %s Mon Sep 17 00:00:00 2001\n", sha1);
+               if (opt->message_id)
+                       printf("Message-Id: <%s>\n", opt->message_id);
+               if (opt->ref_message_id)
+                       printf("In-Reply-To: <%s>\nReferences: <%s>\n",
+                              opt->ref_message_id, opt->ref_message_id);
                if (opt->mime_boundary) {
                        static char subject_buffer[1024];
                        static char buffer[1024];
@@ -147,7 +210,9 @@ void show_log(struct rev_info *opt, const char *sep)
        /*
         * And then the pretty-printed message itself
         */
-       len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject, extra_headers);
+       len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,
+                                 sizeof(this_header), abbrev, subject,
+                                 extra_headers, opt->relative_date);
 
        if (opt->add_signoff)
                len = append_signoff(this_header, sizeof(this_header), len,