pretty.c 32.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
Johannes Schindelin 已提交
9
#include "notes.h"
J
Jeff King 已提交
10
#include "color.h"
11
#include "reflog-walk.h"
12 13

static char *user_format;
14 15 16 17
static struct cmt_fmt_map {
	const char *name;
	enum cmit_fmt format;
	int is_tformat;
18 19
	int is_alias;
	const char *user_format;
20
} *commit_formats;
21
static size_t builtin_formats_len;
22
static size_t commit_formats_len;
23
static size_t commit_formats_alloc;
24
static struct cmt_fmt_map *find_commit_format(const char *sought);
25

26 27 28 29 30 31 32 33 34
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;
}

35
static int git_pretty_formats_config(const char *var, const char *value, void *cb)
36
{
37 38 39
	struct cmt_fmt_map *commit_format = NULL;
	const char *name;
	const char *fmt;
40
	int i;
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

	if (prefixcmp(var, "pretty."))
		return 0;

	name = var + strlen("pretty.");
	for (i = 0; i < builtin_formats_len; i++) {
		if (!strcmp(commit_formats[i].name, name))
			return 0;
	}

	for (i = builtin_formats_len; i < commit_formats_len; i++) {
		if (!strcmp(commit_formats[i].name, name)) {
			commit_format = &commit_formats[i];
			break;
		}
	}

	if (!commit_format) {
		ALLOC_GROW(commit_formats, commit_formats_len+1,
			   commit_formats_alloc);
		commit_format = &commit_formats[commit_formats_len];
62
		memset(commit_format, 0, sizeof(*commit_format));
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		commit_formats_len++;
	}

	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, '%'))
		commit_format->is_tformat = 1;
	else
		commit_format->is_alias = 1;
	commit_format->user_format = fmt;

	return 0;
}

81
static void setup_commit_formats(void)
82
{
83 84 85 86 87 88 89 90
	struct cmt_fmt_map builtin_formats[] = {
		{ "raw",	CMIT_FMT_RAW,		0 },
		{ "medium",	CMIT_FMT_MEDIUM,	0 },
		{ "short",	CMIT_FMT_SHORT,		0 },
		{ "email",	CMIT_FMT_EMAIL,		0 },
		{ "fuller",	CMIT_FMT_FULLER,	0 },
		{ "full",	CMIT_FMT_FULL,		0 },
		{ "oneline",	CMIT_FMT_ONELINE,	1 }
91
	};
92
	commit_formats_len = ARRAY_SIZE(builtin_formats);
93 94
	builtin_formats_len = commit_formats_len;
	ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
95 96
	memcpy(commit_formats, builtin_formats,
	       sizeof(*builtin_formats)*ARRAY_SIZE(builtin_formats));
97 98

	git_config(git_pretty_formats_config, NULL);
99 100
}

101 102 103
static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
							const char *original,
							int num_redirections)
104 105 106 107 108
{
	struct cmt_fmt_map *found = NULL;
	size_t found_match_len = 0;
	int i;

109 110 111 112
	if (num_redirections >= commit_formats_len)
		die("invalid --pretty format: "
		    "'%s' references an alias which points to itself",
		    original);
113 114 115 116 117 118 119 120 121 122 123 124 125

	for (i = 0; i < commit_formats_len; i++) {
		size_t match_len;

		if (prefixcmp(commit_formats[i].name, sought))
			continue;

		match_len = strlen(commit_formats[i].name);
		if (found == NULL || found_match_len > match_len) {
			found = &commit_formats[i];
			found_match_len = match_len;
		}
	}
126 127 128 129 130 131 132

	if (found && found->is_alias) {
		found = find_commit_format_recursive(found->user_format,
						     original,
						     num_redirections+1);
	}

133 134 135
	return found;
}

136 137 138 139 140 141 142 143
static struct cmt_fmt_map *find_commit_format(const char *sought)
{
	if (!commit_formats)
		setup_commit_formats();

	return find_commit_format_recursive(sought, sought, 0);
}

