pretty.c 23.4 KB
Newer Older
1 2 3 4 5
#include "cache.h"
#include "commit.h"
#include "utf8.h"
#include "diff.h"
#include "revision.h"
6
#include "string-list.h"
7
#include "mailmap.h"
8
#include "log-tree.h"
J
Jeff King 已提交
9
#include "color.h"
10 11 12

static char *user_format;

13 14 15 16 17 18 19 20 21
static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
{
	free(user_format);
	user_format = xstrdup(cp);
	if (is_tformat)
		rev->use_terminator = 1;
	rev->commit_format = CMIT_FMT_USERFORMAT;
}

22
void get_commit_format(const char *arg, struct rev_info *rev)
23 24
{
	int i;
25 26 27 28 29 30 31 32 33 34 35 36 37
	static struct cmt_fmt_map {
		const char *n;
		size_t cmp_len;
		enum cmit_fmt v;
	} cmt_fmts[] = {
		{ "raw",	1,	CMIT_FMT_RAW },
		{ "medium",	1,	CMIT_FMT_MEDIUM },
		{ "short",	1,	CMIT_FMT_SHORT },
		{ "email",	1,	CMIT_FMT_EMAIL },
		{ "full",	5,	CMIT_FMT_FULL },
		{ "fuller",	5,	CMIT_FMT_FULLER },
		{ "oneline",	1,	CMIT_FMT_ONELINE },
	};
38

39 40 41 42 43 44
	rev->use_terminator = 0;
	if (!arg || !*arg) {
		rev->commit_format = CMIT_FMT_DEFAULT;
		return;
	}
	if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
45
		save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
46
		return;
47 48 49
	}
	for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
		if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
50 51 52 53 54 55
		    !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
			if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
				rev->use_terminator = 1;
			rev->commit_format = cmt_fmts[i].v;
			return;
		}
56
	}
57 58 59 60
	if (strchr(arg, '%')) {
		save_user_format(rev, arg, 1);
		return;
	}
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

	die("invalid --pretty format: %s", arg);
}

/*
 * Generic support for pretty-printing the header
 */
static int get_one_line(const char *msg)
{
	int ret = 0;

	for (;;) {
		char c = *msg++;
		if (!c)
			break;
		ret++;
		if (c == '\n')
			break;
	}
	return ret;
}

/* High bit set, or ISO-2022-INT */
int non_ascii(int ch)
{
R
René Scharfe 已提交
86
	return !isascii(ch) || ch == '\033';
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
}

static int is_rfc2047_special(char ch)
{
	return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
}

static void add_rfc2047(struct strbuf *sb, const char *line, int len,
		       const char *encoding)
{
	int i, last;

	for (i = 0; i < len; i++) {
		int ch = line[i];
		if (non_ascii(ch))
			goto needquote;
		if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
			goto needquote;
	}
	strbuf_add(sb, line, len);
	return;

needquote:
	strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
	strbuf_addf(sb, "=?%s?q?", encoding);
	for (i = last = 0; i < len; i++) {
		unsigned ch = line[i] & 0xFF;
		/*
		 * We encode ' ' using '=20' even though rfc2047
		 * allows using '_' for readability.  Unfortunately,
		 * many programs do not understand this and just
		 * leave the underscore in place.
		 */
		if (is_rfc2047_special(ch) || ch == ' ') {
			strbuf_add(sb, line + last, i - last);
			strbuf_addf(sb, "=%02X", ch);
			last = i + 1;
		}
	}
	strbuf_add(sb, line + last, len - last);
	strbuf_addstr(sb, "?=");
}

