summaryrefslogtreecommitdiff
path: root/pretty.c
diff options
context:
space:
mode:
Diffstat (limited to 'pretty.c')
-rw-r--r--pretty.c226
1 files changed, 98 insertions, 128 deletions
diff --git a/pretty.c b/pretty.c
index 296cb56..9d34d02 100644
--- a/pretty.c
+++ b/pretty.c
@@ -24,6 +24,11 @@ static size_t commit_formats_len;
static size_t commit_formats_alloc;
static struct cmt_fmt_map *find_commit_format(const char *sought);
+int commit_format_is_empty(enum cmit_fmt fmt)
+{
+ return fmt == CMIT_FMT_USERFORMAT && !*user_format;
+}
+
static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
{
free(user_format);
@@ -40,10 +45,9 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
const char *fmt;
int i;
- if (prefixcmp(var, "pretty."))
+ if (!skip_prefix(var, "pretty.", &name))
return 0;
- name = var + strlen("pretty.");
for (i = 0; i < builtin_formats_len; i++) {
if (!strcmp(commit_formats[i].name, name))
return 0;
@@ -66,11 +70,12 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
commit_format->name = xstrdup(name);
commit_format->format = CMIT_FMT_USERFORMAT;
- git_config_string(&fmt, var, value);
- if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
- commit_format->is_tformat = fmt[0] == 't';
- fmt = strchr(fmt, ':') + 1;
- } else if (strchr(fmt, '%'))
+ if (git_config_string(&fmt, var, value))
+ return -1;
+
+ if (skip_prefix(fmt, "format:", &fmt))
+ commit_format->is_tformat = 0;
+ else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
commit_format->is_tformat = 1;
else
commit_format->is_alias = 1;
@@ -115,7 +120,7 @@ static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
for (i = 0; i < commit_formats_len; i++) {
size_t match_len;
- if (prefixcmp(commit_formats[i].name, sought))
+ if (!starts_with(commit_formats[i].name, sought))
continue;
match_len = strlen(commit_formats[i].name);
@@ -147,16 +152,16 @@ void get_commit_format(const char *arg, struct rev_info *rev)
struct cmt_fmt_map *commit_format;
rev->use_terminator = 0;
- if (!arg || !*arg) {
+ if (!arg) {
rev->commit_format = CMIT_FMT_DEFAULT;
return;
}
- if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
- save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
+ if (skip_prefix(arg, "format:", &arg)) {
+ save_user_format(rev, arg, 0);
return;
}
- if (strchr(arg, '%')) {
+ if (!*arg || skip_prefix(arg, "tformat:", &arg) || strchr(arg, '%')) {
save_user_format(rev, arg, 1);
return;
}
@@ -393,16 +398,22 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
strbuf_addstr(sb, "?=");
}
-static const char *show_ident_date(const struct ident_split *ident,
- enum date_mode mode)
+const char *show_ident_date(const struct ident_split *ident,
+ enum date_mode mode)
{
unsigned long date = 0;
- int tz = 0;
+ long tz = 0;
if (ident->date_begin && ident->date_end)
date = strtoul(ident->date_begin, NULL, 10);
- if (ident->tz_begin && ident->tz_end)
- tz = strtol(ident->tz_begin, NULL, 10);
+ if (date_overflows(date))
+ date = 0;
+ else {
+ if (ident->tz_begin && ident->tz_end)
+ tz = strtol(ident->tz_begin, NULL, 10);
+ if (tz >= INT_MAX || tz <= INT_MIN)
+ tz = 0;
+ }
return show_date(date, tz, mode);
}
@@ -542,32 +553,11 @@ static void add_merge_info(const struct pretty_print_context *pp,
strbuf_addch(sb, '\n');
}
-static char *get_header(const struct commit *commit, const char *msg,
- const char *key)
+static char *get_header(const char *msg, const char *key)
{
- int key_len = strlen(key);
- const char *line = msg;
-
- while (line) {
- const char *eol = strchr(line, '\n'), *next;
-
- if (line == eol)
- return NULL;
- if (!eol) {
- warning("malformed commit (header is missing newline): %s",
- sha1_to_hex(commit->object.sha1));
- eol = line + strlen(line);
- next = NULL;
- } else
- next = eol + 1;
- if (eol - line > key_len &&
- !strncmp(line, key, key_len) &&
- line[key_len] == ' ') {
- return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
- }
- line = next;
- }
- return NULL;
+ size_t len;
+ const char *v = find_commit_header(msg, key, &len);
+ return v ? xmemdupz(v, len) : NULL;
}
static char *replace_encoding_header(char *buf, const char *encoding)
@@ -601,36 +591,22 @@ static char *replace_encoding_header(char *buf, const char *encoding)
return strbuf_detach(&tmp, NULL);
}
-char *logmsg_reencode(const struct commit *commit,
- char **commit_encoding,
- const char *output_encoding)
+const char *logmsg_reencode(const struct commit *commit,
+ char **commit_encoding,
+ const char *output_encoding)
{
static const char *utf8 = "UTF-8";
const char *use_encoding;
char *encoding;
- char *msg = commit->buffer;
+ const char *msg = get_commit_buffer(commit, NULL);
char *out;
- if (!msg) {
- enum object_type type;
- unsigned long size;
-
- msg = read_sha1_file(commit->object.sha1, &type, &size);
- if (!msg)
- die("Cannot read commit object %s",
- sha1_to_hex(commit->object.sha1));
- if (type != OBJ_COMMIT)
- die("Expected commit for '%s', got %s",
- sha1_to_hex(commit->object.sha1), typename(type));
- }
-
if (!output_encoding || !*output_encoding) {
if (commit_encoding)
- *commit_encoding =
- get_header(commit, msg, "encoding");
+ *commit_encoding = get_header(msg, "encoding");
return msg;
}
- encoding = get_header(commit, msg, "encoding");
+ encoding = get_header(msg, "encoding");
if (commit_encoding)
*commit_encoding = encoding;
use_encoding = encoding ? encoding : utf8;
@@ -647,12 +623,13 @@ char *logmsg_reencode(const struct commit *commit,
* Otherwise, we still want to munge the encoding header in the
* result, which will be done by modifying the buffer. If we
* are using a fresh copy, we can reuse it. But if we are using
- * the cached copy from commit->buffer, we need to duplicate it
- * to avoid munging commit->buffer.
+ * the cached copy from get_commit_buffer, we need to duplicate it
+ * to avoid munging the cached copy.
*/
- out = msg;
- if (out == commit->buffer)
- out = xstrdup(out);
+ if (msg == get_cached_commit_buffer(commit, NULL))
+ out = xstrdup(msg);
+ else
+ out = (char *)msg;
}
else {
/*
@@ -662,8 +639,8 @@ char *logmsg_reencode(const struct commit *commit,
* copy, we can free it.
*/
out = reencode_string(msg, output_encoding, use_encoding);
- if (out && msg != commit->buffer)
- free(msg);
+ if (out)
+ unuse_commit_buffer(commit, msg);
}
/*
@@ -682,12 +659,6 @@ char *logmsg_reencode(const struct commit *commit,
return out ? out : msg;
}
-void logmsg_free(char *msg, const struct commit *commit)
-{
- if (msg != commit->buffer)
- free(msg);
-}
-
static int mailmap_name(const char **email, size_t *email_len,
const char **name, size_t *name_len)
{
@@ -745,9 +716,12 @@ static size_t format_person_part(struct strbuf *sb, char part,
case 'r': /* date, relative */
strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
return placeholder_len;
- case 'i': /* date, ISO 8601 */
+ case 'i': /* date, ISO 8601-like */
strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
return placeholder_len;
+ case 'I': /* date, ISO 8601 strict */
+ strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT));
+ return placeholder_len;
}
skip:
@@ -791,7 +765,7 @@ struct format_commit_context {
struct signature_check signature_check;
enum flush_type flush_type;
enum trunc_type truncate;
- char *message;
+ const char *message;
char *commit_encoding;
size_t width, indent1, indent2;
int auto_color;
@@ -834,18 +808,19 @@ static void parse_commit_header(struct format_commit_context *context)
int i;
for (i = 0; msg[i]; i++) {
+ const char *name;
int eol;
for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
; /* do nothing */
if (i == eol) {
break;
- } else if (!prefixcmp(msg + i, "author ")) {
- context->author.off = i + 7;
- context->author.len = eol - i - 7;
- } else if (!prefixcmp(msg + i, "committer ")) {
- context->committer.off = i + 10;
- context->committer.len = eol - i - 10;
+ } else if (skip_prefix(msg + i, "author ", &name)) {
+ context->author.off = name - msg;
+ context->author.len = msg + eol - name;
+ } else if (skip_prefix(msg + i, "committer ", &name)) {
+ context->committer.off = name - msg;
+ context->committer.len = msg + eol - name;
}
i = eol;
}
@@ -976,6 +951,8 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
const char *placeholder,
struct format_commit_context *c)
{
+ const char *rest = placeholder;
+
if (placeholder[1] == '(') {
const char *begin = placeholder + 2;
const char *end = strchr(begin, ')');
@@ -983,31 +960,24 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
if (!end)
return 0;
- if (!prefixcmp(begin, "auto,")) {
+ if (skip_prefix(begin, "auto,", &begin)) {
if (!want_color(c->pretty_ctx->color))
return end - placeholder + 1;
- begin += 5;
}
- color_parse_mem(begin,
- end - begin,
- "--pretty format", color);
+ if (color_parse_mem(begin, end - begin, color) < 0)
+ die(_("unable to parse --pretty format"));
strbuf_addstr(sb, color);
return end - placeholder + 1;
}
- if (!prefixcmp(placeholder + 1, "red")) {
+ if (skip_prefix(placeholder + 1, "red", &rest))
strbuf_addstr(sb, GIT_COLOR_RED);
- return 4;
- } else if (!prefixcmp(placeholder + 1, "green")) {
+ else if (skip_prefix(placeholder + 1, "green", &rest))
strbuf_addstr(sb, GIT_COLOR_GREEN);
- return 6;
- } else if (!prefixcmp(placeholder + 1, "blue")) {
+ else if (skip_prefix(placeholder + 1, "blue", &rest))
strbuf_addstr(sb, GIT_COLOR_BLUE);
- return 5;
- } else if (!prefixcmp(placeholder + 1, "reset")) {
+ else if (skip_prefix(placeholder + 1, "reset", &rest))
strbuf_addstr(sb, GIT_COLOR_RESET);
- return 6;
- } else
- return 0;
+ return rest - placeholder;
}
static size_t parse_padding_placeholder(struct strbuf *sb,
@@ -1060,11 +1030,11 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
end = strchr(start, ')');
if (!end || end == start)
return 0;
- if (!prefixcmp(start, "trunc)"))
+ if (starts_with(start, "trunc)"))
c->truncate = trunc_right;
- else if (!prefixcmp(start, "ltrunc)"))
+ else if (starts_with(start, "ltrunc)"))
c->truncate = trunc_left;
- else if (!prefixcmp(start, "mtrunc)"))
+ else if (starts_with(start, "mtrunc)"))
c->truncate = trunc_middle;
else
return 0;
@@ -1089,7 +1059,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
/* these are independent of the commit */
switch (placeholder[0]) {
case 'C':
- if (!prefixcmp(placeholder + 1, "(auto)")) {
+ if (starts_with(placeholder + 1, "(auto)")) {
c->auto_color = 1;
return 7; /* consumed 7 bytes, "C(auto)" */
} else {
@@ -1204,6 +1174,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
load_ref_decorations(DECORATE_SHORT_REFS);
format_decorations(sb, commit, c->auto_color);
return 1;
+ case 'D':
+ load_ref_decorations(DECORATE_SHORT_REFS);
+ format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
+ return 1;
case 'g': /* reflog info */
switch(placeholder[1]) {
case 'd': /* reflog selector */
@@ -1262,6 +1236,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
if (c->signature_check.key)
strbuf_addstr(sb, c->signature_check.key);
break;
+ default:
+ return 0;
}
return 2;
}
@@ -1388,7 +1364,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
case trunc_none:
break;
}
- strbuf_addstr(sb, local_sb.buf);
+ strbuf_addbuf(sb, &local_sb);
} else {
int sb_len = sb->len, offset = 0;
if (c->flush_type == flush_left)
@@ -1400,9 +1376,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
* convert it back to chars
*/
padding = padding - len + local_sb.len;
- strbuf_grow(sb, padding);
- strbuf_setlen(sb, sb_len + padding);
- memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+ strbuf_addchars(sb, ' ', padding);
memcpy(sb->buf + sb_len + offset, local_sb.buf,
local_sb.len);
}
@@ -1501,13 +1475,18 @@ void format_commit_message(const struct commit *commit,
context.commit = commit;
context.pretty_ctx = pretty_ctx;
context.wrap_start = sb->len;
+ /*
+ * convert a commit message to UTF-8 first
+ * as far as 'format_commit_item' assumes it in UTF-8
+ */
context.message = logmsg_reencode(commit,
&context.commit_encoding,
- output_enc);
+ utf8);
strbuf_expand(sb, format, format_commit_item, &context);
rewrap_message_tail(sb, &context, 0, 0, 0);
+ /* then convert a commit message to an actual output encoding */
if (output_enc) {
if (same_encoding(utf8, output_enc))
output_enc = NULL;
@@ -1526,9 +1505,7 @@ void format_commit_message(const struct commit *commit,
}
free(context.commit_encoding);
- logmsg_free(context.message, commit);
- free(context.signature_check.gpg_output);
- free(context.signature_check.signer);
+ unuse_commit_buffer(commit, context.message);
}
static void pp_header(struct pretty_print_context *pp,
@@ -1540,7 +1517,7 @@ static void pp_header(struct pretty_print_context *pp,
int parents_shown = 0;
for (;;) {
- const char *line = *msg_p;
+ const char *name, *line = *msg_p;
int linelen = get_one_line(*msg_p);
if (!linelen)
@@ -1556,19 +1533,14 @@ static void pp_header(struct pretty_print_context *pp,
continue;
}
- if (!prefixcmp(line, "parent ")) {
+ if (starts_with(line, "parent ")) {
if (linelen != 48)
die("bad parent line in commit");
continue;
}
if (!parents_shown) {
- struct commit_list *parent;
- int num;
- for (parent = commit->parents, num = 0;
- parent;
- parent = parent->next, num++)
- ;
+ unsigned num = commit_list_count(commit->parents);
/* with enough slop */
strbuf_grow(sb, num * 50 + 20);
add_merge_info(pp, sb, commit);
@@ -1580,14 +1552,14 @@ static void pp_header(struct pretty_print_context *pp,
* FULL shows both authors but not dates.
* FULLER shows both authors and dates.
*/
- if (!prefixcmp(line, "author ")) {
+ if (skip_prefix(line, "author ", &name)) {
strbuf_grow(sb, linelen + 80);
- pp_user_info(pp, "Author", sb, line + 7, encoding);
+ pp_user_info(pp, "Author", sb, name, encoding);
}
- if (!prefixcmp(line, "committer ") &&
+ if (skip_prefix(line, "committer ", &name) &&
(pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
strbuf_grow(sb, linelen + 80);
- pp_user_info(pp, "Commit", sb, line + 10, encoding);
+ pp_user_info(pp, "Commit", sb, name, encoding);
}
}
}
@@ -1679,10 +1651,8 @@ void pp_remainder(struct pretty_print_context *pp,
first = 0;
strbuf_grow(sb, linelen + indent + 20);
- if (indent) {
- memset(sb->buf + sb->len, ' ', indent);
- strbuf_setlen(sb, sb->len + indent);
- }
+ if (indent)
+ strbuf_addchars(sb, ' ', indent);
strbuf_add(sb, line, linelen);
strbuf_addch(sb, '\n');
}
@@ -1695,7 +1665,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
unsigned long beginning_of_body;
int indent = 4;
const char *msg;
- char *reencoded;
+ const char *reencoded;
const char *encoding;
int need_8bit_cte = pp->need_8bit_cte;
@@ -1762,7 +1732,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
strbuf_addch(sb, '\n');
- logmsg_free(reencoded, commit);
+ unuse_commit_buffer(commit, reencoded);
}
void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,