144 145 146
void get_commit_format(const char *arg, struct rev_info *rev)
{
	struct cmt_fmt_map *commit_format;
147

148 149 150 151 152 153
	rev->use_terminator = 0;
	if (!arg || !*arg) {
		rev->commit_format = CMIT_FMT_DEFAULT;
		return;
	}
	if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
154
		save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
155
		return;
156
	}
157

158 159 160 161
	if (strchr(arg, '%')) {
		save_user_format(rev, arg, 1);
		return;
	}
162

163 164 165 166 167 168
	commit_format = find_commit_format(arg);
	if (!commit_format)
		die("invalid --pretty format: %s", arg);

	rev->commit_format = commit_format->format;
	rev->use_terminator = commit_format->is_tformat;
169 170 171 172
	if (commit_format->format == CMIT_FMT_USERFORMAT) {
		save_user_format(rev, commit_format->user_format,
				 commit_format->is_tformat);
	}
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
}

/*
 * 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 */
194
static int non_ascii(int ch)
195
{
R
René Scharfe 已提交
196
	return !isascii(ch) || ch == '\033';
197 198
}

199 200 201 202 203 204 205 206 207 208 209 210
int has_non_ascii(const char *s)
{
	int ch;
	if (!s)
		return 0;
	while ((ch = *s++) != '\0') {
		if (non_ascii(ch))
			return 1;
	}
	return 0;
}

211 212 213 214 215 216 217 218 219 220 221 222 223 224 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 255 256 257 258 259 260 261 262
static int is_rfc822_special(char ch)
{
	switch (ch) {
	case '(':
	case ')':
	case '<':
	case '>':
	case '[':
	case ']':
	case ':':
	case ';':
	case '@':
	case ',':
	case '.':
	case '"':
	case '\\':
		return 1;
	default:
		return 0;
	}
}

static int has_rfc822_specials(const char *s, int len)
{
	int i;
	for (i = 0; i < len; i++)
		if (is_rfc822_special(s[i]))
			return 1;
	return 0;
}

static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
{
	int i;

	/* just a guess, we may have to also backslash-quote */
	strbuf_grow(out, len + 2);

	strbuf_addch(out, '"');
	for (i = 0; i < len; i++) {
		switch (s[i]) {
		case '"':
		case '\\':
			strbuf_addch(out, '\\');
			/* fall through */
		default:
			strbuf_addch(out, s[i]);
		}
	}
	strbuf_addch(out, '"');
}

263 264 265 266 267 268 269 270
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)
{
J
Jeff King 已提交
271 272 273 274 275 276 277 278 279
	static const int max_length = 78; /* per rfc2822 */
	int i;
	int line_len;

	/* How many bytes are already used on the current line? */
	for (i = sb->len - 1; i >= 0; i--)
		if (sb->buf[i] == '\n')
			break;
	line_len = sb->len - (i+1);
280 281 282

	for (i = 0; i < len; i++) {
		int ch = line[i];
283
		if (non_ascii(ch) || ch == '\n')
284 285 286 287
			goto needquote;
		if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
			goto needquote;
	}
J
Jeff King 已提交
288
	strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
289 290 291 292 293
	return;

needquote:
	strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
	strbuf_addf(sb, "=?%s?q?", encoding);
J
Jeff King 已提交
294 295
	line_len += strlen(encoding) + 5; /* 5 for =??q? */
	for (i = 0; i < len; i++) {
296
		unsigned ch = line[i] & 0xFF;
J
Jeff King 已提交
297 298 299 300 301 302

		if (line_len >= max_length - 2) {
			strbuf_addf(sb, "?=\n =?%s?q?", encoding);
			line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
		}

303 304 305 306 307 308
		/*
		 * 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.
		 */
309
		if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
310
			strbuf_addf(sb, "=%02X", ch);
J
Jeff King 已提交
311 312 313 314 315
			line_len += 3;
		}
		else {
			strbuf_addch(sb, ch);
			line_len++;
316 317 318 319 320
		}
	}
	strbuf_addstr(sb, "?=");
}