130 131 132
void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
		  const char *line, enum date_mode dmode,
		  const char *encoding)
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
{
	char *date;
	int namelen;
	unsigned long time;
	int tz;

	if (fmt == CMIT_FMT_ONELINE)
		return;
	date = strchr(line, '>');
	if (!date)
		return;
	namelen = ++date - line;
	time = strtoul(date, &date, 10);
	tz = strtol(date, NULL, 10);

	if (fmt == CMIT_FMT_EMAIL) {
		char *name_tail = strchr(line, '<');
		int display_name_length;
		if (!name_tail)
			return;
		while (line < name_tail && isspace(name_tail[-1]))
			name_tail--;
		display_name_length = name_tail - line;
		strbuf_addstr(sb, "From: ");
		add_rfc2047(sb, line, display_name_length, encoding);
		strbuf_add(sb, name_tail, namelen - display_name_length);
		strbuf_addch(sb, '\n');
	} else {
		strbuf_addf(sb, "%s: %.*s%.*s\n", what,
			      (fmt == CMIT_FMT_FULLER) ? 4 : 0,
B
Benjamin Kramer 已提交
163
			      "    ", namelen, line);
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	}
	switch (fmt) {
	case CMIT_FMT_MEDIUM:
		strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, dmode));
		break;
	case CMIT_FMT_EMAIL:
		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
		break;
	case CMIT_FMT_FULLER:
		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
		break;
	default:
		/* notin' */
		break;
	}
}

static int is_empty_line(const char *line, int *len_p)
{
	int len = *len_p;
	while (len && isspace(line[len-1]))
		len--;
	*len_p = len;
	return !len;
}

190 191 192 193 194 195 196 197 198 199 200 201 202 203
static const char *skip_empty_lines(const char *msg)
{
	for (;;) {
		int linelen = get_one_line(msg);
		int ll = linelen;
		if (!linelen)
			break;
		if (!is_empty_line(msg, &ll))
			break;
		msg += linelen;
	}
	return msg;
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
			const struct commit *commit, int abbrev)
{
	struct commit_list *parent = commit->parents;

	if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
	    !parent || !parent->next)
		return;

	strbuf_addstr(sb, "Merge:");

	while (parent) {
		struct commit *p = parent->item;
		const char *hex = NULL;
		if (abbrev)
			hex = find_unique_abbrev(p->object.sha1, abbrev);
		if (!hex)
			hex = sha1_to_hex(p->object.sha1);
		parent = parent->next;

224
		strbuf_addf(sb, " %s", hex);
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	}
	strbuf_addch(sb, '\n');
}

