Merge branch 'ss/blame-textconv-fake-working-tree'
authorJunio C Hamano <gitster@pobox.com>
Tue, 8 Nov 2011 00:43:19 +0000 (16:43 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 8 Nov 2011 00:43:19 +0000 (16:43 -0800)
* ss/blame-textconv-fake-working-tree:
  blame.c: Properly initialize strbuf after calling textconv_object(), again

1  2 
builtin/blame.c

diff --combined builtin/blame.c
@@@ -41,7 -41,6 +41,7 @@@ static int reverse
  static int blank_boundary;
  static int incremental;
  static int xdl_opts;
 +static int abbrev = -1;
  
  static enum date_mode blame_date_mode = DATE_ISO8601;
  static size_t blame_date_width;
@@@ -1313,7 -1312,8 +1313,7 @@@ static void pass_blame(struct scoreboar
  /*
   * Information on commits, used for output.
   */
 -struct commit_info
 -{
 +struct commit_info {
        const char *author;
        const char *author_mail;
        unsigned long author_time;
@@@ -1378,7 -1378,7 +1378,7 @@@ static void get_ac_line(const char *inb
        timepos = tmp;
  
        *tmp = 0;
 -      while (person < tmp && *tmp != ' ')
 +      while (person < tmp && !(*tmp == ' ' && tmp[1] == '<'))
                tmp--;
        if (tmp <= person)
                return;
@@@ -1418,8 -1418,7 +1418,8 @@@ static void get_commit_info(struct comm
                            int detailed)
  {
        int len;
 -      char *tmp, *endp, *reencoded, *message;
 +      const char *subject;
 +      char *reencoded, *message;
        static char author_name[1024];
        static char author_mail[1024];
        static char committer_name[1024];
                    &ret->committer_time, &ret->committer_tz);
  
        ret->summary = summary_buf;
 -      tmp = strstr(message, "\n\n");
 -      if (!tmp) {
 -      error_out:
 +      len = find_commit_subject(message, &subject);
 +      if (len && len < sizeof(summary_buf)) {
 +              memcpy(summary_buf, subject, len);
 +              summary_buf[len] = 0;
 +      } else {
                sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
 -              free(reencoded);
 -              return;
        }
 -      tmp += 2;
 -      endp = strchr(tmp, '\n');
 -      if (!endp)
 -              endp = tmp + strlen(tmp);
 -      len = endp - tmp;
 -      if (len >= sizeof(summary_buf) || len == 0)
 -              goto error_out;
 -      memcpy(summary_buf, tmp, len);
 -      summary_buf[len] = 0;
        free(reencoded);
  }
  
@@@ -1484,14 -1492,13 +1484,14 @@@ static void write_filename_info(const c
  /*
   * Porcelain/Incremental format wants to show a lot of details per
   * commit.  Instead of repeating this every line, emit it only once,
 - * the first time each commit appears in the output.
 + * the first time each commit appears in the output (unless the
 + * user has specifically asked for us to repeat).
   */
 -static int emit_one_suspect_detail(struct origin *suspect)
 +static int emit_one_suspect_detail(struct origin *suspect, int repeat)
  {
        struct commit_info ci;
  
 -      if (suspect->commit->object.flags & METAINFO_SHOWN)
 +      if (!repeat && (suspect->commit->object.flags & METAINFO_SHOWN))
                return 0;
  
        suspect->commit->object.flags |= METAINFO_SHOWN;
@@@ -1530,7 -1537,7 +1530,7 @@@ static void found_guilty_entry(struct b
                printf("%s %d %d %d\n",
                       sha1_to_hex(suspect->commit->object.sha1),
                       ent->s_lno + 1, ent->lno + 1, ent->num_lines);
 -              emit_one_suspect_detail(suspect);
 +              emit_one_suspect_detail(suspect, 0);
                write_filename_info(suspect->path);
                maybe_flush_or_die(stdout, "stdout");
        }
@@@ -1618,20 -1625,9 +1618,20 @@@ static const char *format_time(unsigne
  #define OUTPUT_SHOW_NUMBER    040
  #define OUTPUT_SHOW_SCORE      0100
  #define OUTPUT_NO_AUTHOR       0200
 +#define OUTPUT_SHOW_EMAIL     0400
 +#define OUTPUT_LINE_PORCELAIN 01000
 +
 +static void emit_porcelain_details(struct origin *suspect, int repeat)
 +{
 +      if (emit_one_suspect_detail(suspect, repeat) ||
 +          (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
 +              write_filename_info(suspect->path);
 +}
  
 -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
 +static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
 +                         int opt)
  {
 +      int repeat = opt & OUTPUT_LINE_PORCELAIN;
        int cnt;
        const char *cp;
        struct origin *suspect = ent->suspect;
               ent->s_lno + 1,
               ent->lno + 1,
               ent->num_lines);
 -      if (emit_one_suspect_detail(suspect) ||
 -          (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
 -              write_filename_info(suspect->path);
 +      emit_porcelain_details(suspect, repeat);
  
        cp = nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
 -              if (cnt)
 +              if (cnt) {
                        printf("%s %d %d\n", hex,
                               ent->s_lno + 1 + cnt,
                               ent->lno + 1 + cnt);
 +                      if (repeat)
 +                              emit_porcelain_details(suspect, 1);
 +              }
                putchar('\t');
                do {
                        ch = *cp++;
@@@ -1683,7 -1678,7 +1683,7 @@@ static void emit_other(struct scoreboar
        cp = nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
 -              int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
 +              int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : abbrev;
  
                if (suspect->commit->object.flags & UNINTERESTING) {
                        if (blank_boundary)
                }
  
                printf("%.*s", length, hex);
 -              if (opt & OUTPUT_ANNOTATE_COMPAT)
 -                      printf("\t(%10s\t%10s\t%d)", ci.author,
 +              if (opt & OUTPUT_ANNOTATE_COMPAT) {
 +                      const char *name;
 +                      if (opt & OUTPUT_SHOW_EMAIL)
 +                              name = ci.author_mail;
 +                      else
 +                              name = ci.author;
 +                      printf("\t(%10s\t%10s\t%d)", name,
                               format_time(ci.author_time, ci.author_tz,
                                           show_raw_time),
                               ent->lno + 1 + cnt);
 -              else {
 +              else {
                        if (opt & OUTPUT_SHOW_SCORE)
                                printf(" %*d %02d",
                                       max_score_digits, ent->score,
                                       ent->s_lno + 1 + cnt);
  
                        if (!(opt & OUTPUT_NO_AUTHOR)) {
 -                              int pad = longest_author - utf8_strwidth(ci.author);
 +                              const char *name;
 +                              int pad;
 +                              if (opt & OUTPUT_SHOW_EMAIL)
 +                                      name = ci.author_mail;
 +                              else
 +                                      name = ci.author;
 +                              pad = longest_author - utf8_strwidth(name);
                                printf(" (%s%*s %10s",
 -                                     ci.author, pad, "",
 +                                     name, pad, "",
                                       format_time(ci.author_time,
                                                   ci.author_tz,
                                                   show_raw_time));
@@@ -1768,7 -1752,7 +1768,7 @@@ static void output(struct scoreboard *s
  
        for (ent = sb->ent; ent; ent = ent->next) {
                if (option & OUTPUT_PORCELAIN)
 -                      emit_porcelain(sb, ent);
 +                      emit_porcelain(sb, ent, option);
                else {
                        emit_other(sb, ent, option);
                }
@@@ -1864,10 -1848,7 +1864,10 @@@ static void find_alignment(struct score
                if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
                        suspect->commit->object.flags |= METAINFO_SHOWN;
                        get_commit_info(suspect->commit, &ci, 1);
 -                      num = utf8_strwidth(ci.author);
 +                      if (*option & OUTPUT_SHOW_EMAIL)
 +                              num = utf8_strwidth(ci.author_mail);
 +                      else
 +                              num = utf8_strwidth(ci.author);
                        if (longest_author < num)
                                longest_author = num;
                }
@@@ -2096,6 -2077,7 +2096,7 @@@ static struct commit *fake_working_tree
        if (!contents_from || strcmp("-", contents_from)) {
                struct stat st;
                const char *read_from;
+               char *buf_ptr;
                unsigned long buf_len;
  
                if (contents_from) {
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len)) {
-                               buf.alloc = buf_len;
-                               buf.len = buf_len;
-                       }
+                           textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+                               strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
                        break;
@@@ -2314,19 -2294,16 +2313,19 @@@ int cmd_blame(int argc, const char **ar
                OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
                OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
                OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
 +              OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
                OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
                OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
                OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
                OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
 +              OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL),
                OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
                OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
                OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
                { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
                { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
                OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
 +              OPT__ABBREV(&abbrev),
                OPT_END()
        };
  
        save_commit_buffer = 0;
        dashdash_pos = 0;
  
 -      parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH |
 -                          PARSE_OPT_KEEP_ARGV0);
 +      parse_options_start(&ctx, argc, argv, prefix, options,
 +                          PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
        for (;;) {
                switch (parse_options_step(&ctx, options, blame_opt_usage)) {
                case PARSE_OPT_HELP:
  parse_done:
        argc = parse_options_end(&ctx);
  
 +      if (abbrev == -1)
 +              abbrev = default_abbrev;
 +      /* one more abbrev length is needed for the boundary commit */
 +      abbrev++;
 +
        if (revs_file && read_ancestry(revs_file))
                die_errno("reading graft file '%s' failed", revs_file);