store mode in rev_list, if <tree>:<filename> syntax is used
[gitweb.git] / commit.c
index 555252734298540ffc5678ac5d80888fd23dd4e5..10466c4ae0cb1db8648b9191fece9d9dbf238cb6 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -4,6 +4,8 @@
 #include "pkt-line.h"
 #include "utf8.h"
 #include "interpolate.h"
+#include "diff.h"
+#include "revision.h"
 
 int save_commit_buffer = 1;
 
@@ -96,12 +98,8 @@ struct commit *lookup_commit_reference(const unsigned char *sha1)
 struct commit *lookup_commit(const unsigned char *sha1)
 {
        struct object *obj = lookup_object(sha1);
-       if (!obj) {
-               struct commit *ret = alloc_commit_node();
-               created_object(sha1, &ret->object);
-               ret->object.type = OBJ_COMMIT;
-               return ret;
-       }
+       if (!obj)
+               return create_object(sha1, OBJ_COMMIT, alloc_commit_node());
        if (!obj->type)
                obj->type = OBJ_COMMIT;
        return check_commit(obj, sha1, 0);
@@ -651,9 +649,10 @@ static char *get_header(const struct commit *commit, const char *key)
        }
 }
 
-static char *replace_encoding_header(char *buf, char *encoding)
+static char *replace_encoding_header(char *buf, const char *encoding)
 {
        char *encoding_header = strstr(buf, "\nencoding ");
+       char *header_end = strstr(buf, "\n\n");
        char *end_of_encoding_header;
        int encoding_header_pos;
        int encoding_header_len;
@@ -661,8 +660,10 @@ static char *replace_encoding_header(char *buf, char *encoding)
        int need_len;
        int buflen = strlen(buf) + 1;
 
-       if (!encoding_header)
-               return buf; /* should not happen but be defensive */
+       if (!header_end)
+               header_end = buf + buflen;
+       if (!encoding_header || encoding_header >= header_end)
+               return buf;
        encoding_header++;
        end_of_encoding_header = strchr(encoding_header, '\n');
        if (!end_of_encoding_header)
@@ -694,29 +695,26 @@ static char *replace_encoding_header(char *buf, char *encoding)
 }
 
 static char *logmsg_reencode(const struct commit *commit,
-                            char *output_encoding)
+                            const char *output_encoding)
 {
+       static const char *utf8 = "utf-8";
+       const char *use_encoding;
        char *encoding;
        char *out;
-       char *utf8 = "utf-8";
 
        if (!*output_encoding)
                return NULL;
        encoding = get_header(commit, "encoding");
-       if (!encoding)
-               encoding = utf8;
-       if (!strcmp(encoding, output_encoding))
-               out = strdup(commit->buffer);
+       use_encoding = encoding ? encoding : utf8;
+       if (!strcmp(use_encoding, output_encoding))
+               out = xstrdup(commit->buffer);
        else
                out = reencode_string(commit->buffer,
-                                     output_encoding, encoding);
+                                     output_encoding, use_encoding);
        if (out)
                out = replace_encoding_header(out, output_encoding);
 
-       if (encoding != utf8)
-               free(encoding);
-       if (!out)
-               return NULL;
+       free(encoding);
        return out;
 }
 
@@ -763,7 +761,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
        if (msg + start == ep)
                return;
 
-       table[5].value = xstrndup(msg + start, ep - msg + start);
+       table[5].value = xstrndup(msg + start, ep - (msg + start));
 
        /* parse tz */
        for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
@@ -808,7 +806,8 @@ static long format_commit_message(const struct commit *commit,
                { "%Cgreen" },  /* green */
                { "%Cblue" },   /* blue */
                { "%Creset" },  /* reset color */
-               { "%n" }        /* newline */
+               { "%n" },       /* newline */
+               { "%m" },       /* left/right/bottom */
        };
        enum interp_index {
                IHASH = 0, IHASH_ABBREV,
@@ -824,14 +823,15 @@ static long format_commit_message(const struct commit *commit,
                ISUBJECT,
                IBODY,
                IRED, IGREEN, IBLUE, IRESET_COLOR,
-               INEWLINE
+               INEWLINE,
+               ILEFT_RIGHT,
        };
        struct commit_list *p;
        char parents[1024];
        int i;
        enum { HEADER, SUBJECT, BODY } state;
 
-       if (INEWLINE + 1 != ARRAY_SIZE(table))
+       if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
                die("invalid interp table!");
 
        /* these are independent of the commit */
@@ -852,19 +852,29 @@ static long format_commit_message(const struct commit *commit,
        interp_set_entry(table, ITREE_ABBREV,
                        find_unique_abbrev(commit->tree->object.sha1,
                                DEFAULT_ABBREV));
+       interp_set_entry(table, ILEFT_RIGHT,
+                        (commit->object.flags & BOUNDARY)
+                        ? "-"
+                        : (commit->object.flags & SYMMETRIC_LEFT)
+                        ? "<"
+                        : ">");
+
+       parents[1] = 0;
        for (i = 0, p = commit->parents;
                        p && i < sizeof(parents) - 1;
                        p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
+               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
                        sha1_to_hex(p->item->object.sha1));
-       interp_set_entry(table, IPARENTS, parents);
+       interp_set_entry(table, IPARENTS, parents + 1);
+
+       parents[1] = 0;
        for (i = 0, p = commit->parents;
                        p && i < sizeof(parents) - 1;
                        p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
+               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
                        find_unique_abbrev(p->item->object.sha1,
                                DEFAULT_ABBREV));
-       interp_set_entry(table, IPARENTS_ABBREV, parents);
+       interp_set_entry(table, IPARENTS_ABBREV, parents + 1);
 
        for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
                int eol;
@@ -887,7 +897,8 @@ static long format_commit_message(const struct commit *commit,
                        fill_person(table + ICOMMITTER_NAME,
                                        msg + i + 10, eol - i - 10);
                else if (!prefixcmp(msg + i, "encoding "))
-                       table[IENCODING].value = xstrndup(msg + i, eol - i);
+                       table[IENCODING].value =
+                               xstrndup(msg + i + 9, eol - i - 9);
                i = eol;
        }
        if (msg[i])
@@ -917,7 +928,7 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
        const char *msg = commit->buffer;
        int plain_non_ascii = 0;
        char *reencoded;
-       char *encoding;
+       const char *encoding;
 
        if (fmt == CMIT_FMT_USERFORMAT)
                return format_commit_message(commit, msg, buf, space);