321 322 323
void pp_user_info(const struct pretty_print_context *pp,
		  const char *what, struct strbuf *sb,
		  const char *line, const char *encoding)
324 325 326 327 328 329
{
	char *date;
	int namelen;
	unsigned long time;
	int tz;

330
	if (pp->fmt == CMIT_FMT_ONELINE)
331 332 333 334 335 336 337 338
		return;
	date = strchr(line, '>');
	if (!date)
		return;
	namelen = ++date - line;
	time = strtoul(date, &date, 10);
	tz = strtol(date, NULL, 10);

339
	if (pp->fmt == CMIT_FMT_EMAIL) {
340 341
		char *name_tail = strchr(line, '<');
		int display_name_length;
342
		int final_line;
343 344 345 346 347 348
		if (!name_tail)
			return;
		while (line < name_tail && isspace(name_tail[-1]))
			name_tail--;
		display_name_length = name_tail - line;
		strbuf_addstr(sb, "From: ");
349 350 351 352 353 354 355 356
		if (!has_rfc822_specials(line, display_name_length)) {
			add_rfc2047(sb, line, display_name_length, encoding);
		} else {
			struct strbuf quoted = STRBUF_INIT;
			add_rfc822_quoted(&quoted, line, display_name_length);
			add_rfc2047(sb, quoted.buf, quoted.len, encoding);
			strbuf_release(&quoted);
		}
357 358 359 360 361 362 363 364
		for (final_line = 0; final_line < sb->len; final_line++)
			if (sb->buf[sb->len - final_line - 1] == '\n')
				break;
		if (namelen - display_name_length + final_line > 78) {
			strbuf_addch(sb, '\n');
			if (!isspace(name_tail[0]))
				strbuf_addch(sb, ' ');
		}
365 366 367 368
		strbuf_add(sb, name_tail, namelen - display_name_length);
		strbuf_addch(sb, '\n');
	} else {
		strbuf_addf(sb, "%s: %.*s%.*s\n", what,
369
			      (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,
B
Benjamin Kramer 已提交
370
			      "    ", namelen, line);
371
	}
372
	switch (pp->fmt) {
373
	case CMIT_FMT_MEDIUM:
374
		strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, pp->date_mode));
375 376 377 378 379
		break;
	case CMIT_FMT_EMAIL:
		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
		break;
	case CMIT_FMT_FULLER:
380
		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
		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;
}

397 398 399 400 401 402 403 404 405 406 407 408 409 410
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;
}

411 412
static void add_merge_info(const struct pretty_print_context *pp,
			   struct strbuf *sb, const struct commit *commit)
413 414 415
{
	struct commit_list *parent = commit->parents;

416
	if ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) ||
417 418 419 420 421 422 423 424
	    !parent || !parent->next)
		return;

	strbuf_addstr(sb, "Merge:");

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

431
		strbuf_addf(sb, " %s", hex);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
	}
	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)
{
462
	struct strbuf tmp = STRBUF_INIT;
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
	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);
}

491 492
char *logmsg_reencode(const struct commit *commit,
		      const char *output_encoding)
493
{
494
	static const char *utf8 = "UTF-8";
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
	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;
}

518
static int mailmap_name(char *email, int email_len, char *name, int name_len)
519
{
520
	static struct string_list *mail_map;
521 522
	if (!mail_map) {
		mail_map = xcalloc(1, sizeof(*mail_map));
523
		read_mailmap(mail_map, NULL);
524
	}
525
	return mail_map->nr && map_user(mail_map, email, email_len, name, name_len);
526 527
}

528
static size_t format_person_part(struct strbuf *sb, char part,
529
				 const char *msg, int len, enum date_mode dmode)
