Git fork
at reftables-rust 2372 lines 59 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2#define DISABLE_SIGN_COMPARE_WARNINGS 3 4#include "git-compat-util.h" 5#include "config.h" 6#include "commit.h" 7#include "environment.h" 8#include "gettext.h" 9#include "hash.h" 10#include "hex.h" 11#include "utf8.h" 12#include "diff.h" 13#include "pager.h" 14#include "revision.h" 15#include "string-list.h" 16#include "mailmap.h" 17#include "log-tree.h" 18#include "notes.h" 19#include "color.h" 20#include "reflog-walk.h" 21#include "gpg-interface.h" 22#include "trailer.h" 23#include "run-command.h" 24#include "object-name.h" 25 26/* 27 * The limit for formatting directives, which enable the caller to append 28 * arbitrarily many bytes to the formatted buffer. This includes padding 29 * and wrapping formatters. 30 */ 31#define FORMATTING_LIMIT (16 * 1024) 32 33static char *user_format; 34static struct cmt_fmt_map { 35 const char *name; 36 enum cmit_fmt format; 37 int is_tformat; 38 int expand_tabs_in_log; 39 int is_alias; 40 enum date_mode_type default_date_mode_type; 41 const char *user_format; 42} *commit_formats; 43static size_t builtin_formats_len; 44static size_t commit_formats_len; 45static size_t commit_formats_alloc; 46static struct cmt_fmt_map *find_commit_format(const char *sought); 47 48int commit_format_is_empty(enum cmit_fmt fmt) 49{ 50 return fmt == CMIT_FMT_USERFORMAT && !*user_format; 51} 52 53static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat) 54{ 55 free(user_format); 56 user_format = xstrdup(cp); 57 if (is_tformat) 58 rev->use_terminator = 1; 59 rev->commit_format = CMIT_FMT_USERFORMAT; 60} 61 62static int git_pretty_formats_config(const char *var, const char *value, 63 const struct config_context *ctx UNUSED, 64 void *cb UNUSED) 65{ 66 struct cmt_fmt_map *commit_format = NULL; 67 const char *name, *stripped; 68 char *fmt; 69 int i; 70 71 if (!skip_prefix(var, "pretty.", &name)) 72 return 0; 73 74 for (i = 0; i < builtin_formats_len; i++) { 75 if (!strcmp(commit_formats[i].name, name)) 76 return 0; 77 } 78 79 for (i = builtin_formats_len; i < commit_formats_len; i++) { 80 if (!strcmp(commit_formats[i].name, name)) { 81 commit_format = &commit_formats[i]; 82 break; 83 } 84 } 85 86 if (!commit_format) { 87 ALLOC_GROW(commit_formats, commit_formats_len+1, 88 commit_formats_alloc); 89 commit_format = &commit_formats[commit_formats_len]; 90 memset(commit_format, 0, sizeof(*commit_format)); 91 commit_formats_len++; 92 } 93 94 free((char *)commit_format->name); 95 commit_format->name = xstrdup(name); 96 commit_format->format = CMIT_FMT_USERFORMAT; 97 if (git_config_string(&fmt, var, value)) 98 return -1; 99 100 free((char *)commit_format->user_format); 101 if (skip_prefix(fmt, "format:", &stripped)) { 102 commit_format->is_tformat = 0; 103 commit_format->user_format = xstrdup(stripped); 104 free(fmt); 105 } else if (skip_prefix(fmt, "tformat:", &stripped)) { 106 commit_format->is_tformat = 1; 107 commit_format->user_format = xstrdup(stripped); 108 free(fmt); 109 } else if (strchr(fmt, '%')) { 110 commit_format->is_tformat = 1; 111 commit_format->user_format = fmt; 112 } else { 113 commit_format->is_alias = 1; 114 commit_format->user_format = fmt; 115 } 116 117 return 0; 118} 119 120static void setup_commit_formats(void) 121{ 122 struct cmt_fmt_map builtin_formats[] = { 123 { "raw", CMIT_FMT_RAW, 0, 0 }, 124 { "medium", CMIT_FMT_MEDIUM, 0, 8 }, 125 { "short", CMIT_FMT_SHORT, 0, 0 }, 126 { "email", CMIT_FMT_EMAIL, 0, 0 }, 127 { "mboxrd", CMIT_FMT_MBOXRD, 0, 0 }, 128 { "fuller", CMIT_FMT_FULLER, 0, 8 }, 129 { "full", CMIT_FMT_FULL, 0, 8 }, 130 { "oneline", CMIT_FMT_ONELINE, 1, 0 }, 131 { "reference", CMIT_FMT_USERFORMAT, 1, 0, 132 0, DATE_SHORT, "%C(auto)%h (%s, %ad)" }, 133 /* 134 * Please update $__git_log_pretty_formats in 135 * git-completion.bash when you add new formats. 136 */ 137 }; 138 commit_formats_len = ARRAY_SIZE(builtin_formats); 139 builtin_formats_len = commit_formats_len; 140 ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc); 141 COPY_ARRAY(commit_formats, builtin_formats, 142 ARRAY_SIZE(builtin_formats)); 143 144 repo_config(the_repository, git_pretty_formats_config, NULL); 145} 146 147static struct cmt_fmt_map *find_commit_format_recursive(const char *sought, 148 const char *original, 149 int num_redirections) 150{ 151 struct cmt_fmt_map *found = NULL; 152 size_t found_match_len = 0; 153 int i; 154 155 if (num_redirections >= commit_formats_len) 156 die("invalid --pretty format: " 157 "'%s' references an alias which points to itself", 158 original); 159 160 for (i = 0; i < commit_formats_len; i++) { 161 size_t match_len; 162 163 if (!istarts_with(commit_formats[i].name, sought)) 164 continue; 165 166 match_len = strlen(commit_formats[i].name); 167 if (found == NULL || found_match_len > match_len) { 168 found = &commit_formats[i]; 169 found_match_len = match_len; 170 } 171 } 172 173 if (found && found->is_alias) { 174 found = find_commit_format_recursive(found->user_format, 175 original, 176 num_redirections+1); 177 } 178 179 return found; 180} 181 182static struct cmt_fmt_map *find_commit_format(const char *sought) 183{ 184 if (!commit_formats) 185 setup_commit_formats(); 186 187 return find_commit_format_recursive(sought, sought, 0); 188} 189 190void get_commit_format(const char *arg, struct rev_info *rev) 191{ 192 struct cmt_fmt_map *commit_format; 193 194 rev->use_terminator = 0; 195 if (!arg) { 196 rev->commit_format = CMIT_FMT_DEFAULT; 197 return; 198 } 199 if (skip_prefix(arg, "format:", &arg)) { 200 save_user_format(rev, arg, 0); 201 return; 202 } 203 204 if (!*arg || skip_prefix(arg, "tformat:", &arg) || strchr(arg, '%')) { 205 save_user_format(rev, arg, 1); 206 return; 207 } 208 209 commit_format = find_commit_format(arg); 210 if (!commit_format) 211 die("invalid --pretty format: %s", arg); 212 213 rev->commit_format = commit_format->format; 214 rev->use_terminator = commit_format->is_tformat; 215 rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log; 216 if (!rev->date_mode_explicit && commit_format->default_date_mode_type) 217 rev->date_mode.type = commit_format->default_date_mode_type; 218 if (commit_format->format == CMIT_FMT_USERFORMAT) { 219 save_user_format(rev, commit_format->user_format, 220 commit_format->is_tformat); 221 } 222} 223 224/* 225 * Generic support for pretty-printing the header 226 */ 227static int get_one_line(const char *msg) 228{ 229 int ret = 0; 230 231 for (;;) { 232 char c = *msg++; 233 if (!c) 234 break; 235 ret++; 236 if (c == '\n') 237 break; 238 } 239 return ret; 240} 241 242/* High bit set, or ISO-2022-INT */ 243static int non_ascii(int ch) 244{ 245 return !isascii(ch) || ch == '\033'; 246} 247 248int has_non_ascii(const char *s) 249{ 250 int ch; 251 if (!s) 252 return 0; 253 while ((ch = *s++) != '\0') { 254 if (non_ascii(ch)) 255 return 1; 256 } 257 return 0; 258} 259 260static int is_rfc822_special(char ch) 261{ 262 switch (ch) { 263 case '(': 264 case ')': 265 case '<': 266 case '>': 267 case '[': 268 case ']': 269 case ':': 270 case ';': 271 case '@': 272 case ',': 273 case '.': 274 case '"': 275 case '\\': 276 return 1; 277 default: 278 return 0; 279 } 280} 281 282static int needs_rfc822_quoting(const char *s, int len) 283{ 284 int i; 285 for (i = 0; i < len; i++) 286 if (is_rfc822_special(s[i])) 287 return 1; 288 return 0; 289} 290 291static int last_line_length(struct strbuf *sb) 292{ 293 int i; 294 295 /* How many bytes are already used on the last line? */ 296 for (i = sb->len - 1; i >= 0; i--) 297 if (sb->buf[i] == '\n') 298 break; 299 return sb->len - (i + 1); 300} 301 302static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) 303{ 304 int i; 305 306 /* just a guess, we may have to also backslash-quote */ 307 strbuf_grow(out, len + 2); 308 309 strbuf_addch(out, '"'); 310 for (i = 0; i < len; i++) { 311 switch (s[i]) { 312 case '"': 313 case '\\': 314 strbuf_addch(out, '\\'); 315 /* fall through */ 316 default: 317 strbuf_addch(out, s[i]); 318 } 319 } 320 strbuf_addch(out, '"'); 321} 322 323enum rfc2047_type { 324 RFC2047_SUBJECT, 325 RFC2047_ADDRESS 326}; 327 328static int is_rfc2047_special(char ch, enum rfc2047_type type) 329{ 330 /* 331 * rfc2047, section 4.2: 332 * 333 * 8-bit values which correspond to printable ASCII characters other 334 * than "=", "?", and "_" (underscore), MAY be represented as those 335 * characters. (But see section 5 for restrictions.) In 336 * particular, SPACE and TAB MUST NOT be represented as themselves 337 * within encoded words. 338 */ 339 340 /* 341 * rule out non-ASCII characters and non-printable characters (the 342 * non-ASCII check should be redundant as isprint() is not localized 343 * and only knows about ASCII, but be defensive about that) 344 */ 345 if (non_ascii(ch) || !isprint(ch)) 346 return 1; 347 348 /* 349 * rule out special printable characters (' ' should be the only 350 * whitespace character considered printable, but be defensive and use 351 * isspace()) 352 */ 353 if (isspace(ch) || ch == '=' || ch == '?' || ch == '_') 354 return 1; 355 356 /* 357 * rfc2047, section 5.3: 358 * 359 * As a replacement for a 'word' entity within a 'phrase', for example, 360 * one that precedes an address in a From, To, or Cc header. The ABNF 361 * definition for 'phrase' from RFC 822 thus becomes: 362 * 363 * phrase = 1*( encoded-word / word ) 364 * 365 * In this case the set of characters that may be used in a "Q"-encoded 366 * 'encoded-word' is restricted to: <upper and lower case ASCII 367 * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" 368 * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a 369 * 'phrase' MUST be separated from any adjacent 'word', 'text' or 370 * 'special' by 'linear-white-space'. 371 */ 372 373 if (type != RFC2047_ADDRESS) 374 return 0; 375 376 /* '=' and '_' are special cases and have been checked above */ 377 return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/'); 378} 379 380static int needs_rfc2047_encoding(const char *line, int len) 381{ 382 int i; 383 384 for (i = 0; i < len; i++) { 385 int ch = line[i]; 386 if (non_ascii(ch) || ch == '\n') 387 return 1; 388 if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) 389 return 1; 390 } 391 392 return 0; 393} 394 395static void add_rfc2047(struct strbuf *sb, const char *line, size_t len, 396 const char *encoding, enum rfc2047_type type) 397{ 398 static const int max_encoded_length = 76; /* per rfc2047 */ 399 int i; 400 int line_len = last_line_length(sb); 401 402 strbuf_grow(sb, len * 3 + strlen(encoding) + 100); 403 strbuf_addf(sb, "=?%s?q?", encoding); 404 line_len += strlen(encoding) + 5; /* 5 for =??q? */ 405 406 while (len) { 407 /* 408 * RFC 2047, section 5 (3): 409 * 410 * Each 'encoded-word' MUST represent an integral number of 411 * characters. A multi-octet character may not be split across 412 * adjacent 'encoded- word's. 413 */ 414 const unsigned char *p = (const unsigned char *)line; 415 int chrlen = mbs_chrlen(&line, &len, encoding); 416 int is_special = (chrlen > 1) || is_rfc2047_special(*p, type); 417 418 /* "=%02X" * chrlen, or the byte itself */ 419 const char *encoded_fmt = is_special ? "=%02X" : "%c"; 420 int encoded_len = is_special ? 3 * chrlen : 1; 421 422 /* 423 * According to RFC 2047, we could encode the special character 424 * ' ' (space) with '_' (underscore) for readability. But many 425 * programs do not understand this and just leave the 426 * underscore in place. Thus, we do nothing special here, which 427 * causes ' ' to be encoded as '=20', avoiding this problem. 428 */ 429 430 if (line_len + encoded_len + 2 > max_encoded_length) { 431 /* It won't fit with trailing "?=" --- break the line */ 432 strbuf_addf(sb, "?=\n =?%s?q?", encoding); 433 line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */ 434 } 435 436 for (i = 0; i < chrlen; i++) 437 strbuf_addf(sb, encoded_fmt, p[i]); 438 line_len += encoded_len; 439 } 440 strbuf_addstr(sb, "?="); 441} 442 443const char *show_ident_date(const struct ident_split *ident, 444 struct date_mode mode) 445{ 446 timestamp_t date = 0; 447 long tz = 0; 448 449 if (ident->date_begin && ident->date_end) 450 date = parse_timestamp(ident->date_begin, NULL, 10); 451 if (date_overflows(date)) 452 date = 0; 453 else { 454 if (ident->tz_begin && ident->tz_end) 455 tz = strtol(ident->tz_begin, NULL, 10); 456 if (tz >= INT_MAX || tz <= INT_MIN) 457 tz = 0; 458 } 459 return show_date(date, tz, mode); 460} 461 462static inline void strbuf_add_with_color(struct strbuf *sb, const char *color, 463 const char *buf, size_t buflen) 464{ 465 strbuf_addstr(sb, color); 466 strbuf_add(sb, buf, buflen); 467 if (*color) 468 strbuf_addstr(sb, GIT_COLOR_RESET); 469} 470 471static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt, 472 const char *line, size_t linelen, 473 enum git_colorbool color, enum grep_context ctx, 474 enum grep_header_field field) 475{ 476 const char *buf, *eol, *line_color, *match_color; 477 regmatch_t match; 478 int eflags = 0; 479 480 buf = line; 481 eol = buf + linelen; 482 483 if (!opt || !want_color(color) || opt->invert) 484 goto end; 485 486 line_color = opt->colors[GREP_COLOR_SELECTED]; 487 match_color = opt->colors[GREP_COLOR_MATCH_SELECTED]; 488 489 while (grep_next_match(opt, buf, eol, ctx, &match, field, eflags)) { 490 if (match.rm_so == match.rm_eo) 491 break; 492 493 strbuf_add_with_color(sb, line_color, buf, match.rm_so); 494 strbuf_add_with_color(sb, match_color, buf + match.rm_so, 495 match.rm_eo - match.rm_so); 496 buf += match.rm_eo; 497 eflags = REG_NOTBOL; 498 } 499 500 if (eflags) 501 strbuf_add_with_color(sb, line_color, buf, eol - buf); 502 else { 503end: 504 strbuf_add(sb, buf, eol - buf); 505 } 506} 507 508static int use_in_body_from(const struct pretty_print_context *pp, 509 const struct ident_split *ident) 510{ 511 if (pp->rev && pp->rev->force_in_body_from) 512 return 1; 513 if (ident_cmp(pp->from_ident, ident)) 514 return 1; 515 return 0; 516} 517 518void pp_user_info(struct pretty_print_context *pp, 519 const char *what, struct strbuf *sb, 520 const char *line, const char *encoding) 521{ 522 struct ident_split ident; 523 char *line_end; 524 const char *mailbuf, *namebuf; 525 size_t namelen, maillen; 526 int max_length = 78; /* per rfc2822 */ 527 528 if (pp->fmt == CMIT_FMT_ONELINE) 529 return; 530 531 line_end = strchrnul(line, '\n'); 532 if (split_ident_line(&ident, line, line_end - line)) 533 return; 534 535 mailbuf = ident.mail_begin; 536 maillen = ident.mail_end - ident.mail_begin; 537 namebuf = ident.name_begin; 538 namelen = ident.name_end - ident.name_begin; 539 540 if (pp->mailmap) 541 map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen); 542 543 if (cmit_fmt_is_mail(pp->fmt)) { 544 if (pp->from_ident && use_in_body_from(pp, &ident)) { 545 struct strbuf buf = STRBUF_INIT; 546 547 strbuf_addstr(&buf, "From: "); 548 strbuf_add(&buf, namebuf, namelen); 549 strbuf_addstr(&buf, " <"); 550 strbuf_add(&buf, mailbuf, maillen); 551 strbuf_addstr(&buf, ">\n"); 552 string_list_append(&pp->in_body_headers, 553 strbuf_detach(&buf, NULL)); 554 555 mailbuf = pp->from_ident->mail_begin; 556 maillen = pp->from_ident->mail_end - mailbuf; 557 namebuf = pp->from_ident->name_begin; 558 namelen = pp->from_ident->name_end - namebuf; 559 } 560 561 strbuf_addstr(sb, "From: "); 562 if (pp->encode_email_headers && 563 needs_rfc2047_encoding(namebuf, namelen)) { 564 add_rfc2047(sb, namebuf, namelen, 565 encoding, RFC2047_ADDRESS); 566 max_length = 76; /* per rfc2047 */ 567 } else if (needs_rfc822_quoting(namebuf, namelen)) { 568 struct strbuf quoted = STRBUF_INIT; 569 add_rfc822_quoted(&quoted, namebuf, namelen); 570 strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len, 571 -6, 1, max_length); 572 strbuf_release(&quoted); 573 } else { 574 strbuf_add_wrapped_bytes(sb, namebuf, namelen, 575 -6, 1, max_length); 576 } 577 578 if (max_length < 579 last_line_length(sb) + strlen(" <") + maillen + strlen(">")) 580 strbuf_addch(sb, '\n'); 581 strbuf_addf(sb, " <%.*s>\n", (int)maillen, mailbuf); 582 } else { 583 struct strbuf id = STRBUF_INIT; 584 enum grep_header_field field = GREP_HEADER_FIELD_MAX; 585 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL; 586 587 if (!strcmp(what, "Author")) 588 field = GREP_HEADER_AUTHOR; 589 else if (!strcmp(what, "Commit")) 590 field = GREP_HEADER_COMMITTER; 591 592 strbuf_addf(sb, "%s: ", what); 593 if (pp->fmt == CMIT_FMT_FULLER) 594 strbuf_addchars(sb, ' ', 4); 595 596 strbuf_addf(&id, "%.*s <%.*s>", (int)namelen, namebuf, 597 (int)maillen, mailbuf); 598 599 append_line_with_color(sb, opt, id.buf, id.len, pp->color, 600 GREP_CONTEXT_HEAD, field); 601 strbuf_addch(sb, '\n'); 602 strbuf_release(&id); 603 } 604 605 switch (pp->fmt) { 606 case CMIT_FMT_MEDIUM: 607 strbuf_addf(sb, "Date: %s\n", 608 show_ident_date(&ident, pp->date_mode)); 609 break; 610 case CMIT_FMT_EMAIL: 611 case CMIT_FMT_MBOXRD: 612 strbuf_addf(sb, "Date: %s\n", 613 show_ident_date(&ident, DATE_MODE(RFC2822))); 614 break; 615 case CMIT_FMT_FULLER: 616 strbuf_addf(sb, "%sDate: %s\n", what, 617 show_ident_date(&ident, pp->date_mode)); 618 break; 619 default: 620 /* notin' */ 621 break; 622 } 623} 624 625static int is_blank_line(const char *line, int *len_p) 626{ 627 int len = *len_p; 628 while (len && isspace(line[len - 1])) 629 len--; 630 *len_p = len; 631 return !len; 632} 633 634const char *skip_blank_lines(const char *msg) 635{ 636 for (;;) { 637 int linelen = get_one_line(msg); 638 int ll = linelen; 639 if (!linelen) 640 break; 641 if (!is_blank_line(msg, &ll)) 642 break; 643 msg += linelen; 644 } 645 return msg; 646} 647 648static void add_merge_info(const struct pretty_print_context *pp, 649 struct strbuf *sb, const struct commit *commit) 650{ 651 struct commit_list *parent = commit->parents; 652 653 if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) || 654 !parent || !parent->next) 655 return; 656 657 strbuf_addstr(sb, "Merge:"); 658 659 while (parent) { 660 struct object_id *oidp = &parent->item->object.oid; 661 strbuf_addch(sb, ' '); 662 if (pp->abbrev) 663 strbuf_add_unique_abbrev(sb, oidp, pp->abbrev); 664 else 665 strbuf_addstr(sb, oid_to_hex(oidp)); 666 parent = parent->next; 667 } 668 strbuf_addch(sb, '\n'); 669} 670 671static char *get_header(const char *msg, const char *key) 672{ 673 size_t len; 674 const char *v = find_commit_header(msg, key, &len); 675 return v ? xmemdupz(v, len) : NULL; 676} 677 678static char *replace_encoding_header(char *buf, const char *encoding) 679{ 680 struct strbuf tmp = STRBUF_INIT; 681 size_t start, len; 682 char *cp = buf; 683 684 /* guess if there is an encoding header before a \n\n */ 685 while (!starts_with(cp, "encoding ")) { 686 cp = strchr(cp, '\n'); 687 if (!cp || *++cp == '\n') 688 return buf; 689 } 690 start = cp - buf; 691 cp = strchr(cp, '\n'); 692 if (!cp) 693 return buf; /* should not happen but be defensive */ 694 len = cp + 1 - (buf + start); 695 696 strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); 697 if (is_encoding_utf8(encoding)) { 698 /* we have re-coded to UTF-8; drop the header */ 699 strbuf_remove(&tmp, start, len); 700 } else { 701 /* just replaces XXXX in 'encoding XXXX\n' */ 702 strbuf_splice(&tmp, start + strlen("encoding "), 703 len - strlen("encoding \n"), 704 encoding, strlen(encoding)); 705 } 706 return strbuf_detach(&tmp, NULL); 707} 708 709const char *repo_logmsg_reencode(struct repository *r, 710 const struct commit *commit, 711 char **commit_encoding, 712 const char *output_encoding) 713{ 714 static const char *utf8 = "UTF-8"; 715 const char *use_encoding; 716 char *encoding; 717 const char *msg = repo_get_commit_buffer(r, commit, NULL); 718 char *out; 719 720 if (!output_encoding || !*output_encoding) { 721 if (commit_encoding) 722 *commit_encoding = get_header(msg, "encoding"); 723 return msg; 724 } 725 encoding = get_header(msg, "encoding"); 726 if (commit_encoding) 727 *commit_encoding = encoding; 728 use_encoding = encoding ? encoding : utf8; 729 if (same_encoding(use_encoding, output_encoding)) { 730 /* 731 * No encoding work to be done. If we have no encoding header 732 * at all, then there's nothing to do, and we can return the 733 * message verbatim (whether newly allocated or not). 734 */ 735 if (!encoding) 736 return msg; 737 738 /* 739 * Otherwise, we still want to munge the encoding header in the 740 * result, which will be done by modifying the buffer. If we 741 * are using a fresh copy, we can reuse it. But if we are using 742 * the cached copy from repo_get_commit_buffer, we need to duplicate it 743 * to avoid munging the cached copy. 744 */ 745 if (msg == get_cached_commit_buffer(r, commit, NULL)) 746 out = xstrdup(msg); 747 else 748 out = (char *)msg; 749 } 750 else { 751 /* 752 * There's actual encoding work to do. Do the reencoding, which 753 * still leaves the header to be replaced in the next step. At 754 * this point, we are done with msg. If we allocated a fresh 755 * copy, we can free it. 756 */ 757 out = reencode_string(msg, output_encoding, use_encoding); 758 if (out) 759 repo_unuse_commit_buffer(r, commit, msg); 760 } 761 762 /* 763 * This replacement actually consumes the buffer we hand it, so we do 764 * not have to worry about freeing the old "out" here. 765 */ 766 if (out) 767 out = replace_encoding_header(out, output_encoding); 768 769 if (!commit_encoding) 770 free(encoding); 771 /* 772 * If the re-encoding failed, out might be NULL here; in that 773 * case we just return the commit message verbatim. 774 */ 775 return out ? out : msg; 776} 777 778static int mailmap_name(const char **email, size_t *email_len, 779 const char **name, size_t *name_len) 780{ 781 static struct string_list *mail_map; 782 if (!mail_map) { 783 CALLOC_ARRAY(mail_map, 1); 784 read_mailmap(mail_map); 785 } 786 return mail_map->nr && map_user(mail_map, email, email_len, name, name_len); 787} 788 789static size_t format_person_part(struct strbuf *sb, char part, 790 const char *msg, int len, 791 struct date_mode dmode) 792{ 793 /* currently all placeholders have same length */ 794 const int placeholder_len = 2; 795 struct ident_split s; 796 const char *name, *mail; 797 size_t maillen, namelen; 798 799 if (split_ident_line(&s, msg, len) < 0) 800 goto skip; 801 802 name = s.name_begin; 803 namelen = s.name_end - s.name_begin; 804 mail = s.mail_begin; 805 maillen = s.mail_end - s.mail_begin; 806 807 if (part == 'N' || part == 'E' || part == 'L') /* mailmap lookup */ 808 mailmap_name(&mail, &maillen, &name, &namelen); 809 if (part == 'n' || part == 'N') { /* name */ 810 strbuf_add(sb, name, namelen); 811 return placeholder_len; 812 } 813 if (part == 'e' || part == 'E') { /* email */ 814 strbuf_add(sb, mail, maillen); 815 return placeholder_len; 816 } 817 if (part == 'l' || part == 'L') { /* local-part */ 818 const char *at = memchr(mail, '@', maillen); 819 if (at) 820 maillen = at - mail; 821 strbuf_add(sb, mail, maillen); 822 return placeholder_len; 823 } 824 825 if (!s.date_begin) 826 goto skip; 827 828 if (part == 't') { /* date, UNIX timestamp */ 829 strbuf_add(sb, s.date_begin, s.date_end - s.date_begin); 830 return placeholder_len; 831 } 832 833 switch (part) { 834 case 'd': /* date */ 835 strbuf_addstr(sb, show_ident_date(&s, dmode)); 836 return placeholder_len; 837 case 'D': /* date, RFC2822 style */ 838 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RFC2822))); 839 return placeholder_len; 840 case 'r': /* date, relative */ 841 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(RELATIVE))); 842 return placeholder_len; 843 case 'i': /* date, ISO 8601-like */ 844 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601))); 845 return placeholder_len; 846 case 'I': /* date, ISO 8601 strict */ 847 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(ISO8601_STRICT))); 848 return placeholder_len; 849 case 'h': /* date, human */ 850 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(HUMAN))); 851 return placeholder_len; 852 case 's': 853 strbuf_addstr(sb, show_ident_date(&s, DATE_MODE(SHORT))); 854 return placeholder_len; 855 } 856 857skip: 858 /* 859 * reading from either a bogus commit, or a reflog entry with 860 * %gn, %ge, etc.; 'sb' cannot be updated, but we still need 861 * to compute a valid return value. 862 */ 863 if (part == 'n' || part == 'e' || part == 't' || part == 'd' 864 || part == 'D' || part == 'r' || part == 'i') 865 return placeholder_len; 866 867 return 0; /* unknown placeholder */ 868} 869 870struct chunk { 871 size_t off; 872 size_t len; 873}; 874 875enum flush_type { 876 no_flush, 877 flush_right, 878 flush_left, 879 flush_left_and_steal, 880 flush_both 881}; 882 883enum trunc_type { 884 trunc_none, 885 trunc_left, 886 trunc_middle, 887 trunc_right 888}; 889 890struct format_commit_context { 891 struct repository *repository; 892 const struct commit *commit; 893 const struct pretty_print_context *pretty_ctx; 894 unsigned commit_header_parsed:1; 895 unsigned commit_message_parsed:1; 896 struct signature_check signature_check; 897 enum flush_type flush_type; 898 enum trunc_type truncate; 899 const char *message; 900 char *commit_encoding; 901 size_t width, indent1, indent2; 902 enum git_colorbool auto_color; 903 int padding; 904 905 /* These offsets are relative to the start of the commit message. */ 906 struct chunk author; 907 struct chunk committer; 908 size_t message_off; 909 size_t subject_off; 910 size_t body_off; 911 912 /* The following ones are relative to the result struct strbuf. */ 913 size_t wrap_start; 914}; 915 916static void parse_commit_header(struct format_commit_context *context) 917{ 918 const char *msg = context->message; 919 int i; 920 921 for (i = 0; msg[i]; i++) { 922 const char *name; 923 int eol; 924 for (eol = i; msg[eol] && msg[eol] != '\n'; eol++) 925 ; /* do nothing */ 926 927 if (i == eol) { 928 break; 929 } else if (skip_prefix(msg + i, "author ", &name)) { 930 context->author.off = name - msg; 931 context->author.len = msg + eol - name; 932 } else if (skip_prefix(msg + i, "committer ", &name)) { 933 context->committer.off = name - msg; 934 context->committer.len = msg + eol - name; 935 } 936 i = eol; 937 } 938 context->message_off = i; 939 context->commit_header_parsed = 1; 940} 941 942static int istitlechar(char c) 943{ 944 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 945 (c >= '0' && c <= '9') || c == '.' || c == '_'; 946} 947 948void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len) 949{ 950 size_t trimlen; 951 size_t start_len = sb->len; 952 int space = 2; 953 int i; 954 955 for (i = 0; i < len; i++) { 956 if (istitlechar(msg[i])) { 957 if (space == 1) 958 strbuf_addch(sb, '-'); 959 space = 0; 960 strbuf_addch(sb, msg[i]); 961 if (msg[i] == '.') 962 while (msg[i+1] == '.') 963 i++; 964 } else 965 space |= 1; 966 } 967 968 /* trim any trailing '.' or '-' characters */ 969 trimlen = 0; 970 while (sb->len - trimlen > start_len && 971 (sb->buf[sb->len - 1 - trimlen] == '.' 972 || sb->buf[sb->len - 1 - trimlen] == '-')) 973 trimlen++; 974 strbuf_remove(sb, sb->len - trimlen, trimlen); 975} 976 977const char *format_subject(struct strbuf *sb, const char *msg, 978 const char *line_separator) 979{ 980 int first = 1; 981 982 for (;;) { 983 const char *line = msg; 984 int linelen = get_one_line(line); 985 986 msg += linelen; 987 if (!linelen || is_blank_line(line, &linelen)) 988 break; 989 990 if (!sb) 991 continue; 992 strbuf_grow(sb, linelen + 2); 993 if (!first) 994 strbuf_addstr(sb, line_separator); 995 strbuf_add(sb, line, linelen); 996 first = 0; 997 } 998 return msg; 999} 1000 1001static void parse_commit_message(struct format_commit_context *c) 1002{ 1003 const char *msg = c->message + c->message_off; 1004 const char *start = c->message; 1005 1006 msg = skip_blank_lines(msg); 1007 c->subject_off = msg - start; 1008 1009 msg = format_subject(NULL, msg, NULL); 1010 msg = skip_blank_lines(msg); 1011 c->body_off = msg - start; 1012 1013 c->commit_message_parsed = 1; 1014} 1015 1016static void strbuf_wrap(struct strbuf *sb, size_t pos, 1017 size_t width, size_t indent1, size_t indent2) 1018{ 1019 struct strbuf tmp = STRBUF_INIT; 1020 1021 if (pos) 1022 strbuf_add(&tmp, sb->buf, pos); 1023 strbuf_add_wrapped_text(&tmp, sb->buf + pos, 1024 cast_size_t_to_int(indent1), 1025 cast_size_t_to_int(indent2), 1026 cast_size_t_to_int(width)); 1027 strbuf_swap(&tmp, sb); 1028 strbuf_release(&tmp); 1029} 1030 1031static void rewrap_message_tail(struct strbuf *sb, 1032 struct format_commit_context *c, 1033 size_t new_width, size_t new_indent1, 1034 size_t new_indent2) 1035{ 1036 if (c->width == new_width && c->indent1 == new_indent1 && 1037 c->indent2 == new_indent2) 1038 return; 1039 if (c->wrap_start < sb->len) 1040 strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2); 1041 c->wrap_start = sb->len; 1042 c->width = new_width; 1043 c->indent1 = new_indent1; 1044 c->indent2 = new_indent2; 1045} 1046 1047static int format_reflog_person(struct strbuf *sb, 1048 char part, 1049 struct reflog_walk_info *log, 1050 struct date_mode dmode) 1051{ 1052 const char *ident; 1053 1054 if (!log) 1055 return 2; 1056 1057 ident = get_reflog_ident(log); 1058 if (!ident) 1059 return 2; 1060 1061 return format_person_part(sb, part, ident, strlen(ident), dmode); 1062} 1063 1064static size_t parse_color(struct strbuf *sb, /* in UTF-8 */ 1065 const char *placeholder, 1066 struct format_commit_context *c) 1067{ 1068 const char *rest = placeholder; 1069 const char *basic_color = NULL; 1070 1071 if (placeholder[1] == '(') { 1072 const char *begin = placeholder + 2; 1073 const char *end = strchr(begin, ')'); 1074 char color[COLOR_MAXLEN]; 1075 1076 if (!end) 1077 return 0; 1078 1079 if (skip_prefix(begin, "auto,", &begin)) { 1080 if (!want_color(c->pretty_ctx->color)) 1081 return end - placeholder + 1; 1082 } else if (skip_prefix(begin, "always,", &begin)) { 1083 /* nothing to do; we do not respect want_color at all */ 1084 } else { 1085 /* the default is the same as "auto" */ 1086 if (!want_color(c->pretty_ctx->color)) 1087 return end - placeholder + 1; 1088 } 1089 1090 if (color_parse_mem(begin, end - begin, color) < 0) 1091 die(_("unable to parse --pretty format")); 1092 strbuf_addstr(sb, color); 1093 return end - placeholder + 1; 1094 } 1095 1096 /* 1097 * We handle things like "%C(red)" above; for historical reasons, there 1098 * are a few colors that can be specified without parentheses (and 1099 * they cannot support things like "auto" or "always" at all). 1100 */ 1101 if (skip_prefix(placeholder + 1, "red", &rest)) 1102 basic_color = GIT_COLOR_RED; 1103 else if (skip_prefix(placeholder + 1, "green", &rest)) 1104 basic_color = GIT_COLOR_GREEN; 1105 else if (skip_prefix(placeholder + 1, "blue", &rest)) 1106 basic_color = GIT_COLOR_BLUE; 1107 else if (skip_prefix(placeholder + 1, "reset", &rest)) 1108 basic_color = GIT_COLOR_RESET; 1109 1110 if (basic_color && want_color(c->pretty_ctx->color)) 1111 strbuf_addstr(sb, basic_color); 1112 1113 return rest - placeholder; 1114} 1115 1116static size_t parse_padding_placeholder(const char *placeholder, 1117 struct format_commit_context *c) 1118{ 1119 const char *ch = placeholder; 1120 enum flush_type flush_type; 1121 int to_column = 0; 1122 1123 switch (*ch++) { 1124 case '<': 1125 flush_type = flush_right; 1126 break; 1127 case '>': 1128 if (*ch == '<') { 1129 flush_type = flush_both; 1130 ch++; 1131 } else if (*ch == '>') { 1132 flush_type = flush_left_and_steal; 1133 ch++; 1134 } else 1135 flush_type = flush_left; 1136 break; 1137 default: 1138 return 0; 1139 } 1140 1141 /* the next value means "wide enough to that column" */ 1142 if (*ch == '|') { 1143 to_column = 1; 1144 ch++; 1145 } 1146 1147 if (*ch == '(') { 1148 const char *start = ch + 1; 1149 const char *end = start + strcspn(start, ",)"); 1150 char *next; 1151 int width; 1152 if (!*end || end == start) 1153 return 0; 1154 width = strtol(start, &next, 10); 1155 1156 /* 1157 * We need to limit the amount of padding, or otherwise this 1158 * would allow the user to pad the buffer by arbitrarily many 1159 * bytes and thus cause resource exhaustion. 1160 */ 1161 if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT) 1162 return 0; 1163 1164 if (next == start || width == 0) 1165 return 0; 1166 if (width < 0) { 1167 if (to_column) 1168 width += term_columns(); 1169 if (width < 0) 1170 return 0; 1171 } 1172 c->padding = to_column ? -width : width; 1173 c->flush_type = flush_type; 1174 1175 if (*end == ',') { 1176 start = end + 1; 1177 end = strchr(start, ')'); 1178 if (!end || end == start) 1179 return 0; 1180 if (starts_with(start, "trunc)")) 1181 c->truncate = trunc_right; 1182 else if (starts_with(start, "ltrunc)")) 1183 c->truncate = trunc_left; 1184 else if (starts_with(start, "mtrunc)")) 1185 c->truncate = trunc_middle; 1186 else 1187 return 0; 1188 } else 1189 c->truncate = trunc_none; 1190 1191 return end - placeholder + 1; 1192 } 1193 return 0; 1194} 1195 1196static int match_placeholder_arg_value(const char *to_parse, const char *candidate, 1197 const char **end, const char **valuestart, 1198 size_t *valuelen) 1199{ 1200 const char *p; 1201 1202 if (!(skip_prefix(to_parse, candidate, &p))) 1203 return 0; 1204 if (valuestart) { 1205 if (*p == '=') { 1206 *valuestart = p + 1; 1207 *valuelen = strcspn(*valuestart, ",)"); 1208 p = *valuestart + *valuelen; 1209 } else { 1210 if (*p != ',' && *p != ')') 1211 return 0; 1212 *valuestart = NULL; 1213 *valuelen = 0; 1214 } 1215 } 1216 if (*p == ',') { 1217 *end = p + 1; 1218 return 1; 1219 } 1220 if (*p == ')') { 1221 *end = p; 1222 return 1; 1223 } 1224 return 0; 1225} 1226 1227static int match_placeholder_bool_arg(const char *to_parse, const char *candidate, 1228 const char **end, int *val) 1229{ 1230 const char *argval; 1231 char *strval; 1232 size_t arglen; 1233 int v; 1234 1235 if (!match_placeholder_arg_value(to_parse, candidate, end, &argval, &arglen)) 1236 return 0; 1237 1238 if (!argval) { 1239 *val = 1; 1240 return 1; 1241 } 1242 1243 strval = xstrndup(argval, arglen); 1244 v = git_parse_maybe_bool(strval); 1245 free(strval); 1246 1247 if (v == -1) 1248 return 0; 1249 1250 *val = v; 1251 1252 return 1; 1253} 1254 1255static int format_trailer_match_cb(const struct strbuf *key, void *ud) 1256{ 1257 const struct string_list *list = ud; 1258 const struct string_list_item *item; 1259 1260 for_each_string_list_item (item, list) { 1261 if (key->len == (uintptr_t)item->util && 1262 !strncasecmp(item->string, key->buf, key->len)) 1263 return 1; 1264 } 1265 return 0; 1266} 1267 1268static struct strbuf *expand_string_arg(struct strbuf *sb, 1269 const char *argval, size_t arglen) 1270{ 1271 char *fmt = xstrndup(argval, arglen); 1272 const char *format = fmt; 1273 1274 strbuf_reset(sb); 1275 while (strbuf_expand_step(sb, &format)) { 1276 size_t len; 1277 1278 if (skip_prefix(format, "%", &format)) 1279 strbuf_addch(sb, '%'); 1280 else if ((len = strbuf_expand_literal(sb, format))) 1281 format += len; 1282 else 1283 strbuf_addch(sb, '%'); 1284 } 1285 free(fmt); 1286 return sb; 1287} 1288 1289int format_set_trailers_options(struct process_trailer_options *opts, 1290 struct string_list *filter_list, 1291 struct strbuf *sepbuf, 1292 struct strbuf *kvsepbuf, 1293 const char **arg, 1294 char **invalid_arg) 1295{ 1296 for (;;) { 1297 const char *argval; 1298 size_t arglen; 1299 1300 if (**arg == ')') 1301 break; 1302 1303 if (match_placeholder_arg_value(*arg, "key", arg, &argval, &arglen)) { 1304 uintptr_t len = arglen; 1305 1306 if (!argval) 1307 return -1; 1308 1309 if (len && argval[len - 1] == ':') 1310 len--; 1311 string_list_append(filter_list, argval)->util = (char *)len; 1312 1313 opts->filter = format_trailer_match_cb; 1314 opts->filter_data = filter_list; 1315 opts->only_trailers = 1; 1316 } else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) { 1317 opts->separator = expand_string_arg(sepbuf, argval, arglen); 1318 } else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) { 1319 opts->key_value_separator = expand_string_arg(kvsepbuf, argval, arglen); 1320 } else if (!match_placeholder_bool_arg(*arg, "only", arg, &opts->only_trailers) && 1321 !match_placeholder_bool_arg(*arg, "unfold", arg, &opts->unfold) && 1322 !match_placeholder_bool_arg(*arg, "keyonly", arg, &opts->key_only) && 1323 !match_placeholder_bool_arg(*arg, "valueonly", arg, &opts->value_only)) { 1324 if (invalid_arg) { 1325 size_t len = strcspn(*arg, ",)"); 1326 *invalid_arg = xstrndup(*arg, len); 1327 } 1328 return -1; 1329 } 1330 } 1331 return 0; 1332} 1333 1334static size_t parse_describe_args(const char *start, struct strvec *args) 1335{ 1336 struct { 1337 const char *name; 1338 enum { 1339 DESCRIBE_ARG_BOOL, 1340 DESCRIBE_ARG_INTEGER, 1341 DESCRIBE_ARG_STRING, 1342 } type; 1343 } option[] = { 1344 { "tags", DESCRIBE_ARG_BOOL}, 1345 { "abbrev", DESCRIBE_ARG_INTEGER }, 1346 { "exclude", DESCRIBE_ARG_STRING }, 1347 { "match", DESCRIBE_ARG_STRING }, 1348 }; 1349 const char *arg = start; 1350 1351 for (;;) { 1352 int found = 0; 1353 const char *argval; 1354 size_t arglen = 0; 1355 int optval = 0; 1356 int i; 1357 1358 for (i = 0; !found && i < ARRAY_SIZE(option); i++) { 1359 switch (option[i].type) { 1360 case DESCRIBE_ARG_BOOL: 1361 if (match_placeholder_bool_arg(arg, option[i].name, &arg, &optval)) { 1362 if (optval) 1363 strvec_pushf(args, "--%s", option[i].name); 1364 else 1365 strvec_pushf(args, "--no-%s", option[i].name); 1366 found = 1; 1367 } 1368 break; 1369 case DESCRIBE_ARG_INTEGER: 1370 if (match_placeholder_arg_value(arg, option[i].name, &arg, 1371 &argval, &arglen)) { 1372 char *endptr; 1373 if (!arglen) 1374 return 0; 1375 strtol(argval, &endptr, 10); 1376 if (endptr - argval != arglen) 1377 return 0; 1378 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval); 1379 found = 1; 1380 } 1381 break; 1382 case DESCRIBE_ARG_STRING: 1383 if (match_placeholder_arg_value(arg, option[i].name, &arg, 1384 &argval, &arglen)) { 1385 if (!arglen) 1386 return 0; 1387 strvec_pushf(args, "--%s=%.*s", option[i].name, (int)arglen, argval); 1388 found = 1; 1389 } 1390 break; 1391 } 1392 } 1393 if (!found) 1394 break; 1395 1396 } 1397 return arg - start; 1398} 1399 1400 1401static int parse_decoration_option(const char **arg, 1402 const char *name, 1403 char **opt) 1404{ 1405 const char *argval; 1406 size_t arglen; 1407 1408 if (match_placeholder_arg_value(*arg, name, arg, &argval, &arglen)) { 1409 struct strbuf sb = STRBUF_INIT; 1410 1411 expand_string_arg(&sb, argval, arglen); 1412 *opt = strbuf_detach(&sb, NULL); 1413 return 1; 1414 } 1415 return 0; 1416} 1417 1418static void parse_decoration_options(const char **arg, 1419 struct decoration_options *opts) 1420{ 1421 while (parse_decoration_option(arg, "prefix", &opts->prefix) || 1422 parse_decoration_option(arg, "suffix", &opts->suffix) || 1423 parse_decoration_option(arg, "separator", &opts->separator) || 1424 parse_decoration_option(arg, "pointer", &opts->pointer) || 1425 parse_decoration_option(arg, "tag", &opts->tag)) 1426 ; 1427} 1428 1429static void free_decoration_options(const struct decoration_options *opts) 1430{ 1431 free(opts->prefix); 1432 free(opts->suffix); 1433 free(opts->separator); 1434 free(opts->pointer); 1435 free(opts->tag); 1436} 1437 1438static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ 1439 const char *placeholder, 1440 void *context) 1441{ 1442 struct format_commit_context *c = context; 1443 const struct commit *commit = c->commit; 1444 const char *msg = c->message; 1445 struct commit_list *p; 1446 const char *arg, *eol; 1447 size_t res; 1448 char **slot; 1449 1450 /* these are independent of the commit */ 1451 res = strbuf_expand_literal(sb, placeholder); 1452 if (res) 1453 return res; 1454 1455 switch (placeholder[0]) { 1456 case 'C': 1457 if (starts_with(placeholder + 1, "(auto)")) { 1458 c->auto_color = c->pretty_ctx->color; 1459 if (want_color(c->auto_color) && sb->len) 1460 strbuf_addstr(sb, GIT_COLOR_RESET); 1461 return 7; /* consumed 7 bytes, "C(auto)" */ 1462 } else { 1463 int ret = parse_color(sb, placeholder, c); 1464 if (ret) 1465 c->auto_color = GIT_COLOR_NEVER; 1466 /* 1467 * Otherwise, we decided to treat %C<unknown> 1468 * as a literal string, and the previous 1469 * %C(auto) is still valid. 1470 */ 1471 return ret; 1472 } 1473 case 'w': 1474 if (placeholder[1] == '(') { 1475 unsigned long width = 0, indent1 = 0, indent2 = 0; 1476 char *next; 1477 const char *start = placeholder + 2; 1478 const char *end = strchr(start, ')'); 1479 if (!end) 1480 return 0; 1481 if (end > start) { 1482 width = strtoul(start, &next, 10); 1483 if (*next == ',') { 1484 indent1 = strtoul(next + 1, &next, 10); 1485 if (*next == ',') { 1486 indent2 = strtoul(next + 1, 1487 &next, 10); 1488 } 1489 } 1490 if (*next != ')') 1491 return 0; 1492 } 1493 1494 /* 1495 * We need to limit the format here as it allows the 1496 * user to prepend arbitrarily many bytes to the buffer 1497 * when rewrapping. 1498 */ 1499 if (width > FORMATTING_LIMIT || 1500 indent1 > FORMATTING_LIMIT || 1501 indent2 > FORMATTING_LIMIT) 1502 return 0; 1503 rewrap_message_tail(sb, c, width, indent1, indent2); 1504 return end - placeholder + 1; 1505 } else 1506 return 0; 1507 1508 case '<': 1509 case '>': 1510 return parse_padding_placeholder(placeholder, c); 1511 } 1512 1513 if (skip_prefix(placeholder, "(describe", &arg)) { 1514 struct child_process cmd = CHILD_PROCESS_INIT; 1515 struct strbuf out = STRBUF_INIT; 1516 struct strbuf err = STRBUF_INIT; 1517 struct pretty_print_describe_status *describe_status; 1518 1519 describe_status = c->pretty_ctx->describe_status; 1520 if (describe_status) { 1521 if (!describe_status->max_invocations) 1522 return 0; 1523 describe_status->max_invocations--; 1524 } 1525 1526 cmd.git_cmd = 1; 1527 strvec_push(&cmd.args, "describe"); 1528 1529 if (*arg == ':') { 1530 arg++; 1531 arg += parse_describe_args(arg, &cmd.args); 1532 } 1533 1534 if (*arg != ')') { 1535 child_process_clear(&cmd); 1536 return 0; 1537 } 1538 1539 strvec_push(&cmd.args, oid_to_hex(&commit->object.oid)); 1540 pipe_command(&cmd, NULL, 0, &out, 0, &err, 0); 1541 strbuf_rtrim(&out); 1542 strbuf_addbuf(sb, &out); 1543 strbuf_release(&out); 1544 strbuf_release(&err); 1545 return arg - placeholder + 1; 1546 } 1547 1548 /* these depend on the commit */ 1549 if (!commit->object.parsed) 1550 parse_object(the_repository, &commit->object.oid); 1551 1552 switch (placeholder[0]) { 1553 case 'H': /* commit hash */ 1554 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT)); 1555 strbuf_addstr(sb, oid_to_hex(&commit->object.oid)); 1556 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET)); 1557 return 1; 1558 case 'h': /* abbreviated commit hash */ 1559 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT)); 1560 strbuf_add_unique_abbrev(sb, &commit->object.oid, 1561 c->pretty_ctx->abbrev); 1562 strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET)); 1563 return 1; 1564 case 'T': /* tree hash */ 1565 strbuf_addstr(sb, oid_to_hex(get_commit_tree_oid(commit))); 1566 return 1; 1567 case 't': /* abbreviated tree hash */ 1568 strbuf_add_unique_abbrev(sb, 1569 get_commit_tree_oid(commit), 1570 c->pretty_ctx->abbrev); 1571 return 1; 1572 case 'P': /* parent hashes */ 1573 for (p = commit->parents; p; p = p->next) { 1574 if (p != commit->parents) 1575 strbuf_addch(sb, ' '); 1576 strbuf_addstr(sb, oid_to_hex(&p->item->object.oid)); 1577 } 1578 return 1; 1579 case 'p': /* abbreviated parent hashes */ 1580 for (p = commit->parents; p; p = p->next) { 1581 if (p != commit->parents) 1582 strbuf_addch(sb, ' '); 1583 strbuf_add_unique_abbrev(sb, &p->item->object.oid, 1584 c->pretty_ctx->abbrev); 1585 } 1586 return 1; 1587 case 'm': /* left/right/bottom */ 1588 strbuf_addstr(sb, get_revision_mark(NULL, commit)); 1589 return 1; 1590 case 'd': 1591 format_decorations(sb, commit, c->auto_color, NULL); 1592 return 1; 1593 case 'D': 1594 { 1595 const struct decoration_options opts = { 1596 .prefix = (char *) "", 1597 .suffix = (char *) "", 1598 }; 1599 1600 format_decorations(sb, commit, c->auto_color, &opts); 1601 return 1; 1602 } 1603 case 'S': /* tag/branch like --source */ 1604 if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources)) 1605 return 0; 1606 slot = revision_sources_at(c->pretty_ctx->rev->sources, commit); 1607 if (!(slot && *slot)) 1608 return 0; 1609 strbuf_addstr(sb, *slot); 1610 return 1; 1611 case 'g': /* reflog info */ 1612 switch(placeholder[1]) { 1613 case 'd': /* reflog selector */ 1614 case 'D': 1615 if (c->pretty_ctx->reflog_info) 1616 get_reflog_selector(sb, 1617 c->pretty_ctx->reflog_info, 1618 c->pretty_ctx->date_mode, 1619 c->pretty_ctx->date_mode_explicit, 1620 (placeholder[1] == 'd')); 1621 return 2; 1622 case 's': /* reflog message */ 1623 if (c->pretty_ctx->reflog_info) 1624 get_reflog_message(sb, c->pretty_ctx->reflog_info); 1625 return 2; 1626 case 'n': 1627 case 'N': 1628 case 'e': 1629 case 'E': 1630 return format_reflog_person(sb, 1631 placeholder[1], 1632 c->pretty_ctx->reflog_info, 1633 c->pretty_ctx->date_mode); 1634 } 1635 return 0; /* unknown %g placeholder */ 1636 case 'N': 1637 if (c->pretty_ctx->notes_message) { 1638 strbuf_addstr(sb, c->pretty_ctx->notes_message); 1639 return 1; 1640 } 1641 return 0; 1642 } 1643 1644 if (placeholder[0] == 'G') { 1645 if (!c->signature_check.result) 1646 check_commit_signature(c->commit, &(c->signature_check)); 1647 switch (placeholder[1]) { 1648 case 'G': 1649 if (c->signature_check.output) 1650 strbuf_addstr(sb, c->signature_check.output); 1651 break; 1652 case '?': 1653 switch (c->signature_check.result) { 1654 case 'G': 1655 switch (c->signature_check.trust_level) { 1656 case TRUST_UNDEFINED: 1657 case TRUST_NEVER: 1658 strbuf_addch(sb, 'U'); 1659 break; 1660 default: 1661 strbuf_addch(sb, 'G'); 1662 break; 1663 } 1664 break; 1665 case 'B': 1666 case 'E': 1667 case 'N': 1668 case 'X': 1669 case 'Y': 1670 case 'R': 1671 strbuf_addch(sb, c->signature_check.result); 1672 } 1673 break; 1674 case 'S': 1675 if (c->signature_check.signer) 1676 strbuf_addstr(sb, c->signature_check.signer); 1677 break; 1678 case 'K': 1679 if (c->signature_check.key) 1680 strbuf_addstr(sb, c->signature_check.key); 1681 break; 1682 case 'F': 1683 if (c->signature_check.fingerprint) 1684 strbuf_addstr(sb, c->signature_check.fingerprint); 1685 break; 1686 case 'P': 1687 if (c->signature_check.primary_key_fingerprint) 1688 strbuf_addstr(sb, c->signature_check.primary_key_fingerprint); 1689 break; 1690 case 'T': 1691 strbuf_addstr(sb, gpg_trust_level_to_str(c->signature_check.trust_level)); 1692 break; 1693 default: 1694 return 0; 1695 } 1696 return 2; 1697 } 1698 1699 if (skip_prefix(placeholder, "(decorate", &arg)) { 1700 struct decoration_options opts = { NULL }; 1701 size_t ret = 0; 1702 1703 if (*arg == ':') { 1704 arg++; 1705 parse_decoration_options(&arg, &opts); 1706 } 1707 if (*arg == ')') { 1708 format_decorations(sb, commit, c->auto_color, &opts); 1709 ret = arg - placeholder + 1; 1710 } 1711 1712 free_decoration_options(&opts); 1713 return ret; 1714 } 1715 1716 /* For the rest we have to parse the commit header. */ 1717 if (!c->commit_header_parsed) { 1718 msg = c->message = 1719 repo_logmsg_reencode(c->repository, commit, 1720 &c->commit_encoding, "UTF-8"); 1721 parse_commit_header(c); 1722 } 1723 1724 switch (placeholder[0]) { 1725 case 'a': /* author ... */ 1726 return format_person_part(sb, placeholder[1], 1727 msg + c->author.off, c->author.len, 1728 c->pretty_ctx->date_mode); 1729 case 'c': /* committer ... */ 1730 return format_person_part(sb, placeholder[1], 1731 msg + c->committer.off, c->committer.len, 1732 c->pretty_ctx->date_mode); 1733 case 'e': /* encoding */ 1734 if (c->commit_encoding) 1735 strbuf_addstr(sb, c->commit_encoding); 1736 return 1; 1737 case 'B': /* raw body */ 1738 /* message_off is always left at the initial newline */ 1739 strbuf_addstr(sb, msg + c->message_off + 1); 1740 return 1; 1741 } 1742 1743 /* Now we need to parse the commit message. */ 1744 if (!c->commit_message_parsed) 1745 parse_commit_message(c); 1746 1747 switch (placeholder[0]) { 1748 case 's': /* subject */ 1749 format_subject(sb, msg + c->subject_off, " "); 1750 return 1; 1751 case 'f': /* sanitized subject */ 1752 eol = strchrnul(msg + c->subject_off, '\n'); 1753 format_sanitized_subject(sb, msg + c->subject_off, eol - (msg + c->subject_off)); 1754 return 1; 1755 case 'b': /* body */ 1756 strbuf_addstr(sb, msg + c->body_off); 1757 return 1; 1758 } 1759 1760 if (skip_prefix(placeholder, "(trailers", &arg)) { 1761 struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; 1762 struct string_list filter_list = STRING_LIST_INIT_NODUP; 1763 struct strbuf sepbuf = STRBUF_INIT; 1764 struct strbuf kvsepbuf = STRBUF_INIT; 1765 size_t ret = 0; 1766 1767 opts.no_divider = 1; 1768 1769 if (*arg == ':') { 1770 arg++; 1771 if (format_set_trailers_options(&opts, &filter_list, &sepbuf, &kvsepbuf, &arg, NULL)) 1772 goto trailer_out; 1773 } 1774 if (*arg == ')') { 1775 format_trailers_from_commit(&opts, msg + c->subject_off, sb); 1776 ret = arg - placeholder + 1; 1777 } 1778 trailer_out: 1779 string_list_clear(&filter_list, 0); 1780 strbuf_release(&kvsepbuf); 1781 strbuf_release(&sepbuf); 1782 return ret; 1783 } 1784 1785 return 0; /* unknown placeholder */ 1786} 1787 1788static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ 1789 const char *placeholder, 1790 struct format_commit_context *c) 1791{ 1792 struct strbuf local_sb = STRBUF_INIT; 1793 size_t total_consumed = 0; 1794 int len, padding = c->padding; 1795 1796 if (padding < 0) { 1797 const char *start = strrchr(sb->buf, '\n'); 1798 int occupied; 1799 if (!start) 1800 start = sb->buf; 1801 occupied = utf8_strnwidth(start, strlen(start), 1); 1802 occupied += c->pretty_ctx->graph_width; 1803 padding = (-padding) - occupied; 1804 } 1805 while (1) { 1806 int modifier = *placeholder == 'C'; 1807 size_t consumed = format_commit_one(&local_sb, placeholder, c); 1808 total_consumed += consumed; 1809 1810 if (!modifier) 1811 break; 1812 1813 placeholder += consumed; 1814 if (*placeholder != '%') 1815 break; 1816 placeholder++; 1817 total_consumed++; 1818 } 1819 len = utf8_strnwidth(local_sb.buf, local_sb.len, 1); 1820 1821 if (c->flush_type == flush_left_and_steal) { 1822 const char *ch = sb->buf + sb->len - 1; 1823 while (len > padding && ch > sb->buf) { 1824 const char *p; 1825 if (*ch == ' ') { 1826 ch--; 1827 padding++; 1828 continue; 1829 } 1830 /* check for trailing ansi sequences */ 1831 if (*ch != 'm') 1832 break; 1833 p = ch - 1; 1834 while (p > sb->buf && ch - p < 10 && *p != '\033') 1835 p--; 1836 if (*p != '\033' || 1837 ch + 1 - p != display_mode_esc_sequence_len(p)) 1838 break; 1839 /* 1840 * got a good ansi sequence, put it back to 1841 * local_sb as we're cutting sb 1842 */ 1843 strbuf_insert(&local_sb, 0, p, ch + 1 - p); 1844 ch = p - 1; 1845 } 1846 strbuf_setlen(sb, ch + 1 - sb->buf); 1847 c->flush_type = flush_left; 1848 } 1849 1850 if (len > padding) { 1851 switch (c->truncate) { 1852 case trunc_left: 1853 strbuf_utf8_replace(&local_sb, 1854 0, len - (padding - 2), 1855 ".."); 1856 break; 1857 case trunc_middle: 1858 strbuf_utf8_replace(&local_sb, 1859 padding / 2 - 1, 1860 len - (padding - 2), 1861 ".."); 1862 break; 1863 case trunc_right: 1864 strbuf_utf8_replace(&local_sb, 1865 padding - 2, len - (padding - 2), 1866 ".."); 1867 break; 1868 case trunc_none: 1869 break; 1870 } 1871 strbuf_addbuf(sb, &local_sb); 1872 } else { 1873 size_t sb_len = sb->len, offset = 0; 1874 if (c->flush_type == flush_left) 1875 offset = padding - len; 1876 else if (c->flush_type == flush_both) 1877 offset = (padding - len) / 2; 1878 /* 1879 * we calculate padding in columns, now 1880 * convert it back to chars 1881 */ 1882 padding = padding - len + local_sb.len; 1883 strbuf_addchars(sb, ' ', padding); 1884 memcpy(sb->buf + sb_len + offset, local_sb.buf, 1885 local_sb.len); 1886 } 1887 strbuf_release(&local_sb); 1888 c->flush_type = no_flush; 1889 return total_consumed; 1890} 1891 1892static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */ 1893 const char *placeholder, 1894 struct format_commit_context *context) 1895{ 1896 size_t consumed, orig_len; 1897 enum { 1898 NO_MAGIC, 1899 ADD_LF_BEFORE_NON_EMPTY, 1900 DEL_LF_BEFORE_EMPTY, 1901 ADD_SP_BEFORE_NON_EMPTY 1902 } magic = NO_MAGIC; 1903 1904 switch (placeholder[0]) { 1905 case '-': 1906 magic = DEL_LF_BEFORE_EMPTY; 1907 break; 1908 case '+': 1909 magic = ADD_LF_BEFORE_NON_EMPTY; 1910 break; 1911 case ' ': 1912 magic = ADD_SP_BEFORE_NON_EMPTY; 1913 break; 1914 default: 1915 break; 1916 } 1917 if (magic != NO_MAGIC) { 1918 placeholder++; 1919 1920 switch (placeholder[0]) { 1921 case 'w': 1922 /* 1923 * `%+w()` cannot ever expand to a non-empty string, 1924 * and it potentially changes the layout of preceding 1925 * contents. We're thus not able to handle the magic in 1926 * this combination and refuse the pattern. 1927 */ 1928 return 0; 1929 }; 1930 } 1931 1932 orig_len = sb->len; 1933 if (context->flush_type == no_flush) 1934 consumed = format_commit_one(sb, placeholder, context); 1935 else 1936 consumed = format_and_pad_commit(sb, placeholder, context); 1937 if (magic == NO_MAGIC) 1938 return consumed; 1939 1940 if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) { 1941 while (sb->len && sb->buf[sb->len - 1] == '\n') 1942 strbuf_setlen(sb, sb->len - 1); 1943 } else if (orig_len != sb->len) { 1944 if (magic == ADD_LF_BEFORE_NON_EMPTY) 1945 strbuf_insertstr(sb, orig_len, "\n"); 1946 else if (magic == ADD_SP_BEFORE_NON_EMPTY) 1947 strbuf_insertstr(sb, orig_len, " "); 1948 } 1949 return consumed + 1; 1950} 1951 1952void userformat_find_requirements(const char *fmt, struct userformat_want *w) 1953{ 1954 if (!fmt) { 1955 if (!user_format) 1956 return; 1957 fmt = user_format; 1958 } 1959 while ((fmt = strchr(fmt, '%'))) { 1960 fmt++; 1961 if (skip_prefix(fmt, "%", &fmt)) 1962 continue; 1963 1964 if (*fmt == '+' || *fmt == '-' || *fmt == ' ') 1965 fmt++; 1966 1967 switch (*fmt) { 1968 case 'N': 1969 w->notes = 1; 1970 break; 1971 case 'S': 1972 w->source = 1; 1973 break; 1974 case 'd': 1975 case 'D': 1976 w->decorate = 1; 1977 break; 1978 case '(': 1979 if (starts_with(fmt + 1, "decorate")) 1980 w->decorate = 1; 1981 break; 1982 } 1983 } 1984} 1985 1986void repo_format_commit_message(struct repository *r, 1987 const struct commit *commit, 1988 const char *format, struct strbuf *sb, 1989 const struct pretty_print_context *pretty_ctx) 1990{ 1991 struct format_commit_context context = { 1992 .repository = r, 1993 .commit = commit, 1994 .pretty_ctx = pretty_ctx, 1995 .wrap_start = sb->len 1996 }; 1997 const char *output_enc = pretty_ctx->output_encoding; 1998 const char *utf8 = "UTF-8"; 1999 2000 while (strbuf_expand_step(sb, &format)) { 2001 size_t len; 2002 2003 if (skip_prefix(format, "%", &format)) 2004 strbuf_addch(sb, '%'); 2005 else if ((len = format_commit_item(sb, format, &context))) 2006 format += len; 2007 else 2008 strbuf_addch(sb, '%'); 2009 } 2010 rewrap_message_tail(sb, &context, 0, 0, 0); 2011 2012 /* 2013 * Convert output to an actual output encoding; note that 2014 * format_commit_item() will always use UTF-8, so we don't 2015 * have to bother if that's what the output wants. 2016 */ 2017 if (output_enc) { 2018 if (same_encoding(utf8, output_enc)) 2019 output_enc = NULL; 2020 } else { 2021 if (context.commit_encoding && 2022 !same_encoding(context.commit_encoding, utf8)) 2023 output_enc = context.commit_encoding; 2024 } 2025 2026 if (output_enc) { 2027 size_t outsz; 2028 char *out = reencode_string_len(sb->buf, sb->len, 2029 output_enc, utf8, &outsz); 2030 if (out) 2031 strbuf_attach(sb, out, outsz, outsz + 1); 2032 } 2033 2034 free(context.commit_encoding); 2035 repo_unuse_commit_buffer(r, commit, context.message); 2036 signature_check_clear(&context.signature_check); 2037} 2038 2039static void pp_header(struct pretty_print_context *pp, 2040 const char *encoding, 2041 const struct commit *commit, 2042 const char **msg_p, 2043 struct strbuf *sb) 2044{ 2045 int parents_shown = 0; 2046 2047 for (;;) { 2048 const char *name, *line = *msg_p; 2049 int linelen = get_one_line(*msg_p); 2050 2051 if (!linelen) 2052 return; 2053 *msg_p += linelen; 2054 2055 if (linelen == 1) 2056 /* End of header */ 2057 return; 2058 2059 if (pp->fmt == CMIT_FMT_RAW) { 2060 strbuf_add(sb, line, linelen); 2061 continue; 2062 } 2063 2064 if (starts_with(line, "parent ")) { 2065 if (linelen != the_hash_algo->hexsz + 8) 2066 die("bad parent line in commit"); 2067 continue; 2068 } 2069 2070 if (!parents_shown) { 2071 unsigned num = commit_list_count(commit->parents); 2072 /* with enough slop */ 2073 strbuf_grow(sb, num * (GIT_MAX_HEXSZ + 10) + 20); 2074 add_merge_info(pp, sb, commit); 2075 parents_shown = 1; 2076 } 2077 2078 /* 2079 * MEDIUM == DEFAULT shows only author with dates. 2080 * FULL shows both authors but not dates. 2081 * FULLER shows both authors and dates. 2082 */ 2083 if (skip_prefix(line, "author ", &name)) { 2084 strbuf_grow(sb, linelen + 80); 2085 pp_user_info(pp, "Author", sb, name, encoding); 2086 } 2087 if (skip_prefix(line, "committer ", &name) && 2088 (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) { 2089 strbuf_grow(sb, linelen + 80); 2090 pp_user_info(pp, "Commit", sb, name, encoding); 2091 } 2092 } 2093} 2094 2095void pp_email_subject(struct pretty_print_context *pp, 2096 const char **msg_p, 2097 struct strbuf *sb, 2098 const char *encoding, 2099 int need_8bit_cte) 2100{ 2101 static const int max_length = 78; /* per rfc2047 */ 2102 struct strbuf title; 2103 2104 strbuf_init(&title, 80); 2105 *msg_p = format_subject(&title, *msg_p, 2106 pp->preserve_subject ? "\n" : " "); 2107 2108 strbuf_grow(sb, title.len + 1024); 2109 fmt_output_email_subject(sb, pp->rev); 2110 if (pp->encode_email_headers && 2111 needs_rfc2047_encoding(title.buf, title.len)) 2112 add_rfc2047(sb, title.buf, title.len, 2113 encoding, RFC2047_SUBJECT); 2114 else 2115 strbuf_add_wrapped_bytes(sb, title.buf, title.len, 2116 -last_line_length(sb), 1, max_length); 2117 strbuf_addch(sb, '\n'); 2118 2119 if (need_8bit_cte == 0) { 2120 int i; 2121 for (i = 0; i < pp->in_body_headers.nr; i++) { 2122 if (has_non_ascii(pp->in_body_headers.items[i].string)) { 2123 need_8bit_cte = 1; 2124 break; 2125 } 2126 } 2127 } 2128 2129 if (need_8bit_cte > 0) { 2130 const char *header_fmt = 2131 "MIME-Version: 1.0\n" 2132 "Content-Type: text/plain; charset=%s\n" 2133 "Content-Transfer-Encoding: 8bit\n"; 2134 strbuf_addf(sb, header_fmt, encoding); 2135 } 2136 if (pp->after_subject) { 2137 strbuf_addstr(sb, pp->after_subject); 2138 } 2139 2140 strbuf_addch(sb, '\n'); 2141 2142 if (pp->in_body_headers.nr) { 2143 int i; 2144 for (i = 0; i < pp->in_body_headers.nr; i++) { 2145 strbuf_addstr(sb, pp->in_body_headers.items[i].string); 2146 free(pp->in_body_headers.items[i].string); 2147 } 2148 string_list_clear(&pp->in_body_headers, 0); 2149 strbuf_addch(sb, '\n'); 2150 } 2151 2152 strbuf_release(&title); 2153} 2154 2155static int pp_utf8_width(const char *start, const char *end) 2156{ 2157 int width = 0; 2158 size_t remain = end - start; 2159 2160 while (remain) { 2161 int n = utf8_width(&start, &remain); 2162 if (n < 0 || !start) 2163 return -1; 2164 width += n; 2165 } 2166 return width; 2167} 2168 2169static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt, 2170 enum git_colorbool color, int tabwidth, const char *line, 2171 int linelen) 2172{ 2173 const char *tab; 2174 2175 while ((tab = memchr(line, '\t', linelen)) != NULL) { 2176 int width = pp_utf8_width(line, tab); 2177 2178 /* 2179 * If it wasn't well-formed utf8, or it 2180 * had characters with badly defined 2181 * width (control characters etc), just 2182 * give up on trying to align things. 2183 */ 2184 if (width < 0) 2185 break; 2186 2187 /* Output the data .. */ 2188 append_line_with_color(sb, opt, line, tab - line, color, 2189 GREP_CONTEXT_BODY, 2190 GREP_HEADER_FIELD_MAX); 2191 2192 /* .. and the de-tabified tab */ 2193 strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth)); 2194 2195 /* Skip over the printed part .. */ 2196 linelen -= tab + 1 - line; 2197 line = tab + 1; 2198 } 2199 2200 /* 2201 * Print out everything after the last tab without 2202 * worrying about width - there's nothing more to 2203 * align. 2204 */ 2205 append_line_with_color(sb, opt, line, linelen, color, GREP_CONTEXT_BODY, 2206 GREP_HEADER_FIELD_MAX); 2207} 2208 2209/* 2210 * pp_handle_indent() prints out the indentation, and 2211 * the whole line (without the final newline), after 2212 * de-tabifying. 2213 */ 2214static void pp_handle_indent(struct pretty_print_context *pp, 2215 struct strbuf *sb, int indent, 2216 const char *line, int linelen) 2217{ 2218 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL; 2219 2220 strbuf_addchars(sb, ' ', indent); 2221 if (pp->expand_tabs_in_log) 2222 strbuf_add_tabexpand(sb, opt, pp->color, pp->expand_tabs_in_log, 2223 line, linelen); 2224 else 2225 append_line_with_color(sb, opt, line, linelen, pp->color, 2226 GREP_CONTEXT_BODY, 2227 GREP_HEADER_FIELD_MAX); 2228} 2229 2230static int is_mboxrd_from(const char *line, int len) 2231{ 2232 /* 2233 * a line matching /^From $/ here would only have len == 4 2234 * at this point because is_empty_line would've trimmed all 2235 * trailing space 2236 */ 2237 return len > 4 && starts_with(line + strspn(line, ">"), "From "); 2238} 2239 2240void pp_remainder(struct pretty_print_context *pp, 2241 const char **msg_p, 2242 struct strbuf *sb, 2243 int indent) 2244{ 2245 struct grep_opt *opt = pp->rev ? &pp->rev->grep_filter : NULL; 2246 int first = 1; 2247 2248 for (;;) { 2249 const char *line = *msg_p; 2250 int linelen = get_one_line(line); 2251 *msg_p += linelen; 2252 2253 if (!linelen) 2254 break; 2255 2256 if (is_blank_line(line, &linelen)) { 2257 if (first) 2258 continue; 2259 if (pp->fmt == CMIT_FMT_SHORT) 2260 break; 2261 } 2262 first = 0; 2263 2264 strbuf_grow(sb, linelen + indent + 20); 2265 if (indent) 2266 pp_handle_indent(pp, sb, indent, line, linelen); 2267 else if (pp->expand_tabs_in_log) 2268 strbuf_add_tabexpand(sb, opt, pp->color, 2269 pp->expand_tabs_in_log, line, 2270 linelen); 2271 else { 2272 if (pp->fmt == CMIT_FMT_MBOXRD && 2273 is_mboxrd_from(line, linelen)) 2274 strbuf_addch(sb, '>'); 2275 2276 append_line_with_color(sb, opt, line, linelen, 2277 pp->color, GREP_CONTEXT_BODY, 2278 GREP_HEADER_FIELD_MAX); 2279 } 2280 strbuf_addch(sb, '\n'); 2281 } 2282} 2283 2284void pretty_print_commit(struct pretty_print_context *pp, 2285 const struct commit *commit, 2286 struct strbuf *sb) 2287{ 2288 unsigned long beginning_of_body; 2289 int indent = 4; 2290 const char *msg; 2291 const char *reencoded; 2292 const char *encoding; 2293 int need_8bit_cte = pp->need_8bit_cte; 2294 2295 if (pp->fmt == CMIT_FMT_USERFORMAT) { 2296 repo_format_commit_message(the_repository, commit, 2297 user_format, sb, pp); 2298 return; 2299 } 2300 2301 encoding = get_log_output_encoding(); 2302 msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL, 2303 encoding); 2304 2305 if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt)) 2306 indent = 0; 2307 2308 /* 2309 * We need to check and emit Content-type: to mark it 2310 * as 8-bit if we haven't done so. 2311 */ 2312 if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) { 2313 int i, ch, in_body; 2314 2315 for (in_body = i = 0; (ch = msg[i]); i++) { 2316 if (!in_body) { 2317 /* author could be non 7-bit ASCII but 2318 * the log may be so; skip over the 2319 * header part first. 2320 */ 2321 if (ch == '\n' && msg[i+1] == '\n') 2322 in_body = 1; 2323 } 2324 else if (non_ascii(ch)) { 2325 need_8bit_cte = 1; 2326 break; 2327 } 2328 } 2329 } 2330 2331 pp_header(pp, encoding, commit, &msg, sb); 2332 if (pp->fmt != CMIT_FMT_ONELINE && !cmit_fmt_is_mail(pp->fmt)) { 2333 strbuf_addch(sb, '\n'); 2334 } 2335 2336 /* Skip excess blank lines at the beginning of body, if any... */ 2337 msg = skip_blank_lines(msg); 2338 2339 /* These formats treat the title line specially. */ 2340 if (pp->fmt == CMIT_FMT_ONELINE) { 2341 msg = format_subject(sb, msg, " "); 2342 strbuf_addch(sb, '\n'); 2343 } else if (cmit_fmt_is_mail(pp->fmt)) 2344 pp_email_subject(pp, &msg, sb, encoding, need_8bit_cte); 2345 2346 beginning_of_body = sb->len; 2347 if (pp->fmt != CMIT_FMT_ONELINE) 2348 pp_remainder(pp, &msg, sb, indent); 2349 strbuf_rtrim(sb); 2350 2351 /* Make sure there is an EOLN for the non-oneline case */ 2352 if (pp->fmt != CMIT_FMT_ONELINE) 2353 strbuf_addch(sb, '\n'); 2354 2355 /* 2356 * The caller may append additional body text in e-mail 2357 * format. Make sure we did not strip the blank line 2358 * between the header and the body. 2359 */ 2360 if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body) 2361 strbuf_addch(sb, '\n'); 2362 2363 repo_unuse_commit_buffer(the_repository, commit, reencoded); 2364} 2365 2366void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit, 2367 struct strbuf *sb) 2368{ 2369 struct pretty_print_context pp = {0}; 2370 pp.fmt = fmt; 2371 pretty_print_commit(&pp, commit, sb); 2372}