const char *fmt;
int i;
- if (prefixcmp(var, "pretty."))
+ if (!starts_with(var, "pretty."))
return 0;
name = var + strlen("pretty.");
commit_format->name = xstrdup(name);
commit_format->format = CMIT_FMT_USERFORMAT;
git_config_string(&fmt, var, value);
- if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
+ if (starts_with(fmt, "format:") || starts_with(fmt, "tformat:")) {
commit_format->is_tformat = fmt[0] == 't';
fmt = strchr(fmt, ':') + 1;
} else if (strchr(fmt, '%'))
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);
rev->commit_format = CMIT_FMT_DEFAULT;
return;
}
- if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
+ if (starts_with(arg, "format:") || starts_with(arg, "tformat:")) {
save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
return;
}
enum rfc2047_type {
RFC2047_SUBJECT,
- RFC2047_ADDRESS,
+ RFC2047_ADDRESS
};
static int is_rfc2047_special(char ch, enum rfc2047_type type)
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);
}
-void pp_user_info(const struct pretty_print_context *pp,
+void pp_user_info(struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding)
{
map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
if (pp->fmt == CMIT_FMT_EMAIL) {
+ if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, "From: ");
+ strbuf_add(&buf, namebuf, namelen);
+ strbuf_addstr(&buf, " <");
+ strbuf_add(&buf, mailbuf, maillen);
+ strbuf_addstr(&buf, ">\n");
+ string_list_append(&pp->in_body_headers,
+ strbuf_detach(&buf, NULL));
+
+ mailbuf = pp->from_ident->mail_begin;
+ maillen = pp->from_ident->mail_end - mailbuf;
+ namebuf = pp->from_ident->name_begin;
+ namelen = pp->from_ident->name_end - namebuf;
+ }
+
strbuf_addstr(sb, "From: ");
if (needs_rfc2047_encoding(namebuf, namelen, RFC2047_ADDRESS)) {
add_rfc2047(sb, namebuf, namelen,
static int is_empty_line(const char *line, int *len_p)
{
int len = *len_p;
- while (len && isspace(line[len-1]))
+ while (len && isspace(line[len - 1]))
len--;
*len_p = len;
return !len;
const char *line = msg;
while (line) {
- const char *eol = strchr(line, '\n'), *next;
+ const char *eol = strchrnul(line, '\n'), *next;
if (line == eol)
return NULL;
- if (!eol) {
+ 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;
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 =
* 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 {
/*
* 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);
}
/*
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)
{
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;
if (i == eol) {
break;
- } else if (!prefixcmp(msg + i, "author ")) {
+ } else if (starts_with(msg + i, "author ")) {
context->author.off = i + 7;
context->author.len = eol - i - 7;
- } else if (!prefixcmp(msg + i, "committer ")) {
+ } else if (starts_with(msg + i, "committer ")) {
context->committer.off = i + 10;
context->committer.len = eol - i - 10;
}
if (!end)
return 0;
- if (!prefixcmp(begin, "auto,")) {
+ if (starts_with(begin, "auto,")) {
if (!want_color(c->pretty_ctx->color))
return end - placeholder + 1;
begin += 5;
strbuf_addstr(sb, color);
return end - placeholder + 1;
}
- if (!prefixcmp(placeholder + 1, "red")) {
+ if (starts_with(placeholder + 1, "red")) {
strbuf_addstr(sb, GIT_COLOR_RED);
return 4;
- } else if (!prefixcmp(placeholder + 1, "green")) {
+ } else if (starts_with(placeholder + 1, "green")) {
strbuf_addstr(sb, GIT_COLOR_GREEN);
return 6;
- } else if (!prefixcmp(placeholder + 1, "blue")) {
+ } else if (starts_with(placeholder + 1, "blue")) {
strbuf_addstr(sb, GIT_COLOR_BLUE);
return 5;
- } else if (!prefixcmp(placeholder + 1, "reset")) {
+ } else if (starts_with(placeholder + 1, "reset")) {
strbuf_addstr(sb, GIT_COLOR_RESET);
return 6;
} else
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;
/* 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 {
if (c->signature_check.key)
strbuf_addstr(sb, c->signature_check.key);
break;
+ default:
+ return 0;
}
return 2;
}
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;
}
free(context.commit_encoding);
- logmsg_free(context.message, commit);
+ unuse_commit_buffer(commit, context.message);
free(context.signature_check.gpg_output);
free(context.signature_check.signer);
}
-static void pp_header(const struct pretty_print_context *pp,
+static void pp_header(struct pretty_print_context *pp,
const char *encoding,
const struct commit *commit,
const char **msg_p,
continue;
}
- if (!prefixcmp(line, "parent ")) {
+ if (starts_with(line, "parent ")) {
if (linelen != 48)
die("bad parent line in commit");
continue;
* FULL shows both authors but not dates.
* FULLER shows both authors and dates.
*/
- if (!prefixcmp(line, "author ")) {
+ if (starts_with(line, "author ")) {
strbuf_grow(sb, linelen + 80);
pp_user_info(pp, "Author", sb, line + 7, encoding);
}
- if (!prefixcmp(line, "committer ") &&
+ if (starts_with(line, "committer ") &&
(pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
strbuf_grow(sb, linelen + 80);
pp_user_info(pp, "Commit", sb, line + 10, encoding);
}
}
-void pp_title_line(const struct pretty_print_context *pp,
+void pp_title_line(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
const char *encoding,
}
strbuf_addch(sb, '\n');
+ if (need_8bit_cte == 0) {
+ int i;
+ for (i = 0; i < pp->in_body_headers.nr; i++) {
+ if (has_non_ascii(pp->in_body_headers.items[i].string)) {
+ need_8bit_cte = 1;
+ break;
+ }
+ }
+ }
+
if (need_8bit_cte > 0) {
const char *header_fmt =
"MIME-Version: 1.0\n"
if (pp->fmt == CMIT_FMT_EMAIL) {
strbuf_addch(sb, '\n');
}
+
+ if (pp->in_body_headers.nr) {
+ int i;
+ for (i = 0; i < pp->in_body_headers.nr; i++) {
+ strbuf_addstr(sb, pp->in_body_headers.items[i].string);
+ free(pp->in_body_headers.items[i].string);
+ }
+ string_list_clear(&pp->in_body_headers, 0);
+ strbuf_addch(sb, '\n');
+ }
+
strbuf_release(&title);
}
-void pp_remainder(const struct pretty_print_context *pp,
+void pp_remainder(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
int indent)
}
}
-void pretty_print_commit(const struct pretty_print_context *pp,
+void pretty_print_commit(struct pretty_print_context *pp,
const struct commit *commit,
struct strbuf *sb)
{
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;
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,