530
{
531 532
	/* currently all placeholders have same length */
	const int placeholder_len = 2;
533
	int start, end, tz = 0;
534
	unsigned long date = 0;
535
	char *ep;
536 537 538
	const char *name_start, *name_end, *mail_start, *mail_end, *msg_end = msg+len;
	char person_name[1024];
	char person_mail[1024];
539

540
	/* advance 'end' to point to email start delimiter */
541 542
	for (end = 0; end < len && msg[end] != '<'; end++)
		; /* do nothing */
543

544
	/*
545 546 547
	 * When end points at the '<' that we found, it should have
	 * matching '>' later, which means 'end' must be strictly
	 * below len - 1.
548
	 */
549 550 551
	if (end >= len - 2)
		goto skip;

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
	/* 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);
	}
574
	if (part == 'n' || part == 'N') {	/* name */
575
		strbuf_add(sb, name_start, name_end-name_start);
576
		return placeholder_len;
577
	}
578 579
	if (part == 'e' || part == 'E') {	/* email */
		strbuf_add(sb, mail_start, mail_end-mail_start);
580
		return placeholder_len;
581
	}
582

583
	/* advance 'start' to point to date start delimiter */
584 585 586
	for (start = end + 1; start < len && isspace(msg[start]); start++)
		; /* do nothing */
	if (start >= len)
587
		goto skip;
588 589
	date = strtoul(msg + start, &ep, 10);
	if (msg + start == ep)
590
		goto skip;
591

592 593
	if (part == 't') {	/* date, UNIX timestamp */
		strbuf_add(sb, msg + start, ep - (msg + start));
594
		return placeholder_len;
595
	}
596 597 598 599 600 601 602 603 604 605

	/* 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;
	}

606 607
	switch (part) {
	case 'd':	/* date */
608
		strbuf_addstr(sb, show_date(date, tz, dmode));
609
		return placeholder_len;
610 611
	case 'D':	/* date, RFC2822 style */
		strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
612
		return placeholder_len;
613 614
	case 'r':	/* date, relative */
		strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
615
		return placeholder_len;
616 617
	case 'i':	/* date, ISO 8601 */
		strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
618
		return placeholder_len;
619
	}
620 621 622 623 624 625 626 627 628 629 630

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 */
631 632
}

633 634 635 636 637 638 639
struct chunk {
	size_t off;
	size_t len;
};

struct format_commit_context {
	const struct commit *commit;
640
	const struct pretty_print_context *pretty_ctx;
641 642
	unsigned commit_header_parsed:1;
	unsigned commit_message_parsed:1;
643
	char *message;
644
	size_t width, indent1, indent2;
645 646 647 648 649

	/* These offsets are relative to the start of the commit message. */
	struct chunk author;
	struct chunk committer;
	struct chunk encoding;
650 651
	size_t message_off;
	size_t subject_off;
652
	size_t body_off;
653 654 655 656 657

	/* 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;
658
	size_t wrap_start;
659 660
};

661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
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;
}

678
static void parse_commit_header(struct format_commit_context *context)
679
{
680
	const char *msg = context->message;
681
	int i;
682

683
	for (i = 0; msg[i]; i++) {
684 685 686 687 688
		int eol;
		for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
			; /* do nothing */

		if (i == eol) {
689
			break;
690 691 692 693 694 695 696 697 698 699 700 701
		} 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;
	}
702
	context->message_off = i;
703 704 705
	context->commit_header_parsed = 1;
}

706 707 708 709 710 711 712 713 714
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;
715
	size_t start_len = sb->len;
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	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;
733 734 735
	while (sb->len - trimlen > start_len &&
		(sb->buf[sb->len - 1 - trimlen] == '.'
		|| sb->buf[sb->len - 1 - trimlen] == '-'))
736 737 738 739
		trimlen++;
	strbuf_remove(sb, sb->len - trimlen, trimlen);
}

740 741
const char *format_subject(struct strbuf *sb, const char *msg,
			   const char *line_separator)
742 743 744 745 746 747 748 749 750 751 752
{
	int first = 1;

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

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

753 754
		if (!sb)
			continue;
755 756 757 758 759 760 761 762 763
		strbuf_grow(sb, linelen + 2);
		if (!first)
			strbuf_addstr(sb, line_separator);
		strbuf_add(sb, line, linelen);
		first = 0;
	}
	return msg;
}

