624423142ef99e4ad0a008b738c5978bb9521467
   1#include "git-compat-util.h"
   2#include "line-range.h"
   3#include "cache.h"
   4#include "tag.h"
   5#include "blob.h"
   6#include "tree.h"
   7#include "diff.h"
   8#include "commit.h"
   9#include "decorate.h"
  10#include "revision.h"
  11#include "xdiff-interface.h"
  12#include "strbuf.h"
  13#include "log-tree.h"
  14#include "graph.h"
  15#include "line-log.h"
  16
  17static void range_set_grow(struct range_set *rs, size_t extra)
  18{
  19        ALLOC_GROW(rs->ranges, rs->nr + extra, rs->alloc);
  20}
  21
  22/* Either initialization would be fine */
  23#define RANGE_SET_INIT {0}
  24
  25static void range_set_init(struct range_set *rs, size_t prealloc)
  26{
  27        rs->alloc = rs->nr = 0;
  28        rs->ranges = NULL;
  29        if (prealloc)
  30                range_set_grow(rs, prealloc);
  31}
  32
  33static void range_set_release(struct range_set *rs)
  34{
  35        free(rs->ranges);
  36        rs->alloc = rs->nr = 0;
  37        rs->ranges = NULL;
  38}
  39
  40/* dst must be uninitialized! */
  41static void range_set_copy(struct range_set *dst, struct range_set *src)
  42{
  43        range_set_init(dst, src->nr);
  44        memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range_set));
  45        dst->nr = src->nr;
  46}
  47static void range_set_move(struct range_set *dst, struct range_set *src)
  48{
  49        range_set_release(dst);
  50        dst->ranges = src->ranges;
  51        dst->nr = src->nr;
  52        dst->alloc = src->alloc;
  53        src->ranges = NULL;
  54        src->alloc = src->nr = 0;
  55}
  56
  57/* tack on a _new_ range _at the end_ */
  58static void range_set_append(struct range_set *rs, long a, long b)
  59{
  60        assert(a <= b);
  61        assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
  62        range_set_grow(rs, 1);
  63        rs->ranges[rs->nr].start = a;
  64        rs->ranges[rs->nr].end = b;
  65        rs->nr++;
  66}
  67
  68static int range_cmp(const void *_r, const void *_s)
  69{
  70        const struct range *r = _r;
  71        const struct range *s = _s;
  72
  73        /* this could be simply 'return r.start-s.start', but for the types */
  74        if (r->start == s->start)
  75                return 0;
  76        if (r->start < s->start)
  77                return -1;
  78        return 1;
  79}
  80
  81/*
  82 * Helper: In-place pass of sorting and merging the ranges in the
  83 * range set, to re-establish the invariants after another operation
  84 *
  85 * NEEDSWORK currently not needed
  86 */
  87static void sort_and_merge_range_set(struct range_set *rs)
  88{
  89        int i;
  90        int o = 1; /* output cursor */
  91
  92        qsort(rs->ranges, rs->nr, sizeof(struct range), range_cmp);
  93
  94        for (i = 1; i < rs->nr; i++) {
  95                if (rs->ranges[i].start <= rs->ranges[o-1].end) {
  96                        rs->ranges[o-1].end = rs->ranges[i].end;
  97                } else {
  98                        rs->ranges[o].start = rs->ranges[i].start;
  99                        rs->ranges[o].end = rs->ranges[i].end;
 100                        o++;
 101                }
 102        }
 103        assert(o <= rs->nr);
 104        rs->nr = o;
 105}
 106
 107/*
 108 * Union of range sets (i.e., sets of line numbers).  Used to merge
 109 * them when searches meet at a common ancestor.
 110 *
 111 * This is also where the ranges are consolidated into canonical form:
 112 * overlapping and adjacent ranges are merged, and empty ranges are
 113 * removed.
 114 */
 115static void range_set_union(struct range_set *out,
 116                             struct range_set *a, struct range_set *b)
 117{
 118        int i = 0, j = 0, o = 0;
 119        struct range *ra = a->ranges;
 120        struct range *rb = b->ranges;
 121        /* cannot make an alias of out->ranges: it may change during grow */
 122
 123        assert(out->nr == 0);
 124        while (i < a->nr || j < b->nr) {
 125                struct range *new;
 126                if (i < a->nr && j < b->nr) {
 127                        if (ra[i].start < rb[j].start)
 128                                new = &ra[i++];
 129                        else if (ra[i].start > rb[j].start)
 130                                new = &rb[j++];
 131                        else if (ra[i].end < rb[j].end)
 132                                new = &ra[i++];
 133                        else
 134                                new = &rb[j++];
 135                } else if (i < a->nr)      /* b exhausted */
 136                        new = &ra[i++];
 137                else                       /* a exhausted */
 138                        new = &rb[j++];
 139                if (new->start == new->end)
 140                        ; /* empty range */
 141                else if (!o || out->ranges[o-1].end < new->start) {
 142                        range_set_grow(out, 1);
 143                        out->ranges[o].start = new->start;
 144                        out->ranges[o].end = new->end;
 145                        o++;
 146                } else if (out->ranges[o-1].end < new->end) {
 147                        out->ranges[o-1].end = new->end;
 148                }
 149        }
 150        out->nr = o;
 151}
 152
 153/*
 154 * Difference of range sets (out = a \ b).  Pass the "interesting"
 155 * ranges as 'a' and the target side of the diff as 'b': it removes
 156 * the ranges for which the commit is responsible.
 157 */
 158static void range_set_difference(struct range_set *out,
 159                                  struct range_set *a, struct range_set *b)
 160{
 161        int i, j =  0;
 162        for (i = 0; i < a->nr; i++) {
 163                long start = a->ranges[i].start;
 164                long end = a->ranges[i].end;
 165                while (start < end) {
 166                        while (j < b->nr && start >= b->ranges[j].end)
 167                                /*
 168                                 * a:         |-------
 169                                 * b: ------|
 170                                 */
 171                                j++;
 172                        if (j >= b->nr || end < b->ranges[j].start) {
 173                                /*
 174                                 * b exhausted, or
 175                                 * a:  ----|
 176                                 * b:         |----
 177                                 */
 178                                range_set_append(out, start, end);
 179                                break;
 180                        }
 181                        if (start >= b->ranges[j].start) {
 182                                /*
 183                                 * a:     |--????
 184                                 * b: |------|
 185                                 */
 186                                start = b->ranges[j].end;
 187                        } else if (end > b->ranges[j].start) {
 188                                /*
 189                                 * a: |-----|
 190                                 * b:    |--?????
 191                                 */
 192                                if (start < b->ranges[j].start)
 193                                        range_set_append(out, start, b->ranges[j].start);
 194                                start = b->ranges[j].end;
 195                        }
 196                }
 197        }
 198}
 199
 200static void diff_ranges_init(struct diff_ranges *diff)
 201{
 202        range_set_init(&diff->parent, 0);
 203        range_set_init(&diff->target, 0);
 204}
 205
 206static void diff_ranges_release(struct diff_ranges *diff)
 207{
 208        range_set_release(&diff->parent);
 209        range_set_release(&diff->target);
 210}
 211
 212void line_log_data_init(struct line_log_data *r)
 213{
 214        memset(r, 0, sizeof(struct line_log_data));
 215        range_set_init(&r->ranges, 0);
 216}
 217
 218static void line_log_data_clear(struct line_log_data *r)
 219{
 220        range_set_release(&r->ranges);
 221        if (r->pair)
 222                diff_free_filepair(r->pair);
 223}
 224
 225static void free_line_log_data(struct line_log_data *r)
 226{
 227        while (r) {
 228                struct line_log_data *next = r->next;
 229                line_log_data_clear(r);
 230                free(r);
 231                r = next;
 232        }
 233}
 234
 235static struct line_log_data *
 236search_line_log_data(struct line_log_data *list, const char *path,
 237                     struct line_log_data **insertion_point)
 238{
 239        struct line_log_data *p = list;
 240        if (insertion_point)
 241                *insertion_point = NULL;
 242        while (p) {
 243                int cmp = strcmp(p->spec->path, path);
 244                if (!cmp)
 245                        return p;
 246                if (insertion_point && cmp < 0)
 247                        *insertion_point = p;
 248                p = p->next;
 249        }
 250        return NULL;
 251}
 252
 253static void line_log_data_insert(struct line_log_data **list,
 254                                 struct diff_filespec *spec,
 255                                 long begin, long end)
 256{
 257        struct line_log_data *ip;
 258        struct line_log_data *p = search_line_log_data(*list, spec->path, &ip);
 259
 260        if (p) {
 261                range_set_append(&p->ranges, begin, end);
 262                sort_and_merge_range_set(&p->ranges);
 263                free_filespec(spec);
 264                return;
 265        }
 266
 267        p = xcalloc(1, sizeof(struct line_log_data));
 268        p->spec = spec;
 269        range_set_append(&p->ranges, begin, end);
 270        if (ip) {
 271                p->next = ip->next;
 272                ip->next = p;
 273        } else {
 274                p->next = *list;
 275                *list = p;
 276        }
 277}
 278
 279struct collect_diff_cbdata {
 280        struct diff_ranges *diff;
 281};
 282
 283static int collect_diff_cb(long start_a, long count_a,
 284                           long start_b, long count_b,
 285                           void *data)
 286{
 287        struct collect_diff_cbdata *d = data;
 288
 289        if (count_a >= 0)
 290                range_set_append(&d->diff->parent, start_a, start_a + count_a);
 291        if (count_b >= 0)
 292                range_set_append(&d->diff->target, start_b, start_b + count_b);
 293
 294        return 0;
 295}
 296
 297static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
 298{
 299        struct collect_diff_cbdata cbdata = {NULL};
 300        xpparam_t xpp;
 301        xdemitconf_t xecfg;
 302        xdemitcb_t ecb;
 303
 304        memset(&xpp, 0, sizeof(xpp));
 305        memset(&xecfg, 0, sizeof(xecfg));
 306        xecfg.ctxlen = xecfg.interhunkctxlen = 0;
 307
 308        cbdata.diff = out;
 309        xecfg.hunk_func = collect_diff_cb;
 310        memset(&ecb, 0, sizeof(ecb));
 311        ecb.priv = &cbdata;
 312        xdi_diff(parent, target, &xpp, &xecfg, &ecb);
 313}
 314
 315/*
 316 * These are handy for debugging.  Removing them with #if 0 silences
 317 * the "unused function" warning.
 318 */
 319#if 0
 320static void dump_range_set(struct range_set *rs, const char *desc)
 321{
 322        int i;
 323        printf("range set %s (%d items):\n", desc, rs->nr);
 324        for (i = 0; i < rs->nr; i++)
 325                printf("\t[%ld,%ld]\n", rs->ranges[i].start, rs->ranges[i].end);
 326}
 327
 328static void dump_line_log_data(struct line_log_data *r)
 329{
 330        char buf[4096];
 331        while (r) {
 332                snprintf(buf, 4096, "file %s\n", r->spec->path);
 333                dump_range_set(&r->ranges, buf);
 334                r = r->next;
 335        }
 336}
 337
 338static void dump_diff_ranges(struct diff_ranges *diff, const char *desc)
 339{
 340        int i;
 341        assert(diff->parent.nr == diff->target.nr);
 342        printf("diff ranges %s (%d items):\n", desc, diff->parent.nr);
 343        printf("\tparent\ttarget\n");
 344        for (i = 0; i < diff->parent.nr; i++) {
 345                printf("\t[%ld,%ld]\t[%ld,%ld]\n",
 346                       diff->parent.ranges[i].start,
 347                       diff->parent.ranges[i].end,
 348                       diff->target.ranges[i].start,
 349                       diff->target.ranges[i].end);
 350        }
 351}
 352#endif
 353
 354
 355static int ranges_overlap(struct range *a, struct range *b)
 356{
 357        return !(a->end <= b->start || b->end <= a->start);
 358}
 359
 360/*
 361 * Given a diff and the set of interesting ranges, determine all hunks
 362 * of the diff which touch (overlap) at least one of the interesting
 363 * ranges in the target.
 364 */
 365static void diff_ranges_filter_touched(struct diff_ranges *out,
 366                                       struct diff_ranges *diff,
 367                                       struct range_set *rs)
 368{
 369        int i, j = 0;
 370
 371        assert(out->target.nr == 0);
 372
 373        for (i = 0; i < diff->target.nr; i++) {
 374                while (diff->target.ranges[i].start > rs->ranges[j].end) {
 375                        j++;
 376                        if (j == rs->nr)
 377                                return;
 378                }
 379                if (ranges_overlap(&diff->target.ranges[i], &rs->ranges[j])) {
 380                        range_set_append(&out->parent,
 381                                         diff->parent.ranges[i].start,
 382                                         diff->parent.ranges[i].end);
 383                        range_set_append(&out->target,
 384                                         diff->target.ranges[i].start,
 385                                         diff->target.ranges[i].end);
 386                }
 387        }
 388}
 389
 390/*
 391 * Adjust the line counts in 'rs' to account for the lines
 392 * added/removed in the diff.
 393 */
 394static void range_set_shift_diff(struct range_set *out,
 395                                 struct range_set *rs,
 396                                 struct diff_ranges *diff)
 397{
 398        int i, j = 0;
 399        long offset = 0;
 400        struct range *src = rs->ranges;
 401        struct range *target = diff->target.ranges;
 402        struct range *parent = diff->parent.ranges;
 403
 404        for (i = 0; i < rs->nr; i++) {
 405                while (j < diff->target.nr && src[i].start >= target[j].start) {
 406                        offset += (parent[j].end-parent[j].start)
 407                                - (target[j].end-target[j].start);
 408                        j++;
 409                }
 410                range_set_append(out, src[i].start+offset, src[i].end+offset);
 411        }
 412}
 413
 414/*
 415 * Given a diff and the set of interesting ranges, map the ranges
 416 * across the diff.  That is: observe that the target commit takes
 417 * blame for all the + (target-side) ranges.  So for every pair of
 418 * ranges in the diff that was touched, we remove the latter and add
 419 * its parent side.
 420 */
 421static void range_set_map_across_diff(struct range_set *out,
 422                                      struct range_set *rs,
 423                                      struct diff_ranges *diff,
 424                                      struct diff_ranges **touched_out)
 425{
 426        struct diff_ranges *touched = xmalloc(sizeof(*touched));
 427        struct range_set tmp1 = RANGE_SET_INIT;
 428        struct range_set tmp2 = RANGE_SET_INIT;
 429
 430        diff_ranges_init(touched);
 431        diff_ranges_filter_touched(touched, diff, rs);
 432        range_set_difference(&tmp1, rs, &touched->target);
 433        range_set_shift_diff(&tmp2, &tmp1, diff);
 434        range_set_union(out, &tmp2, &touched->parent);
 435        range_set_release(&tmp1);
 436        range_set_release(&tmp2);
 437
 438        *touched_out = touched;
 439}
 440
 441
 442static struct commit *check_single_commit(struct rev_info *revs)
 443{
 444        struct object *commit = NULL;
 445        int found = -1;
 446        int i;
 447
 448        for (i = 0; i < revs->pending.nr; i++) {
 449                struct object *obj = revs->pending.objects[i].item;
 450                if (obj->flags & UNINTERESTING)
 451                        continue;
 452                while (obj->type == OBJ_TAG)
 453                        obj = deref_tag(obj, NULL, 0);
 454                if (obj->type != OBJ_COMMIT)
 455                        die("Non commit %s?", revs->pending.objects[i].name);
 456                if (commit)
 457                        die("More than one commit to dig from: %s and %s?",
 458                            revs->pending.objects[i].name,
 459                            revs->pending.objects[found].name);
 460                commit = obj;
 461                found = i;
 462        }
 463
 464        if (!commit)
 465                die("No commit specified?");
 466
 467        return (struct commit *) commit;
 468}
 469
 470static void fill_blob_sha1(struct commit *commit, struct diff_filespec *spec)
 471{
 472        unsigned mode;
 473        unsigned char sha1[20];
 474
 475        if (get_tree_entry(commit->object.sha1, spec->path,
 476                           sha1, &mode))
 477                die("There is no path %s in the commit", spec->path);
 478        fill_filespec(spec, sha1, 1, mode);
 479
 480        return;
 481}
 482
 483static void fill_line_ends(struct diff_filespec *spec, long *lines,
 484                           unsigned long **line_ends)
 485{
 486        int num = 0, size = 50;
 487        long cur = 0;
 488        unsigned long *ends = NULL;
 489        char *data = NULL;
 490
 491        if (diff_populate_filespec(spec, 0))
 492                die("Cannot read blob %s", sha1_to_hex(spec->sha1));
 493
 494        ends = xmalloc(size * sizeof(*ends));
 495        ends[cur++] = 0;
 496        data = spec->data;
 497        while (num < spec->size) {
 498                if (data[num] == '\n' || num == spec->size - 1) {
 499                        ALLOC_GROW(ends, (cur + 1), size);
 500                        ends[cur++] = num;
 501                }
 502                num++;
 503        }
 504
 505        /* shrink the array to fit the elements */
 506        ends = xrealloc(ends, cur * sizeof(*ends));
 507        *lines = cur-1;
 508        *line_ends = ends;
 509}
 510
 511struct nth_line_cb {
 512        struct diff_filespec *spec;
 513        long lines;
 514        unsigned long *line_ends;
 515};
 516
 517static const char *nth_line(void *data, long line)
 518{
 519        struct nth_line_cb *d = data;
 520        assert(d && line <= d->lines);
 521        assert(d->spec && d->spec->data);
 522
 523        if (line == 0)
 524                return (char *)d->spec->data;
 525        else
 526                return (char *)d->spec->data + d->line_ends[line] + 1;
 527}
 528
 529static struct line_log_data *
 530parse_lines(struct commit *commit, const char *prefix, struct string_list *args)
 531{
 532        long lines = 0;
 533        unsigned long *ends = NULL;
 534        struct nth_line_cb cb_data;
 535        struct string_list_item *item;
 536        struct line_log_data *ranges = NULL;
 537
 538        for_each_string_list_item(item, args) {
 539                const char *name_part, *range_part;
 540                const char *full_name;
 541                struct diff_filespec *spec;
 542                long begin = 0, end = 0;
 543
 544                name_part = skip_range_arg(item->string);
 545                if (!name_part || *name_part != ':' || !name_part[1])
 546                        die("-L argument '%s' not of the form start,end:file",
 547                            item->string);
 548                range_part = xstrndup(item->string, name_part - item->string);
 549                name_part++;
 550
 551                full_name = prefix_path(prefix, prefix ? strlen(prefix) : 0,
 552                                        name_part);
 553
 554                spec = alloc_filespec(full_name);
 555                fill_blob_sha1(commit, spec);
 556                fill_line_ends(spec, &lines, &ends);
 557                cb_data.spec = spec;
 558                cb_data.lines = lines;
 559                cb_data.line_ends = ends;
 560
 561                if (parse_range_arg(range_part, nth_line, &cb_data,
 562                                    lines, &begin, &end))
 563                        die("malformed -L argument '%s'", range_part);
 564                if (begin < 1)
 565                        begin = 1;
 566                if (end < 1)
 567                        end = lines;
 568                begin--;
 569                if (lines < end || lines < begin)
 570                        die("file %s has only %ld lines", name_part, lines);
 571                line_log_data_insert(&ranges, spec, begin, end);
 572
 573                free(ends);
 574                ends = NULL;
 575        }
 576
 577        return ranges;
 578}
 579
 580static struct line_log_data *line_log_data_copy_one(struct line_log_data *r)
 581{
 582        struct line_log_data *ret = xmalloc(sizeof(*ret));
 583
 584        assert(r);
 585        line_log_data_init(ret);
 586        range_set_copy(&ret->ranges, &r->ranges);
 587
 588        ret->spec = r->spec;
 589        assert(ret->spec);
 590        ret->spec->count++;
 591
 592        return ret;
 593}
 594
 595static struct line_log_data *
 596line_log_data_copy(struct line_log_data *r)
 597{
 598        struct line_log_data *ret = NULL;
 599        struct line_log_data *tmp = NULL, *prev = NULL;
 600
 601        assert(r);
 602        ret = tmp = prev = line_log_data_copy_one(r);
 603        r = r->next;
 604        while (r) {
 605                tmp = line_log_data_copy_one(r);
 606                prev->next = tmp;
 607                prev = tmp;
 608                r = r->next;
 609        }
 610
 611        return ret;
 612}
 613
 614/* merge two range sets across files */
 615static struct line_log_data *line_log_data_merge(struct line_log_data *a,
 616                                                 struct line_log_data *b)
 617{
 618        struct line_log_data *head = NULL, **pp = &head;
 619
 620        while (a || b) {
 621                struct line_log_data *src;
 622                struct line_log_data *src2 = NULL;
 623                struct line_log_data *d;
 624                int cmp;
 625                if (!a)
 626                        cmp = 1;
 627                else if (!b)
 628                        cmp = -1;
 629                else
 630                        cmp = strcmp(a->spec->path, b->spec->path);
 631                if (cmp < 0) {
 632                        src = a;
 633                        a = a->next;
 634                } else if (cmp == 0) {
 635                        src = a;
 636                        a = a->next;
 637                        src2 = b;
 638                        b = b->next;
 639                } else {
 640                        src = b;
 641                        b = b->next;
 642                }
 643                d = xmalloc(sizeof(struct line_log_data));
 644                line_log_data_init(d);
 645                d->spec = src->spec;
 646                d->spec->count++;
 647                *pp = d;
 648                pp = &d->next;
 649                if (src2)
 650                        range_set_union(&d->ranges, &src->ranges, &src2->ranges);
 651                else
 652                        range_set_copy(&d->ranges, &src->ranges);
 653        }
 654
 655        return head;
 656}
 657
 658static void add_line_range(struct rev_info *revs, struct commit *commit,
 659                           struct line_log_data *range)
 660{
 661        struct line_log_data *old = NULL;
 662        struct line_log_data *new = NULL;
 663
 664        old = lookup_decoration(&revs->line_log_data, &commit->object);
 665        if (old && range) {
 666                new = line_log_data_merge(old, range);
 667                free_line_log_data(old);
 668        } else if (range)
 669                new = line_log_data_copy(range);
 670
 671        if (new)
 672                add_decoration(&revs->line_log_data, &commit->object, new);
 673}
 674
 675static void clear_commit_line_range(struct rev_info *revs, struct commit *commit)
 676{
 677        struct line_log_data *r;
 678        r = lookup_decoration(&revs->line_log_data, &commit->object);
 679        if (!r)
 680                return;
 681        free_line_log_data(r);
 682        add_decoration(&revs->line_log_data, &commit->object, NULL);
 683}
 684
 685static struct line_log_data *lookup_line_range(struct rev_info *revs,
 686                                               struct commit *commit)
 687{
 688        struct line_log_data *ret = NULL;
 689
 690        ret = lookup_decoration(&revs->line_log_data, &commit->object);
 691        return ret;
 692}
 693
 694void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args)
 695{
 696        struct commit *commit = NULL;
 697        struct line_log_data *range;
 698
 699        commit = check_single_commit(rev);
 700        range = parse_lines(commit, prefix, args);
 701        add_line_range(rev, commit, range);
 702
 703        if (!rev->diffopt.detect_rename) {
 704                int i, count = 0;
 705                struct line_log_data *r = range;
 706                const char **paths;
 707                while (r) {
 708                        count++;
 709                        r = r->next;
 710                }
 711                paths = xmalloc((count+1)*sizeof(char *));
 712                r = range;
 713                for (i = 0; i < count; i++) {
 714                        paths[i] = xstrdup(r->spec->path);
 715                        r = r->next;
 716                }
 717                paths[count] = NULL;
 718                init_pathspec(&rev->diffopt.pathspec, paths);
 719                free(paths);
 720        }
 721}
 722
 723static void load_tree_desc(struct tree_desc *desc, void **tree,
 724                           const unsigned char *sha1)
 725{
 726        unsigned long size;
 727        *tree = read_object_with_reference(sha1, tree_type, &size, NULL);
 728        if (!*tree)
 729                die("Unable to read tree (%s)", sha1_to_hex(sha1));
 730        init_tree_desc(desc, *tree, size);
 731}
 732
 733static int count_parents(struct commit *commit)
 734{
 735        struct commit_list *parents = commit->parents;
 736        int count = 0;
 737        while (parents) {
 738                count++;
 739                parents = parents->next;
 740        }
 741        return count;
 742}
 743
 744static void move_diff_queue(struct diff_queue_struct *dst,
 745                            struct diff_queue_struct *src)
 746{
 747        assert(src != dst);
 748        memcpy(dst, src, sizeof(struct diff_queue_struct));
 749        DIFF_QUEUE_CLEAR(src);
 750}
 751
 752static void queue_diffs(struct diff_options *opt,
 753                        struct diff_queue_struct *queue,
 754                        struct commit *commit, struct commit *parent)
 755{
 756        void *tree1 = NULL, *tree2 = NULL;
 757        struct tree_desc desc1, desc2;
 758
 759        assert(commit);
 760        load_tree_desc(&desc2, &tree2, commit->tree->object.sha1);
 761        if (parent)
 762                load_tree_desc(&desc1, &tree1, parent->tree->object.sha1);
 763        else
 764                init_tree_desc(&desc1, "", 0);
 765
 766        DIFF_QUEUE_CLEAR(&diff_queued_diff);
 767        diff_tree(&desc1, &desc2, "", opt);
 768        diffcore_std(opt);
 769        move_diff_queue(queue, &diff_queued_diff);
 770
 771        if (tree1)
 772                free(tree1);
 773        if (tree2)
 774                free(tree2);
 775}
 776
 777static char *get_nth_line(long line, unsigned long *ends, void *data)
 778{
 779        if (line == 0)
 780                return (char *)data;
 781        else
 782                return (char *)data + ends[line] + 1;
 783}
 784
 785static void print_line(const char *prefix, char first,
 786                       long line, unsigned long *ends, void *data,
 787                       const char *color, const char *reset)
 788{
 789        char *begin = get_nth_line(line, ends, data);
 790        char *end = get_nth_line(line+1, ends, data);
 791        int had_nl = 0;
 792
 793        if (end > begin && end[-1] == '\n') {
 794                end--;
 795                had_nl = 1;
 796        }
 797
 798        fputs(prefix, stdout);
 799        fputs(color, stdout);
 800        putchar(first);
 801        fwrite(begin, 1, end-begin, stdout);
 802        fputs(reset, stdout);
 803        putchar('\n');
 804        if (!had_nl)
 805                fputs("\\ No newline at end of file\n", stdout);
 806}
 807
 808static char *output_prefix(struct diff_options *opt)
 809{
 810        char *prefix = "";
 811
 812        if (opt->output_prefix) {
 813                struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data);
 814                prefix = sb->buf;
 815        }
 816
 817        return prefix;
 818}
 819
 820static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
 821{
 822        int i, j = 0;
 823        long p_lines, t_lines;
 824        unsigned long *p_ends = NULL, *t_ends = NULL;
 825        struct diff_filepair *pair = range->pair;
 826        struct diff_ranges *diff = &range->diff;
 827
 828        struct diff_options *opt = &rev->diffopt;
 829        char *prefix = output_prefix(opt);
 830        const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
 831        const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
 832        const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
 833        const char *c_old = diff_get_color(opt->use_color, DIFF_FILE_OLD);
 834        const char *c_new = diff_get_color(opt->use_color, DIFF_FILE_NEW);
 835        const char *c_plain = diff_get_color(opt->use_color, DIFF_PLAIN);
 836
 837        if (!pair || !diff)
 838                return;
 839
 840        if (pair->one->sha1_valid)
 841                fill_line_ends(pair->one, &p_lines, &p_ends);
 842        fill_line_ends(pair->two, &t_lines, &t_ends);
 843
 844        printf("%s%sdiff --git a/%s b/%s%s\n", prefix, c_meta, pair->one->path, pair->two->path, c_reset);
 845        printf("%s%s--- %s%s%s\n", prefix, c_meta,
 846               pair->one->sha1_valid ? "a/" : "",
 847               pair->one->sha1_valid ? pair->one->path : "/dev/null",
 848               c_reset);
 849        printf("%s%s+++ b/%s%s\n", prefix, c_meta, pair->two->path, c_reset);
 850        for (i = 0; i < range->ranges.nr; i++) {
 851                long p_start, p_end;
 852                long t_start = range->ranges.ranges[i].start;
 853                long t_end = range->ranges.ranges[i].end;
 854                long t_cur = t_start;
 855                int j_last;
 856
 857                while (j < diff->target.nr && diff->target.ranges[j].end < t_start)
 858                        j++;
 859                if (j == diff->target.nr || diff->target.ranges[j].start > t_end)
 860                        continue;
 861
 862                /* Scan ahead to determine the last diff that falls in this range */
 863                j_last = j;
 864                while (j_last < diff->target.nr && diff->target.ranges[j_last].start < t_end)
 865                        j_last++;
 866                if (j_last > j)
 867                        j_last--;
 868
 869                /*
 870                 * Compute parent hunk headers: we know that the diff
 871                 * has the correct line numbers (but not all hunks).
 872                 * So it suffices to shift the start/end according to
 873                 * the line numbers of the first/last hunk(s) that
 874                 * fall in this range.
 875                 */
 876                if (t_start < diff->target.ranges[j].start)
 877                        p_start = diff->parent.ranges[j].start - (diff->target.ranges[j].start-t_start);
 878                else
 879                        p_start = diff->parent.ranges[j].start;
 880                if (t_end > diff->target.ranges[j_last].end)
 881                        p_end = diff->parent.ranges[j_last].end + (t_end-diff->target.ranges[j_last].end);
 882                else
 883                        p_end = diff->parent.ranges[j_last].end;
 884
 885                if (!p_start && !p_end) {
 886                        p_start = -1;
 887                        p_end = -1;
 888                }
 889
 890                /* Now output a diff hunk for this range */
 891                printf("%s%s@@ -%ld,%ld +%ld,%ld @@%s\n",
 892                       prefix, c_frag,
 893                       p_start+1, p_end-p_start, t_start+1, t_end-t_start,
 894                       c_reset);
 895                while (j < diff->target.nr && diff->target.ranges[j].start < t_end) {
 896                        int k;
 897                        for (; t_cur < diff->target.ranges[j].start; t_cur++)
 898                                print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
 899                                           c_plain, c_reset);
 900                        for (k = diff->parent.ranges[j].start; k < diff->parent.ranges[j].end; k++)
 901                                print_line(prefix, '-', k, p_ends, pair->one->data,
 902                                           c_old, c_reset);
 903                        for (; t_cur < diff->target.ranges[j].end && t_cur < t_end; t_cur++)
 904                                print_line(prefix, '+', t_cur, t_ends, pair->two->data,
 905                                           c_new, c_reset);
 906                        j++;
 907                }
 908                for (; t_cur < t_end; t_cur++)
 909                        print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
 910                                   c_plain, c_reset);
 911        }
 912
 913        free(p_ends);
 914        free(t_ends);
 915}
 916
 917/*
 918 * NEEDSWORK: manually building a diff here is not the Right
 919 * Thing(tm).  log -L should be built into the diff pipeline.
 920 */
 921static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
 922{
 923        puts(output_prefix(&rev->diffopt));
 924        while (range) {
 925                dump_diff_hacky_one(rev, range);
 926                range = range->next;
 927        }
 928}
 929
 930/*
 931 * Unlike most other functions, this destructively operates on
 932 * 'range'.
 933 */
 934static int process_diff_filepair(struct rev_info *rev,
 935                                 struct diff_filepair *pair,
 936                                 struct line_log_data *range,
 937                                 struct diff_ranges **diff_out)
 938{
 939        struct line_log_data *rg = range;
 940        struct range_set tmp;
 941        struct diff_ranges diff;
 942        mmfile_t file_parent, file_target;
 943
 944        assert(pair->two->path);
 945        while (rg) {
 946                assert(rg->spec->path);
 947                if (!strcmp(rg->spec->path, pair->two->path))
 948                        break;
 949                rg = rg->next;
 950        }
 951
 952        if (!rg)
 953                return 0;
 954        if (rg->ranges.nr == 0)
 955                return 0;
 956
 957        assert(pair->two->sha1_valid);
 958        diff_populate_filespec(pair->two, 0);
 959        file_target.ptr = pair->two->data;
 960        file_target.size = pair->two->size;
 961
 962        if (pair->one->sha1_valid) {
 963                diff_populate_filespec(pair->one, 0);
 964                file_parent.ptr = pair->one->data;
 965                file_parent.size = pair->one->size;
 966        } else {
 967                file_parent.ptr = "";
 968                file_parent.size = 0;
 969        }
 970
 971        diff_ranges_init(&diff);
 972        collect_diff(&file_parent, &file_target, &diff);
 973
 974        /* NEEDSWORK should apply some heuristics to prevent mismatches */
 975        rg->spec->path = xstrdup(pair->one->path);
 976
 977        range_set_init(&tmp, 0);
 978        range_set_map_across_diff(&tmp, &rg->ranges, &diff, diff_out);
 979        range_set_release(&rg->ranges);
 980        range_set_move(&rg->ranges, &tmp);
 981
 982        diff_ranges_release(&diff);
 983
 984        return ((*diff_out)->parent.nr > 0);
 985}
 986
 987static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
 988{
 989        struct diff_filepair *new = xmalloc(sizeof(struct diff_filepair));
 990        new->one = pair->one;
 991        new->two = pair->two;
 992        new->one->count++;
 993        new->two->count++;
 994        return new;
 995}
 996
 997static void free_diffqueues(int n, struct diff_queue_struct *dq)
 998{
 999        int i, j;
1000        for (i = 0; i < n; i++)
1001                for (j = 0; j < dq[i].nr; j++)
1002                        diff_free_filepair(dq[i].queue[j]);
1003        free(dq);
1004}
1005
1006static int process_all_files(struct line_log_data **range_out,
1007                             struct rev_info *rev,
1008                             struct diff_queue_struct *queue,
1009                             struct line_log_data *range)
1010{
1011        int i, changed = 0;
1012
1013        *range_out = line_log_data_copy(range);
1014
1015        for (i = 0; i < queue->nr; i++) {
1016                struct diff_ranges *pairdiff = NULL;
1017                if (process_diff_filepair(rev, queue->queue[i], *range_out, &pairdiff)) {
1018                        struct line_log_data *rg = range;
1019                        changed++;
1020                        /* NEEDSWORK tramples over data structures not owned here */
1021                        while (rg && strcmp(rg->spec->path, queue->queue[i]->two->path))
1022                                rg = rg->next;
1023                        assert(rg);
1024                        rg->pair = diff_filepair_dup(queue->queue[i]);
1025                        memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges));
1026                }
1027        }
1028
1029        return changed;
1030}
1031
1032int line_log_print(struct rev_info *rev, struct commit *commit)
1033{
1034        struct line_log_data *range = lookup_line_range(rev, commit);
1035
1036        show_log(rev);
1037        dump_diff_hacky(rev, range);
1038        return 1;
1039}
1040
1041static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *commit,
1042                                          struct line_log_data *range)
1043{
1044        struct commit *parent = NULL;
1045        struct diff_queue_struct queue;
1046        struct line_log_data *parent_range;
1047        int changed;
1048
1049        if (commit->parents)
1050                parent = commit->parents->item;
1051
1052        queue_diffs(&rev->diffopt, &queue, commit, parent);
1053        changed = process_all_files(&parent_range, rev, &queue, range);
1054        if (parent)
1055                add_line_range(rev, parent, parent_range);
1056        return changed;
1057}
1058
1059static int process_ranges_merge_commit(struct rev_info *rev, struct commit *commit,
1060                                       struct line_log_data *range)
1061{
1062        struct diff_queue_struct *diffqueues;
1063        struct line_log_data **cand;
1064        struct commit **parents;
1065        struct commit_list *p;
1066        int i;
1067        int nparents = count_parents(commit);
1068
1069        diffqueues = xmalloc(nparents * sizeof(*diffqueues));
1070        cand = xmalloc(nparents * sizeof(*cand));
1071        parents = xmalloc(nparents * sizeof(*parents));
1072
1073        p = commit->parents;
1074        for (i = 0; i < nparents; i++) {
1075                parents[i] = p->item;
1076                p = p->next;
1077                queue_diffs(&rev->diffopt, &diffqueues[i], commit, parents[i]);
1078        }
1079
1080        for (i = 0; i < nparents; i++) {
1081                int changed;
1082                cand[i] = NULL;
1083                changed = process_all_files(&cand[i], rev, &diffqueues[i], range);
1084                if (!changed) {
1085                        /*
1086                         * This parent can take all the blame, so we
1087                         * don't follow any other path in history
1088                         */
1089                        add_line_range(rev, parents[i], cand[i]);
1090                        clear_commit_line_range(rev, commit);
1091                        commit->parents = xmalloc(sizeof(struct commit_list));
1092                        commit->parents->item = parents[i];
1093                        commit->parents->next = NULL;
1094                        free(parents);
1095                        free(cand);
1096                        free_diffqueues(nparents, diffqueues);
1097                        /* NEEDSWORK leaking like a sieve */
1098                        return 0;
1099                }
1100        }
1101
1102        /*
1103         * No single parent took the blame.  We add the candidates
1104         * from the above loop to the parents.
1105         */
1106        for (i = 0; i < nparents; i++) {
1107                add_line_range(rev, parents[i], cand[i]);
1108        }
1109
1110        clear_commit_line_range(rev, commit);
1111        free(parents);
1112        free(cand);
1113        free_diffqueues(nparents, diffqueues);
1114        return 1;
1115
1116        /* NEEDSWORK evil merge detection stuff */
1117        /* NEEDSWORK leaking like a sieve */
1118}
1119
1120static int process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)
1121{
1122        struct line_log_data *range = lookup_line_range(rev, commit);
1123        int changed = 0;
1124
1125        if (range) {
1126                if (!commit->parents || !commit->parents->next)
1127                        changed = process_ranges_ordinary_commit(rev, commit, range);
1128                else
1129                        changed = process_ranges_merge_commit(rev, commit, range);
1130        }
1131
1132        if (!changed)
1133                commit->object.flags |= TREESAME;
1134
1135        return changed;
1136}
1137
1138static enum rewrite_result line_log_rewrite_one(struct rev_info *rev, struct commit **pp)
1139{
1140        for (;;) {
1141                struct commit *p = *pp;
1142                if (p->parents && p->parents->next)
1143                        return rewrite_one_ok;
1144                if (p->object.flags & UNINTERESTING)
1145                        return rewrite_one_ok;
1146                if (!(p->object.flags & TREESAME))
1147                        return rewrite_one_ok;
1148                if (!p->parents)
1149                        return rewrite_one_noparents;
1150                *pp = p->parents->item;
1151        }
1152}
1153
1154int line_log_filter(struct rev_info *rev)
1155{
1156        struct commit *commit;
1157        struct commit_list *list = rev->commits;
1158        struct commit_list *out = NULL, **pp = &out;
1159
1160        while (list) {
1161                struct commit_list *to_free = NULL;
1162                commit = list->item;
1163                if (process_ranges_arbitrary_commit(rev, commit)) {
1164                        *pp = list;
1165                        pp = &list->next;
1166                } else
1167                        to_free = list;
1168                list = list->next;
1169                free(to_free);
1170        }
1171        *pp = NULL;
1172
1173        for (list = out; list; list = list->next)
1174                rewrite_parents(rev, list->item, line_log_rewrite_one);
1175
1176        rev->commits = out;
1177
1178        return 0;
1179}