]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'nd/pretty-commit-log-message'
authorJunio C Hamano <gitster@pobox.com>
Tue, 1 Nov 2011 22:20:03 +0000 (15:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Nov 2011 22:20:03 +0000 (15:20 -0700)
* nd/pretty-commit-log-message:
  pretty.c: use original commit message if reencoding fails
  pretty.c: free get_header() return value

1  2 
pretty.c

diff --combined pretty.c
index f45eb54e4c99b8d67e4aa85f9a6218ea7a560592,f00933f2e8169b132965518056e161a2ddfaab5b..230fe1cc82e3a3bf7c0fef604350868d917acef4
+++ b/pretty.c
@@@ -208,58 -208,6 +208,58 @@@ int has_non_ascii(const char *s
        return 0;
  }
  
 +static int is_rfc822_special(char ch)
 +{
 +      switch (ch) {
 +      case '(':
 +      case ')':
 +      case '<':
 +      case '>':
 +      case '[':
 +      case ']':
 +      case ':':
 +      case ';':
 +      case '@':
 +      case ',':
 +      case '.':
 +      case '"':
 +      case '\\':
 +              return 1;
 +      default:
 +              return 0;
 +      }
 +}
 +
 +static int has_rfc822_specials(const char *s, int len)
 +{
 +      int i;
 +      for (i = 0; i < len; i++)
 +              if (is_rfc822_special(s[i]))
 +                      return 1;
 +      return 0;
 +}
 +
 +static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
 +{
 +      int i;
 +
 +      /* just a guess, we may have to also backslash-quote */
 +      strbuf_grow(out, len + 2);
 +
 +      strbuf_addch(out, '"');
 +      for (i = 0; i < len; i++) {
 +              switch (s[i]) {
 +              case '"':
 +              case '\\':
 +                      strbuf_addch(out, '\\');
 +                      /* fall through */
 +              default:
 +                      strbuf_addch(out, s[i]);
 +              }
 +      }
 +      strbuf_addch(out, '"');
 +}
 +
  static int is_rfc2047_special(char ch)
  {
        return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
  static void add_rfc2047(struct strbuf *sb, const char *line, int len,
                       const char *encoding)
  {
 -      int i, last;
 +      static const int max_length = 78; /* per rfc2822 */
 +      int i;
 +      int line_len;
 +
 +      /* How many bytes are already used on the current line? */
 +      for (i = sb->len - 1; i >= 0; i--)
 +              if (sb->buf[i] == '\n')
 +                      break;
 +      line_len = sb->len - (i+1);
  
        for (i = 0; i < len; i++) {
                int ch = line[i];
 -              if (non_ascii(ch))
 +              if (non_ascii(ch) || ch == '\n')
                        goto needquote;
                if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
                        goto needquote;
        }
 -      strbuf_add(sb, line, len);
 +      strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
        return;
  
  needquote:
        strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
        strbuf_addf(sb, "=?%s?q?", encoding);
 -      for (i = last = 0; i < len; i++) {
 +      line_len += strlen(encoding) + 5; /* 5 for =??q? */
 +      for (i = 0; i < len; i++) {
                unsigned ch = line[i] & 0xFF;
 +
 +              if (line_len >= max_length - 2) {
 +                      strbuf_addf(sb, "?=\n =?%s?q?", encoding);
 +                      line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
 +              }
 +
                /*
                 * We encode ' ' using '=20' even though rfc2047
                 * allows using '_' for readability.  Unfortunately,
                 * many programs do not understand this and just
                 * leave the underscore in place.
                 */
 -              if (is_rfc2047_special(ch) || ch == ' ') {
 -                      strbuf_add(sb, line + last, i - last);
 +              if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
                        strbuf_addf(sb, "=%02X", ch);
 -                      last = i + 1;
 +                      line_len += 3;
 +              }
 +              else {
 +                      strbuf_addch(sb, ch);
 +                      line_len++;
                }
        }
 -      strbuf_add(sb, line + last, len - last);
        strbuf_addstr(sb, "?=");
  }
  
 -void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
 -                const char *line, enum date_mode dmode,
 -                const char *encoding)
 +void pp_user_info(const struct pretty_print_context *pp,
 +                const char *what, struct strbuf *sb,
 +                const char *line, const char *encoding)
  {
        char *date;
        int namelen;
        unsigned long time;
        int tz;
  
 -      if (fmt == CMIT_FMT_ONELINE)
 +      if (pp->fmt == CMIT_FMT_ONELINE)
                return;
        date = strchr(line, '>');
        if (!date)
        time = strtoul(date, &date, 10);
        tz = strtol(date, NULL, 10);
  
 -      if (fmt == CMIT_FMT_EMAIL) {
 +      if (pp->fmt == CMIT_FMT_EMAIL) {
                char *name_tail = strchr(line, '<');
                int display_name_length;
 +              int final_line;
                if (!name_tail)
                        return;
                while (line < name_tail && isspace(name_tail[-1]))
                        name_tail--;
                display_name_length = name_tail - line;
                strbuf_addstr(sb, "From: ");
 -              add_rfc2047(sb, line, display_name_length, encoding);
 +              if (!has_rfc822_specials(line, display_name_length)) {
 +                      add_rfc2047(sb, line, display_name_length, encoding);
 +              } else {
 +                      struct strbuf quoted = STRBUF_INIT;
 +                      add_rfc822_quoted(&quoted, line, display_name_length);
 +                      add_rfc2047(sb, quoted.buf, quoted.len, encoding);
 +                      strbuf_release(&quoted);
 +              }
 +              for (final_line = 0; final_line < sb->len; final_line++)
 +                      if (sb->buf[sb->len - final_line - 1] == '\n')
 +                              break;
 +              if (namelen - display_name_length + final_line > 78) {
 +                      strbuf_addch(sb, '\n');
 +                      if (!isspace(name_tail[0]))
 +                              strbuf_addch(sb, ' ');
 +              }
                strbuf_add(sb, name_tail, namelen - display_name_length);
                strbuf_addch(sb, '\n');
        } else {
                strbuf_addf(sb, "%s: %.*s%.*s\n", what,
 -                            (fmt == CMIT_FMT_FULLER) ? 4 : 0,
 +                            (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,
                              "    ", namelen, line);
        }
 -      switch (fmt) {
 +      switch (pp->fmt) {
        case CMIT_FMT_MEDIUM:
 -              strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, dmode));
 +              strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, pp->date_mode));
                break;
        case CMIT_FMT_EMAIL:
                strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
                break;
        case CMIT_FMT_FULLER:
 -              strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
 +              strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
                break;
        default:
                /* notin' */
@@@ -408,12 -323,12 +408,12 @@@ static const char *skip_empty_lines(con
        return msg;
  }
  
 -static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
 -                      const struct commit *commit, int abbrev)
 +static void add_merge_info(const struct pretty_print_context *pp,
 +                         struct strbuf *sb, const struct commit *commit)
  {
        struct commit_list *parent = commit->parents;
  
 -      if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
 +      if ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) ||
            !parent || !parent->next)
                return;
  
        while (parent) {
                struct commit *p = parent->item;
                const char *hex = NULL;
 -              if (abbrev)
 -                      hex = find_unique_abbrev(p->object.sha1, abbrev);
 +              if (pp->abbrev)
 +                      hex = find_unique_abbrev(p->object.sha1, pp->abbrev);
                if (!hex)
                        hex = sha1_to_hex(p->object.sha1);
                parent = parent->next;
@@@ -944,7 -859,11 +944,7 @@@ static size_t format_commit_one(struct 
                                              c->abbrev_parent_hashes.off;
                return 1;
        case 'm':               /* left/right/bottom */
 -              strbuf_addch(sb, (commit->object.flags & BOUNDARY)
 -                               ? '-'
 -                               : (commit->object.flags & SYMMETRIC_LEFT)
 -                               ? '<'
 -                               : '>');
 +              strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
                format_decoration(sb, commit);
@@@ -1084,7 -1003,7 +1084,7 @@@ void userformat_find_requirements(cons
                        return;
                fmt = user_format;
        }
 -      strbuf_expand(&dummy, user_format, userformat_want_item, w);
 +      strbuf_expand(&dummy, fmt, userformat_want_item, w);
        strbuf_release(&dummy);
  }
  
@@@ -1094,7 -1013,6 +1094,6 @@@ void format_commit_message(const struc
  {
        struct format_commit_context context;
        static const char utf8[] = "UTF-8";
-       const char *enc;
        const char *output_enc = pretty_ctx->output_encoding;
  
        memset(&context, 0, sizeof(context));
        context.wrap_start = sb->len;
        context.message = commit->buffer;
        if (output_enc) {
-               enc = get_header(commit, "encoding");
-               enc = enc ? enc : utf8;
-               if (strcmp(enc, output_enc))
+               char *enc = get_header(commit, "encoding");
+               if (strcmp(enc ? enc : utf8, output_enc)) {
                        context.message = logmsg_reencode(commit, output_enc);
+                       if (!context.message)
+                               context.message = commit->buffer;
+               }
+               free(enc);
        }
  
        strbuf_expand(sb, format, format_commit_item, &context);
                free(context.message);
  }
  
 -static void pp_header(enum cmit_fmt fmt,
 -                    int abbrev,
 -                    enum date_mode dmode,
 +static void pp_header(const struct pretty_print_context *pp,
                      const char *encoding,
                      const struct commit *commit,
                      const char **msg_p,
                        /* End of header */
                        return;
  
 -              if (fmt == CMIT_FMT_RAW) {
 +              if (pp->fmt == CMIT_FMT_RAW) {
                        strbuf_add(sb, line, linelen);
                        continue;
                }
                                ;
                        /* with enough slop */
                        strbuf_grow(sb, num * 50 + 20);
 -                      add_merge_info(fmt, sb, commit, abbrev);
 +                      add_merge_info(pp, sb, commit);
                        parents_shown = 1;
                }
  
                 */
                if (!memcmp(line, "author ", 7)) {
                        strbuf_grow(sb, linelen + 80);
 -                      pp_user_info("Author", fmt, sb, line + 7, dmode, encoding);
 +                      pp_user_info(pp, "Author", sb, line + 7, encoding);
                }
                if (!memcmp(line, "committer ", 10) &&
 -                  (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
 +                  (pp->fmt == CMIT_FMT_FULL || pp->fmt == CMIT_FMT_FULLER)) {
                        strbuf_grow(sb, linelen + 80);
 -                      pp_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
 +                      pp_user_info(pp, "Commit", sb, line + 10, encoding);
                }
        }
  }
  
 -void pp_title_line(enum cmit_fmt fmt,
 +void pp_title_line(const struct pretty_print_context *pp,
                   const char **msg_p,
                   struct strbuf *sb,
 -                 const char *subject,
 -                 const char *after_subject,
                   const char *encoding,
                   int need_8bit_cte)
  {
 -      const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
        struct strbuf title;
  
        strbuf_init(&title, 80);
 -      *msg_p = format_subject(&title, *msg_p, line_separator);
 +      *msg_p = format_subject(&title, *msg_p,
 +                              pp->preserve_subject ? "\n" : " ");
  
        strbuf_grow(sb, title.len + 1024);
 -      if (subject) {
 -              strbuf_addstr(sb, subject);
 +      if (pp->subject) {
 +              strbuf_addstr(sb, pp->subject);
                add_rfc2047(sb, title.buf, title.len, encoding);
        } else {
                strbuf_addbuf(sb, &title);
                        "Content-Transfer-Encoding: 8bit\n";
                strbuf_addf(sb, header_fmt, encoding);
        }
 -      if (after_subject) {
 -              strbuf_addstr(sb, after_subject);
 +      if (pp->after_subject) {
 +              strbuf_addstr(sb, pp->after_subject);
        }
 -      if (fmt == CMIT_FMT_EMAIL) {
 +      if (pp->fmt == CMIT_FMT_EMAIL) {
                strbuf_addch(sb, '\n');
        }
        strbuf_release(&title);
  }
  
 -void pp_remainder(enum cmit_fmt fmt,
 +void pp_remainder(const struct pretty_print_context *pp,
                  const char **msg_p,
                  struct strbuf *sb,
                  int indent)
                if (is_empty_line(line, &linelen)) {
                        if (first)
                                continue;
 -                      if (fmt == CMIT_FMT_SHORT)
 +                      if (pp->fmt == CMIT_FMT_SHORT)
                                break;
                }
                first = 0;
@@@ -1256,19 -1181,19 +1258,19 @@@ char *reencode_commit_message(const str
        return logmsg_reencode(commit, encoding);
  }
  
 -void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 -                       struct strbuf *sb,
 -                       const struct pretty_print_context *context)
 +void pretty_print_commit(const struct pretty_print_context *pp,
 +                       const struct commit *commit,
 +                       struct strbuf *sb)
  {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
 -      int need_8bit_cte = context->need_8bit_cte;
 +      int need_8bit_cte = pp->need_8bit_cte;
  
 -      if (fmt == CMIT_FMT_USERFORMAT) {
 -              format_commit_message(commit, user_format, sb, context);
 +      if (pp->fmt == CMIT_FMT_USERFORMAT) {
 +              format_commit_message(commit, user_format, sb, pp);
                return;
        }
  
                msg = reencoded;
        }
  
 -      if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
 +      if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
                indent = 0;
  
        /*
         * We need to check and emit Content-type: to mark it
         * as 8-bit if we haven't done so.
         */
 -      if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
 +      if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
                int i, ch, in_body;
  
                for (in_body = i = 0; (ch = msg[i]); i++) {
                }
        }
  
 -      pp_header(fmt, context->abbrev, context->date_mode, encoding,
 -                commit, &msg, sb);
 -      if (fmt != CMIT_FMT_ONELINE && !context->subject) {
 +      pp_header(pp, encoding, commit, &msg, sb);
 +      if (pp->fmt != CMIT_FMT_ONELINE && !pp->subject) {
                strbuf_addch(sb, '\n');
        }
  
        msg = skip_empty_lines(msg);
  
        /* These formats treat the title line specially. */
 -      if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
 -              pp_title_line(fmt, &msg, sb, context->subject,
 -                            context->after_subject, encoding, need_8bit_cte);
 +      if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 +              pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
  
        beginning_of_body = sb->len;
 -      if (fmt != CMIT_FMT_ONELINE)
 -              pp_remainder(fmt, &msg, sb, indent);
 +      if (pp->fmt != CMIT_FMT_ONELINE)
 +              pp_remainder(pp, &msg, sb, indent);
        strbuf_rtrim(sb);
  
        /* Make sure there is an EOLN for the non-oneline case */
 -      if (fmt != CMIT_FMT_ONELINE)
 +      if (pp->fmt != CMIT_FMT_ONELINE)
                strbuf_addch(sb, '\n');
  
        /*
         * format.  Make sure we did not strip the blank line
         * between the header and the body.
         */
 -      if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
 +      if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
  
 -      if (context->show_notes)
 +      if (pp->show_notes)
                format_display_notes(commit->object.sha1, sb, encoding,
                                     NOTES_SHOW_HEADER | NOTES_INDENT);
  
        free(reencoded);
  }
 +
 +void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,
 +                  struct strbuf *sb)
 +{
 +      struct pretty_print_context pp = {0};
 +      pp.fmt = fmt;
 +      pretty_print_commit(&pp, commit, sb);
 +}