764 765
static void parse_commit_message(struct format_commit_context *c)
{
766 767
	const char *msg = c->message + c->message_off;
	const char *start = c->message;
768 769 770 771 772 773 774 775 776 777 778

	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;
}

779 780 781 782 783
static void format_decoration(struct strbuf *sb, const struct commit *commit)
{
	struct name_decoration *d;
	const char *prefix = " (";

784
	load_ref_decorations(DECORATE_SHORT_REFS);
785 786 787 788 789 790 791 792 793 794 795
	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, ')');
}

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
static void strbuf_wrap(struct strbuf *sb, size_t pos,
			size_t width, size_t indent1, size_t indent2)
{
	struct strbuf tmp = STRBUF_INIT;

	if (pos)
		strbuf_add(&tmp, sb->buf, pos);
	strbuf_add_wrapped_text(&tmp, sb->buf + pos,
				(int) indent1, (int) indent2, (int) width);
	strbuf_swap(&tmp, sb);
	strbuf_release(&tmp);
}

static void rewrap_message_tail(struct strbuf *sb,
				struct format_commit_context *c,
				size_t new_width, size_t new_indent1,
				size_t new_indent2)
{
	if (c->width == new_width && c->indent1 == new_indent1 &&
	    c->indent2 == new_indent2)
		return;
817
	if (c->wrap_start < sb->len)
818 819 820 821 822 823 824
		strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
	c->wrap_start = sb->len;
	c->width = new_width;
	c->indent1 = new_indent1;
	c->indent2 = new_indent2;
}

825 826
static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
				void *context)
827 828 829
{
	struct format_commit_context *c = context;
	const struct commit *commit = c->commit;
830
	const char *msg = c->message;
831
	struct commit_list *p;
832
	int h1, h2;
833 834

	/* these are independent of the commit */
835 836
	switch (placeholder[0]) {
	case 'C':
J
Jeff King 已提交
837 838 839 840 841 842 843 844 845 846 847
		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;
		}
848
		if (!prefixcmp(placeholder + 1, "red")) {
849
			strbuf_addstr(sb, GIT_COLOR_RED);
850 851
			return 4;
		} else if (!prefixcmp(placeholder + 1, "green")) {
852
			strbuf_addstr(sb, GIT_COLOR_GREEN);
853 854
			return 6;
		} else if (!prefixcmp(placeholder + 1, "blue")) {
855
			strbuf_addstr(sb, GIT_COLOR_BLUE);
856 857
			return 5;
		} else if (!prefixcmp(placeholder + 1, "reset")) {
858
			strbuf_addstr(sb, GIT_COLOR_RESET);
859 860 861
			return 6;
		} else
			return 0;
862 863
	case 'n':		/* newline */
		strbuf_addch(sb, '\n');
864
		return 1;
865 866 867 868 869 870 871 872 873 874
	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;
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
	case 'w':
		if (placeholder[1] == '(') {
			unsigned long width = 0, indent1 = 0, indent2 = 0;
			char *next;
			const char *start = placeholder + 2;
			const char *end = strchr(start, ')');
			if (!end)
				return 0;
			if (end > start) {
				width = strtoul(start, &next, 10);
				if (*next == ',') {
					indent1 = strtoul(next + 1, &next, 10);
					if (*next == ',') {
						indent2 = strtoul(next + 1,
								 &next, 10);
					}
				}
				if (*next != ')')
					return 0;
			}
			rewrap_message_tail(sb, c, width, indent1, indent2);
			return end - placeholder + 1;
		} else
			return 0;
899
	}
900 901 902 903 904

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

905 906 907
	switch (placeholder[0]) {
	case 'H':		/* commit hash */
		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
908
		return 1;
909
	case 'h':		/* abbreviated commit hash */
910
		if (add_again(sb, &c->abbrev_commit_hash))
911
			return 1;
912
		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
W
Will Palmer 已提交
913
						     c->pretty_ctx->abbrev));
914
		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
915
		return 1;