static char *get_header(const struct commit *commit, const char *key)
{
	int key_len = strlen(key);
	const char *line = commit->buffer;

	for (;;) {
		const char *eol = strchr(line, '\n'), *next;

		if (line == eol)
			return NULL;
		if (!eol) {
			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;
	}
}

static char *replace_encoding_header(char *buf, const char *encoding)
{
255
	struct strbuf tmp = STRBUF_INIT;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	size_t start, len;
	char *cp = buf;

	/* guess if there is an encoding header before a \n\n */
	while (strncmp(cp, "encoding ", strlen("encoding "))) {
		cp = strchr(cp, '\n');
		if (!cp || *++cp == '\n')
			return buf;
	}
	start = cp - buf;
	cp = strchr(cp, '\n');
	if (!cp)
		return buf; /* should not happen but be defensive */
	len = cp + 1 - (buf + start);

	strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
	if (is_encoding_utf8(encoding)) {
		/* we have re-coded to UTF-8; drop the header */
		strbuf_remove(&tmp, start, len);
	} else {
		/* just replaces XXXX in 'encoding XXXX\n' */
		strbuf_splice(&tmp, start + strlen("encoding "),
					  len - strlen("encoding \n"),
					  encoding, strlen(encoding));
	}
	return strbuf_detach(&tmp, NULL);
}

static char *logmsg_reencode(const struct commit *commit,
			     const char *output_encoding)
{
	static const char *utf8 = "utf-8";
	const char *use_encoding;
	char *encoding;
	char *out;

	if (!*output_encoding)
		return NULL;
	encoding = get_header(commit, "encoding");
	use_encoding = encoding ? encoding : utf8;
	if (!strcmp(use_encoding, output_encoding))
		if (encoding) /* we'll strip encoding header later */
			out = xstrdup(commit->buffer);
		else
			return NULL; /* nothing to do */
	else
		out = reencode_string(commit->buffer,
				      output_encoding, use_encoding);
	if (out)
		out = replace_encoding_header(out, output_encoding);

	free(encoding);
	return out;
}

311
static int mailmap_name(char *email, int email_len, char *name, int name_len)
312
{
313
	static struct string_list *mail_map;
314 315
	if (!mail_map) {
		mail_map = xcalloc(1, sizeof(*mail_map));
316
		read_mailmap(mail_map, NULL);
317
	}
318
	return mail_map->nr && map_user(mail_map, email, email_len, name, name_len);
319 320
}

321
static size_t format_person_part(struct strbuf *sb, char part,
322
				 const char *msg, int len, enum date_mode dmode)
323
{
324 325
	/* currently all placeholders have same length */
	const int placeholder_len = 2;
326
	int start, end, tz = 0;
327
	unsigned long date = 0;
328
	char *ep;
329 330 331
	const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
	char person_name[1024];
	char person_mail[1024];
332

333
	/* advance 'end' to point to email start delimiter */
334 335
	for (end = 0; end < len && msg[end] != '<'; end++)
		; /* do nothing */
336

337
	/*
338 339 340
	 * When end points at the '<' that we found, it should have
	 * matching '>' later, which means 'end' must be strictly
	 * below len - 1.
341
	 */
342 343 344
	if (end >= len - 2)
		goto skip;

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	/* Seek for both name and email part */
	name_start = msg;
	name_end = msg+end;
	while (name_end > name_start && isspace(*(name_end-1)))
		name_end--;
	mail_start = msg+end+1;
	mail_end = mail_start;
	while (mail_end < msg_end && *mail_end != '>')
		mail_end++;
	if (mail_end == msg_end)
		goto skip;
	end = mail_end-msg;

	if (part == 'N' || part == 'E') { /* mailmap lookup */
		strlcpy(person_name, name_start, name_end-name_start+1);
		strlcpy(person_mail, mail_start, mail_end-mail_start+1);
		mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
		name_start = person_name;
		name_end = name_start + strlen(person_name);
		mail_start = person_mail;
		mail_end = mail_start +  strlen(person_mail);
	}
367
	if (part == 'n' || part == 'N') {	/* name */
368
		strbuf_add(sb, name_start, name_end-name_start);
369
		return placeholder_len;
370
	}
371 372
	if (part == 'e' || part == 'E') {	/* email */
		strbuf_add(sb, mail_start, mail_end-mail_start);
373
		return placeholder_len;
374
	}
375

376
	/* advance 'start' to point to date start delimiter */
377 378 379
	for (start = end + 1; start < len && isspace(msg[start]); start++)
		; /* do nothing */
	if (start >= len)
380
		goto skip;
381 382
	date = strtoul(msg + start, &ep, 10);
	if (msg + start == ep)
383
		goto skip;
384

385 386
	if (part == 't') {	/* date, UNIX timestamp */
		strbuf_add(sb, msg + start, ep - (msg + start));
387
		return placeholder_len;
388
	}
389 390 391 392 393 394 395 396 397 398

	/* parse tz */
	for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
		; /* do nothing */
	if (start + 1 < len) {
		tz = strtoul(msg + start + 1, NULL, 10);
		if (msg[start] == '-')
			tz = -tz;
	}

399 400
	switch (part) {
	case 'd':	/* date */
401
		strbuf_addstr(sb, show_date(date, tz, dmode));
402
		return placeholder_len;
403 404
	case 'D':	/* date, RFC2822 style */
		strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
405
		return placeholder_len;
406 407
	case 'r':	/* date, relative */
		strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
408
		return placeholder_len;
409 410
	case 'i':	/* date, ISO 8601 */
		strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
411
		return placeholder_len;
412
	}
413 414 415 416 417 418 419 420 421 422 423

skip:
	/*
	 * bogus commit, 'sb' cannot be updated, but we still need to
	 * compute a valid return value.
	 */
	if (part == 'n' || part == 'e' || part == 't' || part == 'd'
	    || part == 'D' || part == 'r' || part == 'i')
		return placeholder_len;

	return 0; /* unknown placeholder */
424 425
}

426 427 428 429 430 431 432
struct chunk {
	size_t off;
	size_t len;
};

struct format_commit_context {
	const struct commit *commit;
433
	enum date_mode dmode;
434 435
	unsigned commit_header_parsed:1;
	unsigned commit_message_parsed:1;
436 437 438 439 440

	/* These offsets are relative to the start of the commit message. */
	struct chunk author;
	struct chunk committer;
	struct chunk encoding;
441 442
	size_t message_off;
	size_t subject_off;
443
	size_t body_off;
444 445 446 447 448

	/* The following ones are relative to the result struct strbuf. */
	struct chunk abbrev_commit_hash;
	struct chunk abbrev_tree_hash;
	struct chunk abbrev_parent_hashes;
449 450
};

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
static int add_again(struct strbuf *sb, struct chunk *chunk)
{
	if (chunk->len) {
		strbuf_adddup(sb, chunk->off, chunk->len);
		return 1;
	}

	/*
	 * We haven't seen this chunk before.  Our caller is surely
	 * going to add it the hard way now.  Remember the most likely
	 * start of the to-be-added chunk: the current end of the
	 * struct strbuf.
	 */
	chunk->off = sb->len;
	return 0;
}

468
static void parse_commit_header(struct format_commit_context *context)
469
{
470
	const char *msg = context->commit->buffer;
471
	int i;
472

473
	for (i = 0; msg[i]; i++) {
474 475 476 477 478
		int eol;
		for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
			; /* do nothing */

		if (i == eol) {
479
			break;
480 481 482 483 484 485 486 487 488 489 490 491
		} 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 (!prefixcmp(msg + i, "encoding ")) {
			context->encoding.off = i + 9;
			context->encoding.len = eol - i - 9;
		}
		i = eol;
	}
492
	context->message_off = i;
493 494 495
	context->commit_header_parsed = 1;
}

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
static int istitlechar(char c)
{
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
		(c >= '0' && c <= '9') || c == '.' || c == '_';
}

static void format_sanitized_subject(struct strbuf *sb, const char *msg)
{
	size_t trimlen;
	int space = 2;

	for (; *msg && *msg != '\n'; msg++) {
		if (istitlechar(*msg)) {
			if (space == 1)
				strbuf_addch(sb, '-');
			space = 0;
			strbuf_addch(sb, *msg);
			if (*msg == '.')
				while (*(msg+1) == '.')
					msg++;
		} else
			space |= 1;
	}

	/* trim any trailing '.' or '-' characters */
	trimlen = 0;
	while (sb->buf[sb->len - 1 - trimlen] == '.'
		|| sb->buf[sb->len - 1 - trimlen] == '-')
		trimlen++;
	strbuf_remove(sb, sb->len - trimlen, trimlen);
}

528 529
const char *format_subject(struct strbuf *sb, const char *msg,
			   const char *line_separator)
530 531 532 533 534 535 536 537 538 539 540
{
	int first = 1;

	for (;;) {
		const char *line = msg;
		int linelen = get_one_line(line);

		msg += linelen;
		if (!linelen || is_empty_line(line, &linelen))
			break;

541 542
		if (!sb)
			continue;
543 544 545 546 547 548 549 550 551
		strbuf_grow(sb, linelen + 2);
		if (!first)
			strbuf_addstr(sb, line_separator);
		strbuf_add(sb, line, linelen);
		first = 0;
	}
	return msg;
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
static void parse_commit_message(struct format_commit_context *c)
{
	const char *msg = c->commit->buffer + c->message_off;
	const char *start = c->commit->buffer;

	msg = skip_empty_lines(msg);
	c->subject_off = msg - start;

	msg = format_subject(NULL, msg, NULL);
	msg = skip_empty_lines(msg);
	c->body_off = msg - start;

	c->commit_message_parsed = 1;
}

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
static void format_decoration(struct strbuf *sb, const struct commit *commit)
{
	struct name_decoration *d;
	const char *prefix = " (";

	load_ref_decorations();
	d = lookup_decoration(&name_decoration, &commit->object);
	while (d) {
		strbuf_addstr(sb, prefix);
		prefix = ", ";
		strbuf_addstr(sb, d->name);
		d = d->next;
	}
	if (prefix[0] == ',')
		strbuf_addch(sb, ')');
}

584
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
585 586 587 588
                               void *context)
{
	struct format_commit_context *c = context;
	const struct commit *commit = c->commit;
589
	const char *msg = commit->buffer;
590
	struct commit_list *p;
591
	int h1, h2;
592 593

	/* these are independent of the commit */
594 595
	switch (placeholder[0]) {
	case 'C':
J
Jeff King 已提交
596 597 598 599 600 601 602 603 604 605 606
		if (placeholder[1] == '(') {
			const char *end = strchr(placeholder + 2, ')');
			char color[COLOR_MAXLEN];
			if (!end)
				return 0;
			color_parse_mem(placeholder + 2,
					end - (placeholder + 2),
					"--pretty format", color);
			strbuf_addstr(sb, color);
			return end - placeholder + 1;
		}
607
		if (!prefixcmp(placeholder + 1, "red")) {
608
			strbuf_addstr(sb, GIT_COLOR_RED);
609 610
			return 4;
		} else if (!prefixcmp(placeholder + 1, "green")) {
611
			strbuf_addstr(sb, GIT_COLOR_GREEN);
612 613
			return 6;
		} else if (!prefixcmp(placeholder + 1, "blue")) {
614
			strbuf_addstr(sb, GIT_COLOR_BLUE);
615 616
			return 5;
		} else if (!prefixcmp(placeholder + 1, "reset")) {
617
			strbuf_addstr(sb, GIT_COLOR_RESET);
618 619 620
			return 6;
		} else
			return 0;
621 622
	case 'n':		/* newline */
		strbuf_addch(sb, '\n');
623
		return 1;
624 625 626 627 628 629 630 631 632 633
	case 'x':
		/* %x00 == NUL, %x0a == LF, etc. */
		if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
		    h1 <= 16 &&
		    0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
		    h2 <= 16) {
			strbuf_addch(sb, (h1<<4)|h2);
			return 3;
		} else
			return 0;
634
	}
635 636 637 638 639

	/* these depend on the commit */
	if (!commit->object.parsed)
		parse_object(commit->object.sha1);

640 641 642
	switch (placeholder[0]) {
	case 'H':		/* commit hash */
		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
643
		return 1;
644
	case 'h':		/* abbreviated commit hash */
645
		if (add_again(sb, &c->abbrev_commit_hash))
646
			return 1;
647 648
		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
		                                     DEFAULT_ABBREV));
