blame.con commit git-blame: add internal statistics to count read blobs. (2bc4547)
   1/*
   2 * Copyright (C) 2006, Fredrik Kuivinen <freku045@student.liu.se>
   3 */
   4
   5#include <assert.h>
   6#include <time.h>
   7#include <sys/time.h>
   8#include <math.h>
   9
  10#include "cache.h"
  11#include "refs.h"
  12#include "tag.h"
  13#include "commit.h"
  14#include "tree.h"
  15#include "blob.h"
  16#include "diff.h"
  17#include "diffcore.h"
  18#include "revision.h"
  19#include "xdiff-interface.h"
  20
  21#define DEBUG 0
  22
  23static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S <revs-file>] [--] file [commit]\n"
  24        "  -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
  25        "  -l, --long          Show long commit SHA1 (Default: off)\n"
  26        "  -t, --time          Show raw timestamp (Default: off)\n"
  27        "  -S, --revs-file     Use revisions from revs-file instead of calling git-rev-list\n"
  28        "  -h, --help          This message";
  29
  30static struct commit **blame_lines;
  31static int num_blame_lines;
  32static char* blame_contents;
  33static int blame_len;
  34
  35struct util_info {
  36        int *line_map;
  37        unsigned char sha1[20]; /* blob sha, not commit! */
  38        char *buf;
  39        unsigned long size;
  40        int num_lines;
  41        const char* pathname;
  42
  43        void* topo_data;
  44};
  45
  46struct chunk {
  47        int off1, len1; /* --- */
  48        int off2, len2; /* +++ */
  49};
  50
  51struct patch {
  52        struct chunk *chunks;
  53        int num;
  54};
  55
  56static void get_blob(struct commit *commit);
  57
  58/* Only used for statistics */
  59static int num_get_patch;
  60static int num_commits;
  61static int patch_time;
  62static int num_read_blob;
  63
  64struct blame_diff_state {
  65        struct xdiff_emit_state xm;
  66        struct patch *ret;
  67};
  68
  69static void process_u0_diff(void *state_, char *line, unsigned long len)
  70{
  71        struct blame_diff_state *state = state_;
  72        struct chunk *chunk;
  73
  74        if (len < 4 || line[0] != '@' || line[1] != '@')
  75                return;
  76
  77        if (DEBUG)
  78                printf("chunk line: %.*s", (int)len, line);
  79        state->ret->num++;
  80        state->ret->chunks = xrealloc(state->ret->chunks,
  81                                      sizeof(struct chunk) * state->ret->num);
  82        chunk = &state->ret->chunks[state->ret->num - 1];
  83
  84        assert(!strncmp(line, "@@ -", 4));
  85
  86        if (parse_hunk_header(line, len,
  87                              &chunk->off1, &chunk->len1,
  88                              &chunk->off2, &chunk->len2)) {
  89                state->ret->num--;
  90                return;
  91        }
  92
  93        if (chunk->len1 == 0)
  94                chunk->off1++;
  95        if (chunk->len2 == 0)
  96                chunk->off2++;
  97
  98        if (chunk->off1 > 0)
  99                chunk->off1--;
 100        if (chunk->off2 > 0)
 101                chunk->off2--;
 102
 103        assert(chunk->off1 >= 0);
 104        assert(chunk->off2 >= 0);
 105}
 106
 107static struct patch *get_patch(struct commit *commit, struct commit *other)
 108{
 109        struct blame_diff_state state;
 110        xpparam_t xpp;
 111        xdemitconf_t xecfg;
 112        mmfile_t file_c, file_o;
 113        xdemitcb_t ecb;
 114        struct util_info *info_c = (struct util_info *)commit->util;
 115        struct util_info *info_o = (struct util_info *)other->util;
 116        struct timeval tv_start, tv_end;
 117
 118        get_blob(commit);
 119        file_c.ptr = info_c->buf;
 120        file_c.size = info_c->size;
 121
 122        get_blob(other);
 123        file_o.ptr = info_o->buf;
 124        file_o.size = info_o->size;
 125
 126        gettimeofday(&tv_start, NULL);
 127
 128        xpp.flags = XDF_NEED_MINIMAL;
 129        xecfg.ctxlen = 0;
 130        xecfg.flags = 0;
 131        ecb.outf = xdiff_outf;
 132        ecb.priv = &state;
 133        memset(&state, 0, sizeof(state));
 134        state.xm.consume = process_u0_diff;
 135        state.ret = xmalloc(sizeof(struct patch));
 136        state.ret->chunks = NULL;
 137        state.ret->num = 0;
 138
 139        xdl_diff(&file_c, &file_o, &xpp, &xecfg, &ecb);
 140
 141        gettimeofday(&tv_end, NULL);
 142        patch_time += 1000000 * (tv_end.tv_sec - tv_start.tv_sec) +
 143                tv_end.tv_usec - tv_start.tv_usec;
 144
 145        num_get_patch++;
 146        return state.ret;
 147}
 148
 149static void free_patch(struct patch *p)
 150{
 151        free(p->chunks);
 152        free(p);
 153}
 154
 155static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,
 156                                  int baselen, const char *pathname,
 157                                  unsigned mode, int stage);
 158
 159static unsigned char blob_sha1[20];
 160static const char* blame_file;
 161static int get_blob_sha1(struct tree *t, const char *pathname,
 162                         unsigned char *sha1)
 163{
 164        int i;
 165        const char *pathspec[2];
 166        blame_file = pathname;
 167        pathspec[0] = pathname;
 168        pathspec[1] = NULL;
 169        hashclr(blob_sha1);
 170        read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
 171
 172        for (i = 0; i < 20; i++) {
 173                if (blob_sha1[i] != 0)
 174                        break;
 175        }
 176
 177        if (i == 20)
 178                return -1;
 179
 180        hashcpy(sha1, blob_sha1);
 181        return 0;
 182}
 183
 184static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,
 185                                  int baselen, const char *pathname,
 186                                  unsigned mode, int stage)
 187{
 188        if (S_ISDIR(mode))
 189                return READ_TREE_RECURSIVE;
 190
 191        if (strncmp(blame_file, base, baselen) ||
 192            strcmp(blame_file + baselen, pathname))
 193                return -1;
 194
 195        hashcpy(blob_sha1, sha1);
 196        return -1;
 197}
 198
 199static void get_blob(struct commit *commit)
 200{
 201        struct util_info *info = commit->util;
 202        char type[20];
 203
 204        if (info->buf)
 205                return;
 206
 207        info->buf = read_sha1_file(info->sha1, type, &info->size);
 208        num_read_blob++;
 209
 210        assert(!strcmp(type, blob_type));
 211}
 212
 213/* For debugging only */
 214static void print_patch(struct patch *p)
 215{
 216        int i;
 217        printf("Num chunks: %d\n", p->num);
 218        for (i = 0; i < p->num; i++) {
 219                printf("%d,%d %d,%d\n", p->chunks[i].off1, p->chunks[i].len1,
 220                       p->chunks[i].off2, p->chunks[i].len2);
 221        }
 222}
 223
 224#if DEBUG
 225/* For debugging only */
 226static void print_map(struct commit *cmit, struct commit *other)
 227{
 228        struct util_info *util = cmit->util;
 229        struct util_info *util2 = other->util;
 230
 231        int i;
 232        int max =
 233            util->num_lines >
 234            util2->num_lines ? util->num_lines : util2->num_lines;
 235        int num;
 236
 237        for (i = 0; i < max; i++) {
 238                printf("i: %d ", i);
 239                num = -1;
 240
 241                if (i < util->num_lines) {
 242                        num = util->line_map[i];
 243                        printf("%d\t", num);
 244                } else
 245                        printf("\t");
 246
 247                if (i < util2->num_lines) {
 248                        int num2 = util2->line_map[i];
 249                        printf("%d\t", num2);
 250                        if (num != -1 && num2 != num)
 251                                printf("---");
 252                } else
 253                        printf("\t");
 254
 255                printf("\n");
 256        }
 257}
 258#endif
 259
 260/* p is a patch from commit to other. */
 261static void fill_line_map(struct commit *commit, struct commit *other,
 262                          struct patch *p)
 263{
 264        struct util_info *util = commit->util;
 265        struct util_info *util2 = other->util;
 266        int *map = util->line_map;
 267        int *map2 = util2->line_map;
 268        int cur_chunk = 0;
 269        int i1, i2;
 270
 271        if (p->num && DEBUG)
 272                print_patch(p);
 273
 274        if (DEBUG)
 275                printf("num lines 1: %d num lines 2: %d\n", util->num_lines,
 276                       util2->num_lines);
 277
 278        for (i1 = 0, i2 = 0; i1 < util->num_lines; i1++, i2++) {
 279                struct chunk *chunk = NULL;
 280                if (cur_chunk < p->num)
 281                        chunk = &p->chunks[cur_chunk];
 282
 283                if (chunk && chunk->off1 == i1) {
 284                        if (DEBUG && i2 != chunk->off2)
 285                                printf("i2: %d off2: %d\n", i2, chunk->off2);
 286
 287                        assert(i2 == chunk->off2);
 288
 289                        i1--;
 290                        i2--;
 291                        if (chunk->len1 > 0)
 292                                i1 += chunk->len1;
 293
 294                        if (chunk->len2 > 0)
 295                                i2 += chunk->len2;
 296
 297                        cur_chunk++;
 298                } else {
 299                        if (i2 >= util2->num_lines)
 300                                break;
 301
 302                        if (map[i1] != map2[i2] && map[i1] != -1) {
 303                                if (DEBUG)
 304                                        printf("map: i1: %d %d %p i2: %d %d %p\n",
 305                                               i1, map[i1],
 306                                               (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL),
 307                                               i2, map2[i2],
 308                                               (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL));
 309                                if (map2[i2] != -1 &&
 310                                    blame_lines[map[i1]] &&
 311                                    !blame_lines[map2[i2]])
 312                                        map[i1] = map2[i2];
 313                        }
 314
 315                        if (map[i1] == -1 && map2[i2] != -1)
 316                                map[i1] = map2[i2];
 317                }
 318
 319                if (DEBUG > 1)
 320                        printf("l1: %d l2: %d i1: %d i2: %d\n",
 321                               map[i1], map2[i2], i1, i2);
 322        }
 323}
 324
 325static int map_line(struct commit *commit, int line)
 326{
 327        struct util_info *info = commit->util;
 328        assert(line >= 0 && line < info->num_lines);
 329        return info->line_map[line];
 330}
 331
 332static struct util_info* get_util(struct commit *commit)
 333{
 334        struct util_info *util = commit->util;
 335
 336        if (util)
 337                return util;
 338
 339        util = xmalloc(sizeof(struct util_info));
 340        util->buf = NULL;
 341        util->size = 0;
 342        util->line_map = NULL;
 343        util->num_lines = -1;
 344        util->pathname = NULL;
 345        commit->util = util;
 346        return util;
 347}
 348
 349static int fill_util_info(struct commit *commit)
 350{
 351        struct util_info *util = commit->util;
 352
 353        assert(util);
 354        assert(util->pathname);
 355
 356        return !!get_blob_sha1(commit->tree, util->pathname, util->sha1);
 357}
 358
 359static void alloc_line_map(struct commit *commit)
 360{
 361        struct util_info *util = commit->util;
 362        int i;
 363
 364        if (util->line_map)
 365                return;
 366
 367        get_blob(commit);
 368
 369        util->num_lines = 0;
 370        for (i = 0; i < util->size; i++) {
 371                if (util->buf[i] == '\n')
 372                        util->num_lines++;
 373        }
 374        if(util->buf[util->size - 1] != '\n')
 375                util->num_lines++;
 376
 377        util->line_map = xmalloc(sizeof(int) * util->num_lines);
 378
 379        for (i = 0; i < util->num_lines; i++)
 380                util->line_map[i] = -1;
 381}
 382
 383static void init_first_commit(struct commit* commit, const char* filename)
 384{
 385        struct util_info* util = commit->util;
 386        int i;
 387
 388        util->pathname = filename;
 389        if (fill_util_info(commit))
 390                die("fill_util_info failed");
 391
 392        alloc_line_map(commit);
 393
 394        util = commit->util;
 395
 396        for (i = 0; i < util->num_lines; i++)
 397                util->line_map[i] = i;
 398}
 399
 400
 401static void process_commits(struct rev_info *rev, const char *path,
 402                            struct commit** initial)
 403{
 404        int i;
 405        struct util_info* util;
 406        int lines_left;
 407        int *blame_p;
 408        int *new_lines;
 409        int new_lines_len;
 410
 411        struct commit* commit = get_revision(rev);
 412        assert(commit);
 413        init_first_commit(commit, path);
 414
 415        util = commit->util;
 416        num_blame_lines = util->num_lines;
 417        blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
 418        blame_contents = util->buf;
 419        blame_len = util->size;
 420
 421        for (i = 0; i < num_blame_lines; i++)
 422                blame_lines[i] = NULL;
 423
 424        lines_left = num_blame_lines;
 425        blame_p = xmalloc(sizeof(int) * num_blame_lines);
 426        new_lines = xmalloc(sizeof(int) * num_blame_lines);
 427        do {
 428                struct commit_list *parents;
 429                int num_parents;
 430                struct util_info *util;
 431
 432                if (DEBUG)
 433                        printf("\nProcessing commit: %d %s\n", num_commits,
 434                               sha1_to_hex(commit->object.sha1));
 435
 436                if (lines_left == 0)
 437                        return;
 438
 439                num_commits++;
 440                memset(blame_p, 0, sizeof(int) * num_blame_lines);
 441                new_lines_len = 0;
 442                num_parents = 0;
 443                for (parents = commit->parents;
 444                     parents != NULL; parents = parents->next)
 445                        num_parents++;
 446
 447                if(num_parents == 0)
 448                        *initial = commit;
 449
 450                if (fill_util_info(commit))
 451                        continue;
 452
 453                alloc_line_map(commit);
 454                util = commit->util;
 455
 456                for (parents = commit->parents;
 457                     parents != NULL; parents = parents->next) {
 458                        struct commit *parent = parents->item;
 459                        struct patch *patch;
 460
 461                        if (parse_commit(parent) < 0)
 462                                die("parse_commit error");
 463
 464                        if (DEBUG)
 465                                printf("parent: %s\n",
 466                                       sha1_to_hex(parent->object.sha1));
 467
 468                        if (fill_util_info(parent)) {
 469                                num_parents--;
 470                                continue;
 471                        }
 472
 473                        patch = get_patch(parent, commit);
 474                        alloc_line_map(parent);
 475                        fill_line_map(parent, commit, patch);
 476
 477                        for (i = 0; i < patch->num; i++) {
 478                            int l;
 479                            for (l = 0; l < patch->chunks[i].len2; l++) {
 480                                int mapped_line =
 481                                    map_line(commit, patch->chunks[i].off2 + l);
 482                                if (mapped_line != -1) {
 483                                    blame_p[mapped_line]++;
 484                                    if (blame_p[mapped_line] == num_parents)
 485                                        new_lines[new_lines_len++] = mapped_line;
 486                                }
 487                            }
 488                        }
 489                        free_patch(patch);
 490                }
 491
 492                if (DEBUG)
 493                        printf("parents: %d\n", num_parents);
 494
 495                for (i = 0; i < new_lines_len; i++) {
 496                        int mapped_line = new_lines[i];
 497                        if (blame_lines[mapped_line] == NULL) {
 498                                blame_lines[mapped_line] = commit;
 499                                lines_left--;
 500                                if (DEBUG)
 501                                        printf("blame: mapped: %d i: %d\n",
 502                                               mapped_line, i);
 503                        }
 504                }
 505        } while ((commit = get_revision(rev)) != NULL);
 506}
 507
 508
 509static int compare_tree_path(struct rev_info* revs,
 510                             struct commit* c1, struct commit* c2)
 511{
 512        int ret;
 513        const char* paths[2];
 514        struct util_info* util = c2->util;
 515        paths[0] = util->pathname;
 516        paths[1] = NULL;
 517
 518        diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
 519                              &revs->pruning);
 520        ret = rev_compare_tree(revs, c1->tree, c2->tree);
 521        diff_tree_release_paths(&revs->pruning);
 522        return ret;
 523}
 524
 525
 526static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
 527                                   const char* path)
 528{
 529        int ret;
 530        const char* paths[2];
 531        paths[0] = path;
 532        paths[1] = NULL;
 533
 534        diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
 535                              &revs->pruning);
 536        ret = rev_same_tree_as_empty(revs, t1);
 537        diff_tree_release_paths(&revs->pruning);
 538        return ret;
 539}
 540
 541static const char* find_rename(struct commit* commit, struct commit* parent)
 542{
 543        struct util_info* cutil = commit->util;
 544        struct diff_options diff_opts;
 545        const char *paths[1];
 546        int i;
 547
 548        if (DEBUG) {
 549                printf("find_rename commit: %s ",
 550                       sha1_to_hex(commit->object.sha1));
 551                puts(sha1_to_hex(parent->object.sha1));
 552        }
 553
 554        diff_setup(&diff_opts);
 555        diff_opts.recursive = 1;
 556        diff_opts.detect_rename = DIFF_DETECT_RENAME;
 557        paths[0] = NULL;
 558        diff_tree_setup_paths(paths, &diff_opts);
 559        if (diff_setup_done(&diff_opts) < 0)
 560                die("diff_setup_done failed");
 561
 562        diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
 563                       "", &diff_opts);
 564        diffcore_std(&diff_opts);
 565
 566        for (i = 0; i < diff_queued_diff.nr; i++) {
 567                struct diff_filepair *p = diff_queued_diff.queue[i];
 568
 569                if (p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) {
 570                        if (DEBUG)
 571                                printf("rename %s -> %s\n", p->one->path, p->two->path);
 572                        return p->two->path;
 573                }
 574        }
 575
 576        return 0;
 577}
 578
 579static void simplify_commit(struct rev_info *revs, struct commit *commit)
 580{
 581        struct commit_list **pp, *parent;
 582
 583        if (!commit->tree)
 584                return;
 585
 586        if (!commit->parents) {
 587                struct util_info* util = commit->util;
 588                if (!same_tree_as_empty_path(revs, commit->tree,
 589                                             util->pathname))
 590                        commit->object.flags |= TREECHANGE;
 591                return;
 592        }
 593
 594        pp = &commit->parents;
 595        while ((parent = *pp) != NULL) {
 596                struct commit *p = parent->item;
 597
 598                if (p->object.flags & UNINTERESTING) {
 599                        pp = &parent->next;
 600                        continue;
 601                }
 602
 603                parse_commit(p);
 604                switch (compare_tree_path(revs, p, commit)) {
 605                case REV_TREE_SAME:
 606                        parent->next = NULL;
 607                        commit->parents = parent;
 608                        get_util(p)->pathname = get_util(commit)->pathname;
 609                        return;
 610
 611                case REV_TREE_NEW:
 612                {
 613
 614                        struct util_info* util = commit->util;
 615                        if (revs->remove_empty_trees &&
 616                            same_tree_as_empty_path(revs, p->tree,
 617                                                    util->pathname)) {
 618                                const char* new_name = find_rename(commit, p);
 619                                if (new_name) {
 620                                        struct util_info* putil = get_util(p);
 621                                        if (!putil->pathname)
 622                                                putil->pathname = xstrdup(new_name);
 623                                } else {
 624                                        *pp = parent->next;
 625                                        continue;
 626                                }
 627                        }
 628                }
 629
 630                /* fallthrough */
 631                case REV_TREE_DIFFERENT:
 632                        pp = &parent->next;
 633                        if (!get_util(p)->pathname)
 634                                get_util(p)->pathname =
 635                                        get_util(commit)->pathname;
 636                        continue;
 637                }
 638                die("bad tree compare for commit %s",
 639                    sha1_to_hex(commit->object.sha1));
 640        }
 641        commit->object.flags |= TREECHANGE;
 642}
 643
 644
 645struct commit_info
 646{
 647        char* author;
 648        char* author_mail;
 649        unsigned long author_time;
 650        char* author_tz;
 651};
 652
 653static void get_commit_info(struct commit* commit, struct commit_info* ret)
 654{
 655        int len;
 656        char* tmp;
 657        static char author_buf[1024];
 658
 659        tmp = strstr(commit->buffer, "\nauthor ") + 8;
 660        len = strchr(tmp, '\n') - tmp;
 661        ret->author = author_buf;
 662        memcpy(ret->author, tmp, len);
 663
 664        tmp = ret->author;
 665        tmp += len;
 666        *tmp = 0;
 667        while(*tmp != ' ')
 668                tmp--;
 669        ret->author_tz = tmp+1;
 670
 671        *tmp = 0;
 672        while(*tmp != ' ')
 673                tmp--;
 674        ret->author_time = strtoul(tmp, NULL, 10);
 675
 676        *tmp = 0;
 677        while(*tmp != ' ')
 678                tmp--;
 679        ret->author_mail = tmp + 1;
 680
 681        *tmp = 0;
 682}
 683
 684static const char* format_time(unsigned long time, const char* tz_str,
 685                               int show_raw_time)
 686{
 687        static char time_buf[128];
 688        time_t t = time;
 689        int minutes, tz;
 690        struct tm *tm;
 691
 692        if (show_raw_time) {
 693                sprintf(time_buf, "%lu %s", time, tz_str);
 694                return time_buf;
 695        }
 696
 697        tz = atoi(tz_str);
 698        minutes = tz < 0 ? -tz : tz;
 699        minutes = (minutes / 100)*60 + (minutes % 100);
 700        minutes = tz < 0 ? -minutes : minutes;
 701        t = time + minutes * 60;
 702        tm = gmtime(&t);
 703
 704        strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
 705        strcat(time_buf, tz_str);
 706        return time_buf;
 707}
 708
 709static void topo_setter(struct commit* c, void* data)
 710{
 711        struct util_info* util = c->util;
 712        util->topo_data = data;
 713}
 714
 715static void* topo_getter(struct commit* c)
 716{
 717        struct util_info* util = c->util;
 718        return util->topo_data;
 719}
 720
 721static int read_ancestry(const char *graft_file,
 722                         unsigned char **start_sha1)
 723{
 724        FILE *fp = fopen(graft_file, "r");
 725        char buf[1024];
 726        if (!fp)
 727                return -1;
 728        while (fgets(buf, sizeof(buf), fp)) {
 729                /* The format is just "Commit Parent1 Parent2 ...\n" */
 730                int len = strlen(buf);
 731                struct commit_graft *graft = read_graft_line(buf, len);
 732                register_commit_graft(graft, 0);
 733                if (!*start_sha1)
 734                        *start_sha1 = graft->sha1;
 735        }
 736        fclose(fp);
 737        return 0;
 738}
 739
 740int main(int argc, const char **argv)
 741{
 742        int i;
 743        struct commit *initial = NULL;
 744        unsigned char sha1[20], *sha1_p = NULL;
 745
 746        const char *filename = NULL, *commit = NULL;
 747        char filename_buf[256];
 748        int sha1_len = 8;
 749        int compatibility = 0;
 750        int show_raw_time = 0;
 751        int options = 1;
 752        struct commit* start_commit;
 753
 754        const char* args[10];
 755        struct rev_info rev;
 756
 757        struct commit_info ci;
 758        const char *buf;
 759        int max_digits;
 760        int longest_file, longest_author;
 761        int found_rename;
 762
 763        const char* prefix = setup_git_directory();
 764        git_config(git_default_config);
 765
 766        for(i = 1; i < argc; i++) {
 767                if(options) {
 768                        if(!strcmp(argv[i], "-h") ||
 769                           !strcmp(argv[i], "--help"))
 770                                usage(blame_usage);
 771                        else if(!strcmp(argv[i], "-l") ||
 772                                !strcmp(argv[i], "--long")) {
 773                                sha1_len = 40;
 774                                continue;
 775                        } else if(!strcmp(argv[i], "-c") ||
 776                                  !strcmp(argv[i], "--compatibility")) {
 777                                compatibility = 1;
 778                                continue;
 779                        } else if(!strcmp(argv[i], "-t") ||
 780                                  !strcmp(argv[i], "--time")) {
 781                                show_raw_time = 1;
 782                                continue;
 783                        } else if(!strcmp(argv[i], "-S")) {
 784                                if (i + 1 < argc &&
 785                                    !read_ancestry(argv[i + 1], &sha1_p)) {
 786                                        compatibility = 1;
 787                                        i++;
 788                                        continue;
 789                                }
 790                                usage(blame_usage);
 791                        } else if(!strcmp(argv[i], "--")) {
 792                                options = 0;
 793                                continue;
 794                        } else if(argv[i][0] == '-')
 795                                usage(blame_usage);
 796                        else
 797                                options = 0;
 798                }
 799
 800                if(!options) {
 801                        if(!filename)
 802                                filename = argv[i];
 803                        else if(!commit)
 804                                commit = argv[i];
 805                        else
 806                                usage(blame_usage);
 807                }
 808        }
 809
 810        if(!filename)
 811                usage(blame_usage);
 812        if (commit && sha1_p)
 813                usage(blame_usage);
 814        else if(!commit)
 815                commit = "HEAD";
 816
 817        if(prefix)
 818                sprintf(filename_buf, "%s%s", prefix, filename);
 819        else
 820                strcpy(filename_buf, filename);
 821        filename = filename_buf;
 822
 823        if (!sha1_p) {
 824                if (get_sha1(commit, sha1))
 825                        die("get_sha1 failed, commit '%s' not found", commit);
 826                sha1_p = sha1;
 827        }
 828        start_commit = lookup_commit_reference(sha1_p);
 829        get_util(start_commit)->pathname = filename;
 830        if (fill_util_info(start_commit)) {
 831                printf("%s not found in %s\n", filename, commit);
 832                return 1;
 833        }
 834
 835
 836        init_revisions(&rev, setup_git_directory());
 837        rev.remove_empty_trees = 1;
 838        rev.topo_order = 1;
 839        rev.prune_fn = simplify_commit;
 840        rev.topo_setter = topo_setter;
 841        rev.topo_getter = topo_getter;
 842        rev.parents = 1;
 843        rev.limited = 1;
 844
 845        commit_list_insert(start_commit, &rev.commits);
 846
 847        args[0] = filename;
 848        args[1] = NULL;
 849        diff_tree_setup_paths(args, &rev.pruning);
 850        prepare_revision_walk(&rev);
 851        process_commits(&rev, filename, &initial);
 852
 853        buf = blame_contents;
 854        for (max_digits = 1, i = 10; i <= num_blame_lines + 1; max_digits++)
 855                i *= 10;
 856
 857        longest_file = 0;
 858        longest_author = 0;
 859        found_rename = 0;
 860        for (i = 0; i < num_blame_lines; i++) {
 861                struct commit *c = blame_lines[i];
 862                struct util_info* u;
 863                if (!c)
 864                        c = initial;
 865                u = c->util;
 866
 867                if (!found_rename && strcmp(filename, u->pathname))
 868                        found_rename = 1;
 869                if (longest_file < strlen(u->pathname))
 870                        longest_file = strlen(u->pathname);
 871                get_commit_info(c, &ci);
 872                if (longest_author < strlen(ci.author))
 873                        longest_author = strlen(ci.author);
 874        }
 875
 876        for (i = 0; i < num_blame_lines; i++) {
 877                struct commit *c = blame_lines[i];
 878                struct util_info* u;
 879
 880                if (!c)
 881                        c = initial;
 882
 883                u = c->util;
 884                get_commit_info(c, &ci);
 885                fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
 886                if(compatibility) {
 887                        printf("\t(%10s\t%10s\t%d)", ci.author,
 888                               format_time(ci.author_time, ci.author_tz,
 889                                           show_raw_time),
 890                               i+1);
 891                } else {
 892                        if (found_rename)
 893                                printf(" %-*.*s", longest_file, longest_file,
 894                                       u->pathname);
 895                        printf(" (%-*.*s %10s %*d) ",
 896                               longest_author, longest_author, ci.author,
 897                               format_time(ci.author_time, ci.author_tz,
 898                                           show_raw_time),
 899                               max_digits, i+1);
 900                }
 901
 902                if(i == num_blame_lines - 1) {
 903                        fwrite(buf, blame_len - (buf - blame_contents),
 904                               1, stdout);
 905                        if(blame_contents[blame_len-1] != '\n')
 906                                putc('\n', stdout);
 907                } else {
 908                        char* next_buf = strchr(buf, '\n') + 1;
 909                        fwrite(buf, next_buf - buf, 1, stdout);
 910                        buf = next_buf;
 911                }
 912        }
 913
 914        if (DEBUG) {
 915                printf("num read blob: %d\n", num_read_blob);
 916                printf("num get patch: %d\n", num_get_patch);
 917                printf("num commits: %d\n", num_commits);
 918                printf("patch time: %f\n", patch_time / 1000000.0);
 919                printf("initial: %s\n", sha1_to_hex(initial->object.sha1));
 920        }
 921
 922        return 0;
 923}