916 917
	case 'T':		/* tree hash */
		strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
918
		return 1;
919
	case 't':		/* abbreviated tree hash */
920
		if (add_again(sb, &c->abbrev_tree_hash))
921
			return 1;
922
		strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
W
Will Palmer 已提交
923
						     c->pretty_ctx->abbrev));
924
		c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
925
		return 1;
926 927 928 929 930 931
	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));
		}
932
		return 1;
933
	case 'p':		/* abbreviated parent hashes */
934
		if (add_again(sb, &c->abbrev_parent_hashes))
935
			return 1;
936 937 938 939
		for (p = commit->parents; p; p = p->next) {
			if (p != commit->parents)
				strbuf_addch(sb, ' ');
			strbuf_addstr(sb, find_unique_abbrev(
W
Will Palmer 已提交
940 941
					p->item->object.sha1,
					c->pretty_ctx->abbrev));
942
		}
943 944
		c->abbrev_parent_hashes.len = sb->len -
		                              c->abbrev_parent_hashes.off;
945
		return 1;
946
	case 'm':		/* left/right/bottom */
947
		strbuf_addstr(sb, get_revision_mark(NULL, commit));
948
		return 1;
949 950 951
	case 'd':
		format_decoration(sb, commit);
		return 1;
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
	case 'g':		/* reflog info */
		switch(placeholder[1]) {
		case 'd':	/* reflog selector */
		case 'D':
			if (c->pretty_ctx->reflog_info)
				get_reflog_selector(sb,
						    c->pretty_ctx->reflog_info,
						    c->pretty_ctx->date_mode,
						    (placeholder[1] == 'd'));
			return 2;
		case 's':	/* reflog message */
			if (c->pretty_ctx->reflog_info)
				get_reflog_message(sb, c->pretty_ctx->reflog_info);
			return 2;
		}
		return 0;	/* unknown %g placeholder */
968
	case 'N':
969 970
		if (c->pretty_ctx->show_notes) {
			format_display_notes(commit->object.sha1, sb,
971
				    get_log_output_encoding(), 0);
972 973 974
			return 1;
		}
		return 0;
975 976 977
	}

	/* For the rest we have to parse the commit header. */
978 979
	if (!c->commit_header_parsed)
		parse_commit_header(c);
980

981
	switch (placeholder[0]) {
982 983
	case 'a':	/* author ... */
		return format_person_part(sb, placeholder[1],
984
				   msg + c->author.off, c->author.len,
985
				   c->pretty_ctx->date_mode);
986 987
	case 'c':	/* committer ... */
		return format_person_part(sb, placeholder[1],
988
				   msg + c->committer.off, c->committer.len,
989
				   c->pretty_ctx->date_mode);
990
	case 'e':	/* encoding */
991
		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
992
		return 1;
993 994 995 996
	case 'B':	/* raw body */
		/* message_off is always left at the initial newline */
		strbuf_addstr(sb, msg + c->message_off + 1);
		return 1;
997 998 999 1000 1001 1002 1003 1004 1005 1006
	}

	/* 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;
1007 1008 1009
	case 'f':	/* sanitized subject */
		format_sanitized_subject(sb, msg + c->subject_off);
		return 1;
1010
	case 'b':	/* body */
1011
		strbuf_addstr(sb, msg + c->body_off);
1012
		return 1;
1013
	}
1014
	return 0;	/* unknown placeholder */
1015 1016
}