649
		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
650
		return 1;
651 652
	case 'T':		/* tree hash */
		strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
653
		return 1;
654
	case 't':		/* abbreviated tree hash */
655
		if (add_again(sb, &c->abbrev_tree_hash))
656
			return 1;
657 658
		strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
		                                     DEFAULT_ABBREV));
659
		c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
660
		return 1;
661 662 663 664 665 666
	case 'P':		/* parent hashes */
		for (p = commit->parents; p; p = p->next) {
			if (p != commit->parents)
				strbuf_addch(sb, ' ');
			strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
		}
667
		return 1;
668
	case 'p':		/* abbreviated parent hashes */
669
		if (add_again(sb, &c->abbrev_parent_hashes))
670
			return 1;
671 672 673 674 675 676
		for (p = commit->parents; p; p = p->next) {
			if (p != commit->parents)
				strbuf_addch(sb, ' ');
			strbuf_addstr(sb, find_unique_abbrev(
					p->item->object.sha1, DEFAULT_ABBREV));
		}
677 678
		c->abbrev_parent_hashes.len = sb->len -
		                              c->abbrev_parent_hashes.off;
679
		return 1;
680 681 682 683 684 685
	case 'm':		/* left/right/bottom */
		strbuf_addch(sb, (commit->object.flags & BOUNDARY)
		                 ? '-'
		                 : (commit->object.flags & SYMMETRIC_LEFT)
		                 ? '<'
		                 : '>');
