diff options
Diffstat (limited to 'pretty.c')
-rw-r--r-- | pretty.c | 226 |
1 files changed, 98 insertions, 128 deletions
@@ -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, |