1017 1018 1019 1020 1021 1022 1023 1024 1025
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
				 void *context)
{
	int consumed;
	size_t orig_len;
	enum {
		NO_MAGIC,
		ADD_LF_BEFORE_NON_EMPTY,
		DEL_LF_BEFORE_EMPTY,
1026
		ADD_SP_BEFORE_NON_EMPTY
1027 1028 1029 1030 1031 1032 1033 1034 1035
	} magic = NO_MAGIC;

	switch (placeholder[0]) {
	case '-':
		magic = DEL_LF_BEFORE_EMPTY;
		break;
	case '+':
		magic = ADD_LF_BEFORE_NON_EMPTY;
		break;
1036 1037 1038
	case ' ':
		magic = ADD_SP_BEFORE_NON_EMPTY;
		break;
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
	default:
		break;
	}
	if (magic != NO_MAGIC)
		placeholder++;

	orig_len = sb->len;
	consumed = format_commit_one(sb, placeholder, context);
	if (magic == NO_MAGIC)
		return consumed;

	if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
		while (sb->len && sb->buf[sb->len - 1] == '\n')
			strbuf_setlen(sb, sb->len - 1);
1053 1054 1055 1056 1057
	} else if (orig_len != sb->len) {
		if (magic == ADD_LF_BEFORE_NON_EMPTY)
			strbuf_insert(sb, orig_len, "\n", 1);
		else if (magic == ADD_SP_BEFORE_NON_EMPTY)
			strbuf_insert(sb, orig_len, " ", 1);
1058 1059 1060 1061
	}
	return consumed + 1;
}

1062 1063 1064 1065 1066
static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
				   void *context)
{
	struct userformat_want *w = context;

1067
	if (*placeholder == '+' || *placeholder == '-' || *placeholder == ' ')
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
		placeholder++;

	switch (*placeholder) {
	case 'N':
		w->notes = 1;
		break;
	}
	return 0;
}

void userformat_find_requirements(const char *fmt, struct userformat_want *w)
{
	struct strbuf dummy = STRBUF_INIT;

	if (!fmt) {
		if (!user_format)
			return;
		fmt = user_format;
	}
1087
	strbuf_expand(&dummy, fmt, userformat_want_item, w);
1088 1089 1090
	strbuf_release(&dummy);
}

1091
void format_commit_message(const struct commit *commit,
1092
			   const char *format, struct strbuf *sb,
1093
			   const struct pretty_print_context *pretty_ctx)
1094
{
1095
	struct format_commit_context context;
1096 1097
	static const char utf8[] = "UTF-8";
	const char *output_enc = pretty_ctx->output_encoding;
1098 1099 1100

	memset(&context, 0, sizeof(context));
	context.commit = commit;
1101
	context.pretty_ctx = pretty_ctx;
1102
	context.wrap_start = sb->len;
1103 1104
	context.message = commit->buffer;
	if (output_enc) {
1105
		char *enc = get_header(commit, "encoding");
1106
		if (strcmp(enc ? enc : utf8, output_enc)) {
1107
			context.message = logmsg_reencode(commit, output_enc);
1108 1109 1110
			if (!context.message)
				context.message = commit->buffer;
		}
1111
		free(enc);
1112 1113
	}

1114
	strbuf_expand(sb, format, format_commit_item, &context);
1115
	rewrap_message_tail(sb, &context, 0, 0, 0);
1116 1117 1118

	if (context.message != commit->buffer)
		free(context.message);
1119 1120
}

1121
static void pp_header(const struct pretty_print_context *pp,
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
		      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;

1141
		if (pp->fmt == CMIT_FMT_RAW) {
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
			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);
1161
			add_merge_info(pp, sb, commit);
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
			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);
1172
			pp_user_info(pp, "Author", sb, line + 7, encoding);
1173 1174
		}
		if (!memcmp(line, "committer ", 10) &&
1175
		    (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
1176
			strbuf_grow(sb, linelen + 80);
1177
			pp_user_info(pp, "Commit", sb, line + 10, encoding);
1178 1179 1180 1181
		}
	}
}

1182
void pp_title_line(const struct pretty_print_context *pp,
1183 1184 1185
		   const char **msg_p,
		   struct strbuf *sb,
		   const char *encoding,
J
Junio C Hamano 已提交
1186
		   int need_8bit_cte)