686
		return 1;
687 688 689
	case 'd':
		format_decoration(sb, commit);
		return 1;
690 691 692
	}

	/* For the rest we have to parse the commit header. */
693 694
	if (!c->commit_header_parsed)
		parse_commit_header(c);
695

696
	switch (placeholder[0]) {
697 698
	case 'a':	/* author ... */
		return format_person_part(sb, placeholder[1],
699 700
				   msg + c->author.off, c->author.len,
				   c->dmode);
701 702
	case 'c':	/* committer ... */
		return format_person_part(sb, placeholder[1],
703 704
				   msg + c->committer.off, c->committer.len,
				   c->dmode);
705
	case 'e':	/* encoding */
706
		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
707
		return 1;
708 709 710 711 712 713 714 715 716 717
	}

	/* Now we need to parse the commit message. */
	if (!c->commit_message_parsed)
		parse_commit_message(c);

	switch (placeholder[0]) {
	case 's':	/* subject */
		format_subject(sb, msg + c->subject_off, " ");
		return 1;
718 719 720
	case 'f':	/* sanitized subject */
		format_sanitized_subject(sb, msg + c->subject_off);
		return 1;
721
	case 'b':	/* body */
722
		strbuf_addstr(sb, msg + c->body_off);
723
		return 1;
724
	}
