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