1187 1188 1189 1190
{
	struct strbuf title;

	strbuf_init(&title, 80);
1191 1192
	*msg_p = format_subject(&title, *msg_p,
				pp->preserve_subject ? "\n" : " ");
1193 1194

	strbuf_grow(sb, title.len + 1024);
1195 1196
	if (pp->subject) {
		strbuf_addstr(sb, pp->subject);
1197 1198 1199 1200 1201 1202
		add_rfc2047(sb, title.buf, title.len, encoding);
	} else {
		strbuf_addbuf(sb, &title);
	}
	strbuf_addch(sb, '\n');

1203
	if (need_8bit_cte > 0) {
1204 1205 1206 1207 1208 1209
		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);
	}
1210 1211
	if (pp->after_subject) {
		strbuf_addstr(sb, pp->after_subject);
1212
	}
1213
	if (pp->fmt == CMIT_FMT_EMAIL) {
1214 1215 1216 1217 1218
		strbuf_addch(sb, '\n');
	}
	strbuf_release(&title);
}

1219
void pp_remainder(const struct pretty_print_context *pp,
1220 1221 1222
		  const char **msg_p,
		  struct strbuf *sb,
		  int indent)
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
{
	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;
1236
			if (pp->fmt == CMIT_FMT_SHORT)
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
				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');
	}
}

1251 1252 1253 1254
char *reencode_commit_message(const struct commit *commit, const char **encoding_p)
{
	const char *encoding;

1255
	encoding = get_log_output_encoding();
1256 1257 1258 1259 1260
	if (encoding_p)
		*encoding_p = encoding;
	return logmsg_reencode(commit, encoding);
}

1261 1262 1263
void pretty_print_commit(const struct pretty_print_context *pp,
			 const struct commit *commit,
			 struct strbuf *sb)
1264 1265 1266 1267 1268 1269
{
	unsigned long beginning_of_body;
	int indent = 4;
	const char *msg = commit->buffer;
	char *reencoded;
	const char *encoding;
1270
	int need_8bit_cte = pp->need_8bit_cte;
1271

1272 1273
	if (pp->fmt == CMIT_FMT_USERFORMAT) {
		format_commit_message(commit, user_format, sb, pp);
1274 1275 1276
		return;
	}

1277
	reencoded = reencode_commit_message(commit, &encoding);
1278 1279 1280 1281
	if (reencoded) {
		msg = reencoded;
	}

1282
	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
1283 1284
		indent = 0;

1285 1286 1287
	/*
	 * We need to check and emit Content-type: to mark it
	 * as 8-bit if we haven't done so.
1288
	 */
1289
	if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
		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)) {
1302
				need_8bit_cte = 1;
1303 1304 1305 1306 1307
				break;
			}
		}
	}

1308 1309
	pp_header(pp, encoding, commit, &msg, sb);
	if (pp->fmt != CMIT_FMT_ONELINE && !pp->subject) {
1310 1311 1312 1313
		strbuf_addch(sb, '\n');
	}

	/* Skip excess blank lines at the beginning of body, if any... */
1314
	msg = skip_empty_lines(msg);
1315 1316

	/* These formats treat the title line specially. */
1317 1318
	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
		pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
1319 1320

	beginning_of_body = sb->len;
1321 1322
	if (pp->fmt != CMIT_FMT_ONELINE)
		pp_remainder(pp, &msg, sb, indent);
1323 1324 1325
	strbuf_rtrim(sb);

	/* Make sure there is an EOLN for the non-oneline case */
1326
	if (pp->fmt != CMIT_FMT_ONELINE)
1327 1328 1329 1330 1331 1332 1333
		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.
	 */
1334
	if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
1335
		strbuf_addch(sb, '\n');
J
Johannes Schindelin 已提交
1336

1337
	if (pp->show_notes)
1338 1339
		format_display_notes(commit->object.sha1, sb, encoding,
				     NOTES_SHOW_HEADER | NOTES_INDENT);
J
Johannes Schindelin 已提交
1340

1341 1342
	free(reencoded);
}
1343 1344 1345 1346 1347

void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
		    struct strbuf *sb)
{
	struct pretty_print_context pp = {0};
1348 1349
	pp.fmt = fmt;
	pretty_print_commit(&pp, commit, sb);
1350
}