Merge branch 'rs/pp-user-info-without-extra-allocation'
authorJunio C Hamano <gitster@pobox.com>
Wed, 1 May 2013 22:24:08 +0000 (15:24 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 1 May 2013 22:24:08 +0000 (15:24 -0700)
* rs/pp-user-info-without-extra-allocation:
pretty: remove intermediate strbufs from pp_user_info()
pretty: simplify output line length calculation in pp_user_info()
pretty: simplify input line length calculation in pp_user_info()

1  2 
pretty.c
diff --combined pretty.c
index ba3148181eff960ff6de68cafffe77e37719fd1d,0530abfa727df91b42395a08cd94fd4634a6207e..9e431545d8e6c14401faea5e76296974ca1d6649
+++ b/pretty.c
@@@ -410,10 -410,7 +410,7 @@@ void pp_user_info(const struct pretty_p
                  const char *what, struct strbuf *sb,
                  const char *line, const char *encoding)
  {
-       struct strbuf name;
-       struct strbuf mail;
        struct ident_split ident;
-       int linelen;
        char *line_end;
        const char *mailbuf, *namebuf;
        size_t namelen, maillen;
        if (pp->fmt == CMIT_FMT_ONELINE)
                return;
  
-       line_end = strchr(line, '\n');
-       if (!line_end) {
-               line_end = strchr(line, '\0');
-               if (!line_end)
-                       return;
-       }
-       linelen = ++line_end - line;
-       if (split_ident_line(&ident, line, linelen))
+       line_end = strchrnul(line, '\n');
+       if (split_ident_line(&ident, line, line_end - line))
                return;
  
        mailbuf = ident.mail_begin;
        maillen = ident.mail_end - ident.mail_begin;
        namebuf = ident.name_begin;
        if (pp->mailmap)
                map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
  
-       strbuf_init(&mail, 0);
-       strbuf_init(&name, 0);
-       strbuf_add(&mail, mailbuf, maillen);
-       strbuf_add(&name, namebuf, namelen);
-       namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
        if (pp->fmt == CMIT_FMT_EMAIL) {
                strbuf_addstr(sb, "From: ");
-               if (needs_rfc2047_encoding(name.buf, name.len, RFC2047_ADDRESS)) {
-                       add_rfc2047(sb, name.buf, name.len,
+               if (needs_rfc2047_encoding(namebuf, namelen, RFC2047_ADDRESS)) {
+                       add_rfc2047(sb, namebuf, namelen,
                                    encoding, RFC2047_ADDRESS);
                        max_length = 76; /* per rfc2047 */
-               } else if (needs_rfc822_quoting(name.buf, name.len)) {
+               } else if (needs_rfc822_quoting(namebuf, namelen)) {
                        struct strbuf quoted = STRBUF_INIT;
-                       add_rfc822_quoted(&quoted, name.buf, name.len);
+                       add_rfc822_quoted(&quoted, namebuf, namelen);
                        strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
                                                        -6, 1, max_length);
                        strbuf_release(&quoted);
                } else {
-                       strbuf_add_wrapped_bytes(sb, name.buf, name.len,
+                       strbuf_add_wrapped_bytes(sb, namebuf, namelen,
                                                 -6, 1, max_length);
                }
-               if (namelen - name.len + last_line_length(sb) > max_length)
-                       strbuf_addch(sb, '\n');
  
-               strbuf_addf(sb, " <%s>\n", mail.buf);
+               if (max_length <
+                   last_line_length(sb) + strlen(" <") + maillen + strlen(">"))
+                       strbuf_addch(sb, '\n');
+               strbuf_addf(sb, " <%.*s>\n", (int)maillen, mailbuf);
        } else {
-               strbuf_addf(sb, "%s: %.*s%s <%s>\n", what,
-                             (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,
-                             "    ", name.buf, mail.buf);
+               strbuf_addf(sb, "%s: %.*s%.*s <%.*s>\n", what,
+                           (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0, "    ",
+                           (int)namelen, namebuf, (int)maillen, mailbuf);
        }
  
-       strbuf_release(&mail);
-       strbuf_release(&name);
        switch (pp->fmt) {
        case CMIT_FMT_MEDIUM:
                strbuf_addf(sb, "Date:   %s\n",
@@@ -606,7 -585,6 +585,7 @@@ static char *replace_encoding_header(ch
  }
  
  char *logmsg_reencode(const struct commit *commit,
 +                    char **commit_encoding,
                      const char *output_encoding)
  {
        static const char *utf8 = "UTF-8";
                            sha1_to_hex(commit->object.sha1), typename(type));
        }
  
 -      if (!output_encoding || !*output_encoding)
 +      if (!output_encoding || !*output_encoding) {
 +              if (commit_encoding)
 +                      *commit_encoding =
 +                              get_header(commit, msg, "encoding");
                return msg;
 +      }
        encoding = get_header(commit, msg, "encoding");
 +      if (commit_encoding)
 +              *commit_encoding = encoding;
        use_encoding = encoding ? encoding : utf8;
        if (same_encoding(use_encoding, output_encoding)) {
                /*
        if (out)
                out = replace_encoding_header(out, output_encoding);
  
 -      free(encoding);
 +      if (!commit_encoding)
 +              free(encoding);
        /*
         * If the re-encoding failed, out might be NULL here; in that
         * case we just return the commit message verbatim.
@@@ -772,38 -743,26 +751,38 @@@ struct chunk 
        size_t len;
  };
  
 +enum flush_type {
 +      no_flush,
 +      flush_right,
 +      flush_left,
 +      flush_left_and_steal,
 +      flush_both
 +};
 +
 +enum trunc_type {
 +      trunc_none,
 +      trunc_left,
 +      trunc_middle,
 +      trunc_right
 +};
 +
  struct format_commit_context {
        const struct commit *commit;
        const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
 -      unsigned commit_signature_parsed:1;
 -      struct {
 -              char *gpg_output;
 -              char *gpg_status;
 -              char good_bad;
 -              char *signer;
 -              char *key;
 -      } signature;
 +      struct signature_check signature_check;
 +      enum flush_type flush_type;
 +      enum trunc_type truncate;
        char *message;
 +      char *commit_encoding;
        size_t width, indent1, indent2;
 +      int auto_color;
 +      int padding;
  
        /* These offsets are relative to the start of the commit message. */
        struct chunk author;
        struct chunk committer;
 -      struct chunk encoding;
        size_t message_off;
        size_t subject_off;
        size_t body_off;
@@@ -850,6 -809,9 +829,6 @@@ static void parse_commit_header(struct 
                } 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;
        }
@@@ -930,6 -892,23 +909,6 @@@ static void parse_commit_message(struc
        c->commit_message_parsed = 1;
  }
  
 -static void format_decoration(struct strbuf *sb, const struct commit *commit)
 -{
 -      struct name_decoration *d;
 -      const char *prefix = " (";
 -
 -      load_ref_decorations(DECORATE_SHORT_REFS);
 -      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, ')');
 -}
 -
  static void strbuf_wrap(struct strbuf *sb, size_t pos,
                        size_t width, size_t indent1, size_t indent2)
  {
@@@ -959,6 -938,64 +938,6 @@@ static void rewrap_message_tail(struct 
        c->indent2 = new_indent2;
  }
  
 -static struct {
 -      char result;
 -      const char *check;
 -} signature_check[] = {
 -      { 'G', "\n[GNUPG:] GOODSIG " },
 -      { 'B', "\n[GNUPG:] BADSIG " },
 -};
 -
 -static void parse_signature_lines(struct format_commit_context *ctx)
 -{
 -      const char *buf = ctx->signature.gpg_status;
 -      int i;
 -
 -      for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
 -              const char *found = strstr(buf, signature_check[i].check);
 -              const char *next;
 -              if (!found)
 -                      continue;
 -              ctx->signature.good_bad = signature_check[i].result;
 -              found += strlen(signature_check[i].check);
 -              ctx->signature.key = xmemdupz(found, 16);
 -              found += 17;
 -              next = strchrnul(found, '\n');
 -              ctx->signature.signer = xmemdupz(found, next - found);
 -              break;
 -      }
 -}
 -
 -static void parse_commit_signature(struct format_commit_context *ctx)
 -{
 -      struct strbuf payload = STRBUF_INIT;
 -      struct strbuf signature = STRBUF_INIT;
 -      struct strbuf gpg_output = STRBUF_INIT;
 -      struct strbuf gpg_status = STRBUF_INIT;
 -      int status;
 -
 -      ctx->commit_signature_parsed = 1;
 -
 -      if (parse_signed_commit(ctx->commit->object.sha1,
 -                              &payload, &signature) <= 0)
 -              goto out;
 -      status = verify_signed_buffer(payload.buf, payload.len,
 -                                    signature.buf, signature.len,
 -                                    &gpg_output, &gpg_status);
 -      if (status && !gpg_output.len)
 -              goto out;
 -      ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
 -      ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL);
 -      parse_signature_lines(ctx);
 -
 - out:
 -      strbuf_release(&gpg_status);
 -      strbuf_release(&gpg_output);
 -      strbuf_release(&payload);
 -      strbuf_release(&signature);
 -}
 -
 -
  static int format_reflog_person(struct strbuf *sb,
                                char part,
                                struct reflog_walk_info *log,
        return format_person_part(sb, part, ident, strlen(ident), dmode);
  }
  
 -static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 +static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
 +                        const char *placeholder,
 +                        struct format_commit_context *c)
 +{
 +      if (placeholder[1] == '(') {
 +              const char *begin = placeholder + 2;
 +              const char *end = strchr(begin, ')');
 +              char color[COLOR_MAXLEN];
 +
 +              if (!end)
 +                      return 0;
 +              if (!prefixcmp(begin, "auto,")) {
 +                      if (!want_color(c->pretty_ctx->color))
 +                              return end - placeholder + 1;
 +                      begin += 5;
 +              }
 +              color_parse_mem(begin,
 +                              end - begin,
 +                              "--pretty format", color);
 +              strbuf_addstr(sb, color);
 +              return end - placeholder + 1;
 +      }
 +      if (!prefixcmp(placeholder + 1, "red")) {
 +              strbuf_addstr(sb, GIT_COLOR_RED);
 +              return 4;
 +      } else if (!prefixcmp(placeholder + 1, "green")) {
 +              strbuf_addstr(sb, GIT_COLOR_GREEN);
 +              return 6;
 +      } else if (!prefixcmp(placeholder + 1, "blue")) {
 +              strbuf_addstr(sb, GIT_COLOR_BLUE);
 +              return 5;
 +      } else if (!prefixcmp(placeholder + 1, "reset")) {
 +              strbuf_addstr(sb, GIT_COLOR_RESET);
 +              return 6;
 +      } else
 +              return 0;
 +}
 +
 +static size_t parse_padding_placeholder(struct strbuf *sb,
 +                                      const char *placeholder,
 +                                      struct format_commit_context *c)
 +{
 +      const char *ch = placeholder;
 +      enum flush_type flush_type;
 +      int to_column = 0;
 +
 +      switch (*ch++) {
 +      case '<':
 +              flush_type = flush_right;
 +              break;
 +      case '>':
 +              if (*ch == '<') {
 +                      flush_type = flush_both;
 +                      ch++;
 +              } else if (*ch == '>') {
 +                      flush_type = flush_left_and_steal;
 +                      ch++;
 +              } else
 +                      flush_type = flush_left;
 +              break;
 +      default:
 +              return 0;
 +      }
 +
 +      /* the next value means "wide enough to that column" */
 +      if (*ch == '|') {
 +              to_column = 1;
 +              ch++;
 +      }
 +
 +      if (*ch == '(') {
 +              const char *start = ch + 1;
 +              const char *end = start + strcspn(start, ",)");
 +              char *next;
 +              int width;
 +              if (!end || end == start)
 +                      return 0;
 +              width = strtoul(start, &next, 10);
 +              if (next == start || width == 0)
 +                      return 0;
 +              c->padding = to_column ? -width : width;
 +              c->flush_type = flush_type;
 +
 +              if (*end == ',') {
 +                      start = end + 1;
 +                      end = strchr(start, ')');
 +                      if (!end || end == start)
 +                              return 0;
 +                      if (!prefixcmp(start, "trunc)"))
 +                              c->truncate = trunc_right;
 +                      else if (!prefixcmp(start, "ltrunc)"))
 +                              c->truncate = trunc_left;
 +                      else if (!prefixcmp(start, "mtrunc)"))
 +                              c->truncate = trunc_middle;
 +                      else
 +                              return 0;
 +              } else
 +                      c->truncate = trunc_none;
 +
 +              return end - placeholder + 1;
 +      }
 +      return 0;
 +}
 +
 +static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 +                              const char *placeholder,
                                void *context)
  {
        struct format_commit_context *c = context;
        /* these are independent of the commit */
        switch (placeholder[0]) {
        case 'C':
 -              if (placeholder[1] == '(') {
 -                      const char *begin = placeholder + 2;
 -                      const char *end = strchr(begin, ')');
 -                      char color[COLOR_MAXLEN];
 -
 -                      if (!end)
 -                              return 0;
 -                      if (!prefixcmp(begin, "auto,")) {
 -                              if (!want_color(c->pretty_ctx->color))
 -                                      return end - placeholder + 1;
 -                              begin += 5;
 -                      }
 -                      color_parse_mem(begin,
 -                                      end - begin,
 -                                      "--pretty format", color);
 -                      strbuf_addstr(sb, color);
 -                      return end - placeholder + 1;
 +              if (!prefixcmp(placeholder + 1, "(auto)")) {
 +                      c->auto_color = 1;
 +                      return 7; /* consumed 7 bytes, "C(auto)" */
 +              } else {
 +                      int ret = parse_color(sb, placeholder, c);
 +                      if (ret)
 +                              c->auto_color = 0;
 +                      /*
 +                       * Otherwise, we decided to treat %C<unknown>
 +                       * as a literal string, and the previous
 +                       * %C(auto) is still valid.
 +                       */
 +                      return ret;
                }
 -              if (!prefixcmp(placeholder + 1, "red")) {
 -                      strbuf_addstr(sb, GIT_COLOR_RED);
 -                      return 4;
 -              } else if (!prefixcmp(placeholder + 1, "green")) {
 -                      strbuf_addstr(sb, GIT_COLOR_GREEN);
 -                      return 6;
 -              } else if (!prefixcmp(placeholder + 1, "blue")) {
 -                      strbuf_addstr(sb, GIT_COLOR_BLUE);
 -                      return 5;
 -              } else if (!prefixcmp(placeholder + 1, "reset")) {
 -                      strbuf_addstr(sb, GIT_COLOR_RESET);
 -                      return 6;
 -              } else
 -                      return 0;
        case 'n':               /* newline */
                strbuf_addch(sb, '\n');
                return 1;
                        return end - placeholder + 1;
                } else
                        return 0;
 +
 +      case '<':
 +      case '>':
 +              return parse_padding_placeholder(sb, placeholder, c);
        }
  
        /* these depend on the commit */
  
        switch (placeholder[0]) {
        case 'H':               /* commit hash */
 +              strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
                strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
 +              strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                return 1;
        case 'h':               /* abbreviated commit hash */
 -              if (add_again(sb, &c->abbrev_commit_hash))
 +              strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
 +              if (add_again(sb, &c->abbrev_commit_hash)) {
 +                      strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                        return 1;
 +              }
                strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
                                                     c->pretty_ctx->abbrev));
 +              strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
                c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
                strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
 -              format_decoration(sb, commit);
 +              load_ref_decorations(DECORATE_SHORT_REFS);
 +              format_decorations(sb, commit, c->auto_color);
                return 1;
        case 'g':               /* reflog info */
                switch(placeholder[1]) {
        }
  
        if (placeholder[0] == 'G') {
 -              if (!c->commit_signature_parsed)
 -                      parse_commit_signature(c);
 +              if (!c->signature_check.result)
 +                      check_commit_signature(c->commit, &(c->signature_check));
                switch (placeholder[1]) {
                case 'G':
 -                      if (c->signature.gpg_output)
 -                              strbuf_addstr(sb, c->signature.gpg_output);
 +                      if (c->signature_check.gpg_output)
 +                              strbuf_addstr(sb, c->signature_check.gpg_output);
                        break;
                case '?':
 -                      switch (c->signature.good_bad) {
 +                      switch (c->signature_check.result) {
                        case 'G':
                        case 'B':
 -                              strbuf_addch(sb, c->signature.good_bad);
 +                      case 'U':
 +                      case 'N':
 +                              strbuf_addch(sb, c->signature_check.result);
                        }
                        break;
                case 'S':
 -                      if (c->signature.signer)
 -                              strbuf_addstr(sb, c->signature.signer);
 +                      if (c->signature_check.signer)
 +                              strbuf_addstr(sb, c->signature_check.signer);
                        break;
                case 'K':
 -                      if (c->signature.key)
 -                              strbuf_addstr(sb, c->signature.key);
 +                      if (c->signature_check.key)
 +                              strbuf_addstr(sb, c->signature_check.key);
                        break;
                }
                return 2;
                                   msg + c->committer.off, c->committer.len,
                                   c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
 -              strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
 +              if (c->commit_encoding)
 +                      strbuf_addstr(sb, c->commit_encoding);
                return 1;
        case 'B':       /* raw body */
                /* message_off is always left at the initial newline */
        return 0;       /* unknown placeholder */
  }
  
 -static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
 +static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 +                                  const char *placeholder,
 +                                  struct format_commit_context *c)
 +{
 +      struct strbuf local_sb = STRBUF_INIT;
 +      int total_consumed = 0, len, padding = c->padding;
 +      if (padding < 0) {
 +              const char *start = strrchr(sb->buf, '\n');
 +              int occupied;
 +              if (!start)
 +                      start = sb->buf;
 +              occupied = utf8_strnwidth(start, -1, 1);
 +              padding = (-padding) - occupied;
 +      }
 +      while (1) {
 +              int modifier = *placeholder == 'C';
 +              int consumed = format_commit_one(&local_sb, placeholder, c);
 +              total_consumed += consumed;
 +
 +              if (!modifier)
 +                      break;
 +
 +              placeholder += consumed;
 +              if (*placeholder != '%')
 +                      break;
 +              placeholder++;
 +              total_consumed++;
 +      }
 +      len = utf8_strnwidth(local_sb.buf, -1, 1);
 +
 +      if (c->flush_type == flush_left_and_steal) {
 +              const char *ch = sb->buf + sb->len - 1;
 +              while (len > padding && ch > sb->buf) {
 +                      const char *p;
 +                      if (*ch == ' ') {
 +                              ch--;
 +                              padding++;
 +                              continue;
 +                      }
 +                      /* check for trailing ansi sequences */
 +                      if (*ch != 'm')
 +                              break;
 +                      p = ch - 1;
 +                      while (ch - p < 10 && *p != '\033')
 +                              p--;
 +                      if (*p != '\033' ||
 +                          ch + 1 - p != display_mode_esc_sequence_len(p))
 +                              break;
 +                      /*
 +                       * got a good ansi sequence, put it back to
 +                       * local_sb as we're cutting sb
 +                       */
 +                      strbuf_insert(&local_sb, 0, p, ch + 1 - p);
 +                      ch = p - 1;
 +              }
 +              strbuf_setlen(sb, ch + 1 - sb->buf);
 +              c->flush_type = flush_left;
 +      }
 +
 +      if (len > padding) {
 +              switch (c->truncate) {
 +              case trunc_left:
 +                      strbuf_utf8_replace(&local_sb,
 +                                          0, len - (padding - 2),
 +                                          "..");
 +                      break;
 +              case trunc_middle:
 +                      strbuf_utf8_replace(&local_sb,
 +                                          padding / 2 - 1,
 +                                          len - (padding - 2),
 +                                          "..");
 +                      break;
 +              case trunc_right:
 +                      strbuf_utf8_replace(&local_sb,
 +                                          padding - 2, len - (padding - 2),
 +                                          "..");
 +                      break;
 +              case trunc_none:
 +                      break;
 +              }
 +              strbuf_addstr(sb, local_sb.buf);
 +      } else {
 +              int sb_len = sb->len, offset = 0;
 +              if (c->flush_type == flush_left)
 +                      offset = padding - len;
 +              else if (c->flush_type == flush_both)
 +                      offset = (padding - len) / 2;
 +              /*
 +               * we calculate padding in columns, now
 +               * convert it back to chars
 +               */
 +              padding = padding - len + local_sb.len;
 +              strbuf_grow(sb, padding);
 +              strbuf_setlen(sb, sb_len + padding);
 +              memset(sb->buf + sb_len, ' ', sb->len - sb_len);
 +              memcpy(sb->buf + sb_len + offset, local_sb.buf,
 +                     local_sb.len);
 +      }
 +      strbuf_release(&local_sb);
 +      c->flush_type = no_flush;
 +      return total_consumed;
 +}
 +
 +static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 +                               const char *placeholder,
                                 void *context)
  {
        int consumed;
                placeholder++;
  
        orig_len = sb->len;
 -      consumed = format_commit_one(sb, placeholder, context);
 +      if (((struct format_commit_context *)context)->flush_type != no_flush)
 +              consumed = format_and_pad_commit(sb, placeholder, context);
 +      else
 +              consumed = format_commit_one(sb, placeholder, context);
        if (magic == NO_MAGIC)
                return consumed;
  
@@@ -1499,40 -1328,19 +1478,40 @@@ void format_commit_message(const struc
  {
        struct format_commit_context context;
        const char *output_enc = pretty_ctx->output_encoding;
 +      const char *utf8 = "UTF-8";
  
        memset(&context, 0, sizeof(context));
        context.commit = commit;
        context.pretty_ctx = pretty_ctx;
        context.wrap_start = sb->len;
 -      context.message = logmsg_reencode(commit, output_enc);
 +      context.message = logmsg_reencode(commit,
 +                                        &context.commit_encoding,
 +                                        output_enc);
  
        strbuf_expand(sb, format, format_commit_item, &context);
        rewrap_message_tail(sb, &context, 0, 0, 0);
  
 +      if (output_enc) {
 +              if (same_encoding(utf8, output_enc))
 +                      output_enc = NULL;
 +      } else {
 +              if (context.commit_encoding &&
 +                  !same_encoding(context.commit_encoding, utf8))
 +                      output_enc = context.commit_encoding;
 +      }
 +
 +      if (output_enc) {
 +              int outsz;
 +              char *out = reencode_string_len(sb->buf, sb->len,
 +                                              output_enc, utf8, &outsz);
 +              if (out)
 +                      strbuf_attach(sb, out, outsz, outsz + 1);
 +      }
 +
 +      free(context.commit_encoding);
        logmsg_free(context.message, commit);
 -      free(context.signature.gpg_output);
 -      free(context.signature.signer);
 +      free(context.signature_check.gpg_output);
 +      free(context.signature_check.signer);
  }
  
  static void pp_header(const struct pretty_print_context *pp,
@@@ -1688,7 -1496,7 +1667,7 @@@ void pretty_print_commit(const struct p
        }
  
        encoding = get_log_output_encoding();
 -      msg = reencoded = logmsg_reencode(commit, encoding);
 +      msg = reencoded = logmsg_reencode(commit, NULL, encoding);
  
        if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
                indent = 0;