725
	return 0;	/* unknown placeholder */
726 727 728
}

void format_commit_message(const struct commit *commit,
729 730
			   const void *format, struct strbuf *sb,
			   enum date_mode dmode)
731
{
732 733 734 735
	struct format_commit_context context;

	memset(&context, 0, sizeof(context));
	context.commit = commit;
736
	context.dmode = dmode;
737
	strbuf_expand(sb, format, format_commit_item, &context);
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
}

static void pp_header(enum cmit_fmt fmt,
		      int abbrev,
		      enum date_mode dmode,
		      const char *encoding,
		      const struct commit *commit,
		      const char **msg_p,
		      struct strbuf *sb)
{
	int parents_shown = 0;

	for (;;) {
		const char *line = *msg_p;
		int linelen = get_one_line(*msg_p);

		if (!linelen)
			return;
		*msg_p += linelen;

		if (linelen == 1)
			/* End of header */
			return;

		if (fmt == CMIT_FMT_RAW) {
			strbuf_add(sb, line, linelen);
			continue;
		}

		if (!memcmp(line, "parent ", 7)) {
			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++)
				;
			/* with enough slop */
			strbuf_grow(sb, num * 50 + 20);
			add_merge_info(fmt, sb, commit, abbrev);
			parents_shown = 1;
		}

		/*
		 * MEDIUM == DEFAULT shows only author with dates.
		 * FULL shows both authors but not dates.
		 * FULLER shows both authors and dates.
		 */
		if (!memcmp(line, "author ", 7)) {
			strbuf_grow(sb, linelen + 80);
793
			pp_user_info("Author", fmt, sb, line + 7, dmode, encoding);
794 795 796 797
		}
		if (!memcmp(line, "committer ", 10) &&
		    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
			strbuf_grow(sb, linelen + 80);
798
			pp_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
799 800 801 802
		}
	}
}

803 804 805 806 807 808
void pp_title_line(enum cmit_fmt fmt,
		   const char **msg_p,
		   struct strbuf *sb,
		   const char *subject,
		   const char *after_subject,
		   const char *encoding,
J
Junio C Hamano 已提交
809
		   int need_8bit_cte)
810
{
811
	const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
812 813 814
	struct strbuf title;

	strbuf_init(&title, 80);
815
	*msg_p = format_subject(&title, *msg_p, line_separator);
816 817 818 819 820 821 822 823 824 825

	strbuf_grow(sb, title.len + 1024);
	if (subject) {
		strbuf_addstr(sb, subject);
		add_rfc2047(sb, title.buf, title.len, encoding);
	} else {
		strbuf_addbuf(sb, &title);
	}
	strbuf_addch(sb, '\n');

826
	if (need_8bit_cte > 0) {
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
		const char *header_fmt =
			"MIME-Version: 1.0\n"
			"Content-Type: text/plain; charset=%s\n"
			"Content-Transfer-Encoding: 8bit\n";
		strbuf_addf(sb, header_fmt, encoding);
	}
	if (after_subject) {
		strbuf_addstr(sb, after_subject);
	}
	if (fmt == CMIT_FMT_EMAIL) {
		strbuf_addch(sb, '\n');
	}
	strbuf_release(&title);
}

842 843 844 845
void pp_remainder(enum cmit_fmt fmt,
		  const char **msg_p,
		  struct strbuf *sb,
		  int indent)
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
{
	int first = 1;
	for (;;) {
		const char *line = *msg_p;
		int linelen = get_one_line(line);
		*msg_p += linelen;

		if (!linelen)
			break;

		if (is_empty_line(line, &linelen)) {
			if (first)
				continue;
			if (fmt == CMIT_FMT_SHORT)
				break;
		}
		first = 0;

		strbuf_grow(sb, linelen + indent + 20);
		if (indent) {
			memset(sb->buf + sb->len, ' ', indent);
			strbuf_setlen(sb, sb->len + indent);
		}
		strbuf_add(sb, line, linelen);
		strbuf_addch(sb, '\n');
	}
}

874 875 876 877 878 879 880 881 882 883 884 885 886 887
char *reencode_commit_message(const struct commit *commit, const char **encoding_p)
{
	const char *encoding;

	encoding = (git_log_output_encoding
		    ? git_log_output_encoding
		    : git_commit_encoding);
	if (!encoding)
		encoding = "utf-8";
	if (encoding_p)
		*encoding_p = encoding;
	return logmsg_reencode(commit, encoding);
}

888
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
889 890 891
			 struct strbuf *sb, int abbrev,
			 const char *subject, const char *after_subject,
			 enum date_mode dmode, int need_8bit_cte)
892 893 894 895 896 897 898 899
{
	unsigned long beginning_of_body;
	int indent = 4;
	const char *msg = commit->buffer;
	char *reencoded;
	const char *encoding;

	if (fmt == CMIT_FMT_USERFORMAT) {
900
		format_commit_message(commit, user_format, sb, dmode);
901 902 903
		return;
	}

904
	reencoded = reencode_commit_message(commit, &encoding);
905 906 907 908 909 910 911
	if (reencoded) {
		msg = reencoded;
	}

	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
		indent = 0;

912 913 914
	/*
	 * We need to check and emit Content-type: to mark it
	 * as 8-bit if we haven't done so.
915
	 */
916
	if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
917 918 919 920 921 922 923 924 925 926 927 928
		int i, ch, in_body;

		for (in_body = i = 0; (ch = msg[i]); i++) {
			if (!in_body) {
				/* author could be non 7-bit ASCII but
				 * the log may be so; skip over the
				 * header part first.
				 */
				if (ch == '\n' && msg[i+1] == '\n')
					in_body = 1;
			}
			else if (non_ascii(ch)) {
929
				need_8bit_cte = 1;
930 931 932 933 934 935 936 937 938 939 940
				break;
			}
		}
	}

	pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
	if (fmt != CMIT_FMT_ONELINE && !subject) {
		strbuf_addch(sb, '\n');
	}

	/* Skip excess blank lines at the beginning of body, if any... */
941
	msg = skip_empty_lines(msg);
942 943 944 945

	/* These formats treat the title line specially. */
	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
		pp_title_line(fmt, &msg, sb, subject,
946
			      after_subject, encoding, need_8bit_cte);
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965

	beginning_of_body = sb->len;
	if (fmt != CMIT_FMT_ONELINE)
		pp_remainder(fmt, &msg, sb, indent);
	strbuf_rtrim(sb);

	/* Make sure there is an EOLN for the non-oneline case */
	if (fmt != CMIT_FMT_ONELINE)
		strbuf_addch(sb, '\n');

	/*
	 * The caller may append additional body text in e-mail
	 * format.  Make sure we did not strip the blank line
	 * between the header and the body.
	 */
	if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
		strbuf_addch(sb, '\n');
	free(reencoded);
}