bafbc09808d393ceddc0c0445d322568b2007853
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include <sys/types.h>
   5#include <sys/wait.h>
   6#include <signal.h>
   7#include "cache.h"
   8#include "diff.h"
   9#include "diffcore.h"
  10
  11static const char *diff_opts = "-pu";
  12static unsigned char null_sha1[20] = { 0, };
  13
  14static int reverse_diff;
  15
  16static const char *external_diff(void)
  17{
  18        static const char *external_diff_cmd = NULL;
  19        static int done_preparing = 0;
  20
  21        if (done_preparing)
  22                return external_diff_cmd;
  23
  24        /*
  25         * Default values above are meant to match the
  26         * Linux kernel development style.  Examples of
  27         * alternative styles you can specify via environment
  28         * variables are:
  29         *
  30         * GIT_DIFF_OPTS="-c";
  31         */
  32        if (gitenv("GIT_EXTERNAL_DIFF"))
  33                external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF");
  34
  35        /* In case external diff fails... */
  36        diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts;
  37
  38        done_preparing = 1;
  39        return external_diff_cmd;
  40}
  41
  42/* Help to copy the thing properly quoted for the shell safety.
  43 * any single quote is replaced with '\'', and the caller is
  44 * expected to enclose the result within a single quote pair.
  45 *
  46 * E.g.
  47 *  original     sq_expand     result
  48 *  name     ==> name      ==> 'name'
  49 *  a b      ==> a b       ==> 'a b'
  50 *  a'b      ==> a'\''b    ==> 'a'\''b'
  51 */
  52static char *sq_expand(const char *src)
  53{
  54        static char *buf = NULL;
  55        int cnt, c;
  56        const char *cp;
  57        char *bp;
  58
  59        /* count bytes needed to store the quoted string. */
  60        for (cnt = 1, cp = src; *cp; cnt++, cp++)
  61                if (*cp == '\'')
  62                        cnt += 3;
  63
  64        buf = xmalloc(cnt);
  65        bp = buf;
  66        while ((c = *src++)) {
  67                if (c != '\'')
  68                        *bp++ = c;
  69                else {
  70                        bp = strcpy(bp, "'\\''");
  71                        bp += 4;
  72                }
  73        }
  74        *bp = 0;
  75        return buf;
  76}
  77
  78static struct diff_tempfile {
  79        const char *name; /* filename external diff should read from */
  80        char hex[41];
  81        char mode[10];
  82        char tmp_path[50];
  83} diff_temp[2];
  84
  85static void builtin_diff(const char *name_a,
  86                         const char *name_b,
  87                         struct diff_tempfile *temp,
  88                         const char *xfrm_msg)
  89{
  90        int i, next_at, cmd_size;
  91        const char *diff_cmd = "diff -L'%s%s' -L'%s%s'";
  92        const char *diff_arg  = "'%s' '%s'||:"; /* "||:" is to return 0 */
  93        const char *input_name_sq[2];
  94        const char *path0[2];
  95        const char *path1[2];
  96        const char *name_sq[2];
  97        char *cmd;
  98
  99        name_sq[0] = sq_expand(name_a);
 100        name_sq[1] = sq_expand(name_b);
 101
 102        /* diff_cmd and diff_arg have 6 %s in total which makes
 103         * the sum of these strings 12 bytes larger than required.
 104         * we use 2 spaces around diff-opts, and we need to count
 105         * terminating NUL, so we subtract 9 here.
 106         */
 107        cmd_size = (strlen(diff_cmd) + strlen(diff_opts) +
 108                        strlen(diff_arg) - 9);
 109        for (i = 0; i < 2; i++) {
 110                input_name_sq[i] = sq_expand(temp[i].name);
 111                if (!strcmp(temp[i].name, "/dev/null")) {
 112                        path0[i] = "/dev/null";
 113                        path1[i] = "";
 114                } else {
 115                        path0[i] = i ? "b/" : "a/";
 116                        path1[i] = name_sq[i];
 117                }
 118                cmd_size += (strlen(path0[i]) + strlen(path1[i]) +
 119                             strlen(input_name_sq[i]));
 120        }
 121
 122        cmd = xmalloc(cmd_size);
 123
 124        next_at = 0;
 125        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 126                            diff_cmd,
 127                            path0[0], path1[0], path0[1], path1[1]);
 128        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 129                            " %s ", diff_opts);
 130        next_at += snprintf(cmd+next_at, cmd_size-next_at,
 131                            diff_arg, input_name_sq[0], input_name_sq[1]);
 132
 133        printf("diff --git a/%s b/%s\n", name_a, name_b);
 134        if (!path1[0][0])
 135                printf("new file mode %s\n", temp[1].mode);
 136        else if (!path1[1][0])
 137                printf("deleted file mode %s\n", temp[0].mode);
 138        else {
 139                if (strcmp(temp[0].mode, temp[1].mode)) {
 140                        printf("old mode %s\n", temp[0].mode);
 141                        printf("new mode %s\n", temp[1].mode);
 142                }
 143                if (xfrm_msg && xfrm_msg[0])
 144                        puts(xfrm_msg);
 145
 146                if (strncmp(temp[0].mode, temp[1].mode, 3))
 147                        /* we do not run diff between different kind
 148                         * of objects.
 149                         */
 150                        exit(0);
 151        }
 152        fflush(NULL);
 153        execlp("/bin/sh","sh", "-c", cmd, NULL);
 154}
 155
 156struct diff_filespec *alloc_filespec(const char *path)
 157{
 158        int namelen = strlen(path);
 159        struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
 160        spec->path = (char *)(spec + 1);
 161        strcpy(spec->path, path);
 162        spec->should_free = spec->should_munmap = 0;
 163        spec->xfrm_flags = 0;
 164        spec->size = 0;
 165        spec->data = NULL;
 166        spec->mode = 0;
 167        memset(spec->sha1, 0, 20);
 168        return spec;
 169}
 170
 171void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 172                   unsigned short mode)
 173{
 174        if (mode) {
 175                spec->mode = DIFF_FILE_CANON_MODE(mode);
 176                memcpy(spec->sha1, sha1, 20);
 177                spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
 178        }
 179}
 180
 181/*
 182 * Given a name and sha1 pair, if the dircache tells us the file in
 183 * the work tree has that object contents, return true, so that
 184 * prepare_temp_file() does not have to inflate and extract.
 185 */
 186static int work_tree_matches(const char *name, const unsigned char *sha1)
 187{
 188        struct cache_entry *ce;
 189        struct stat st;
 190        int pos, len;
 191
 192        /* We do not read the cache ourselves here, because the
 193         * benchmark with my previous version that always reads cache
 194         * shows that it makes things worse for diff-tree comparing
 195         * two linux-2.6 kernel trees in an already checked out work
 196         * tree.  This is because most diff-tree comparisons deal with
 197         * only a small number of files, while reading the cache is
 198         * expensive for a large project, and its cost outweighs the
 199         * savings we get by not inflating the object to a temporary
 200         * file.  Practically, this code only helps when we are used
 201         * by diff-cache --cached, which does read the cache before
 202         * calling us.
 203         */
 204        if (!active_cache)
 205                return 0;
 206
 207        len = strlen(name);
 208        pos = cache_name_pos(name, len);
 209        if (pos < 0)
 210                return 0;
 211        ce = active_cache[pos];
 212        if ((lstat(name, &st) < 0) ||
 213            !S_ISREG(st.st_mode) || /* careful! */
 214            ce_match_stat(ce, &st) ||
 215            memcmp(sha1, ce->sha1, 20))
 216                return 0;
 217        /* we return 1 only when we can stat, it is a regular file,
 218         * stat information matches, and sha1 recorded in the cache
 219         * matches.  I.e. we know the file in the work tree really is
 220         * the same as the <name, sha1> pair.
 221         */
 222        return 1;
 223}
 224
 225/*
 226 * While doing rename detection and pickaxe operation, we may need to
 227 * grab the data for the blob (or file) for our own in-core comparison.
 228 * diff_filespec has data and size fields for this purpose.
 229 */
 230int diff_populate_filespec(struct diff_filespec *s)
 231{
 232        int err = 0;
 233        if (!DIFF_FILE_VALID(s))
 234                die("internal error: asking to populate invalid file.");
 235        if (S_ISDIR(s->mode))
 236                return -1;
 237
 238        if (s->data)
 239                return err;
 240        if (!s->sha1_valid ||
 241            work_tree_matches(s->path, s->sha1)) {
 242                struct stat st;
 243                int fd;
 244                if (lstat(s->path, &st) < 0) {
 245                        if (errno == ENOENT) {
 246                        err_empty:
 247                                err = -1;
 248                        empty:
 249                                s->data = "";
 250                                s->size = 0;
 251                                return err;
 252                        }
 253                }
 254                s->size = st.st_size;
 255                if (!s->size)
 256                        goto empty;
 257                if (S_ISLNK(st.st_mode)) {
 258                        int ret;
 259                        s->data = xmalloc(s->size);
 260                        s->should_free = 1;
 261                        ret = readlink(s->path, s->data, s->size);
 262                        if (ret < 0) {
 263                                free(s->data);
 264                                goto err_empty;
 265                        }
 266                        return 0;
 267                }
 268                fd = open(s->path, O_RDONLY);
 269                if (fd < 0)
 270                        goto err_empty;
 271                s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
 272                s->should_munmap = 1;
 273                close(fd);
 274        }
 275        else {
 276                char type[20];
 277                s->data = read_sha1_file(s->sha1, type, &s->size);
 278                s->should_free = 1;
 279        }
 280        return 0;
 281}
 282
 283void diff_free_filespec_data(struct diff_filespec *s)
 284{
 285        if (s->should_free)
 286                free(s->data);
 287        else if (s->should_munmap)
 288                munmap(s->data, s->size);
 289        s->should_free = s->should_munmap = 0;
 290        s->data = NULL;
 291}
 292
 293static void prep_temp_blob(struct diff_tempfile *temp,
 294                           void *blob,
 295                           unsigned long size,
 296                           unsigned char *sha1,
 297                           int mode)
 298{
 299        int fd;
 300
 301        strcpy(temp->tmp_path, ".diff_XXXXXX");
 302        fd = mkstemp(temp->tmp_path);
 303        if (fd < 0)
 304                die("unable to create temp-file");
 305        if (write(fd, blob, size) != size)
 306                die("unable to write temp-file");
 307        close(fd);
 308        temp->name = temp->tmp_path;
 309        strcpy(temp->hex, sha1_to_hex(sha1));
 310        temp->hex[40] = 0;
 311        sprintf(temp->mode, "%06o", mode);
 312}
 313
 314static void prepare_temp_file(const char *name,
 315                              struct diff_tempfile *temp,
 316                              struct diff_filespec *one)
 317{
 318        if (!DIFF_FILE_VALID(one)) {
 319        not_a_valid_file:
 320                /* A '-' entry produces this for file-2, and
 321                 * a '+' entry produces this for file-1.
 322                 */
 323                temp->name = "/dev/null";
 324                strcpy(temp->hex, ".");
 325                strcpy(temp->mode, ".");
 326                return;
 327        }
 328
 329        if (!one->sha1_valid ||
 330            work_tree_matches(name, one->sha1)) {
 331                struct stat st;
 332                if (lstat(name, &st) < 0) {
 333                        if (errno == ENOENT)
 334                                goto not_a_valid_file;
 335                        die("stat(%s): %s", name, strerror(errno));
 336                }
 337                if (S_ISLNK(st.st_mode)) {
 338                        int ret;
 339                        char *buf, buf_[1024];
 340                        buf = ((sizeof(buf_) < st.st_size) ?
 341                               xmalloc(st.st_size) : buf_);
 342                        ret = readlink(name, buf, st.st_size);
 343                        if (ret < 0)
 344                                die("readlink(%s)", name);
 345                        prep_temp_blob(temp, buf, st.st_size,
 346                                       (one->sha1_valid ?
 347                                        one->sha1 : null_sha1),
 348                                       (one->sha1_valid ?
 349                                        one->mode : S_IFLNK));
 350                }
 351                else {
 352                        /* we can borrow from the file in the work tree */
 353                        temp->name = name;
 354                        if (!one->sha1_valid)
 355                                strcpy(temp->hex, sha1_to_hex(null_sha1));
 356                        else
 357                                strcpy(temp->hex, sha1_to_hex(one->sha1));
 358                        sprintf(temp->mode, "%06o",
 359                                S_IFREG |ce_permissions(st.st_mode));
 360                }
 361                return;
 362        }
 363        else {
 364                if (diff_populate_filespec(one))
 365                        die("cannot read data blob for %s", one->path);
 366                prep_temp_blob(temp, one->data, one->size,
 367                               one->sha1, one->mode);
 368        }
 369}
 370
 371static void remove_tempfile(void)
 372{
 373        int i;
 374
 375        for (i = 0; i < 2; i++)
 376                if (diff_temp[i].name == diff_temp[i].tmp_path) {
 377                        unlink(diff_temp[i].name);
 378                        diff_temp[i].name = NULL;
 379                }
 380}
 381
 382static void remove_tempfile_on_signal(int signo)
 383{
 384        remove_tempfile();
 385}
 386
 387/* An external diff command takes:
 388 *
 389 * diff-cmd name infile1 infile1-sha1 infile1-mode \
 390 *               infile2 infile2-sha1 infile2-mode [ rename-to ]
 391 *
 392 */
 393static void run_external_diff(const char *pgm,
 394                              const char *name,
 395                              const char *other,
 396                              struct diff_filespec *one,
 397                              struct diff_filespec *two,
 398                              const char *xfrm_msg)
 399{
 400        struct diff_tempfile *temp = diff_temp;
 401        pid_t pid;
 402        int status;
 403        static int atexit_asked = 0;
 404
 405        if (one && two) {
 406                prepare_temp_file(name, &temp[0], one);
 407                prepare_temp_file(other ? : name, &temp[1], two);
 408                if (! atexit_asked &&
 409                    (temp[0].name == temp[0].tmp_path ||
 410                     temp[1].name == temp[1].tmp_path)) {
 411                        atexit_asked = 1;
 412                        atexit(remove_tempfile);
 413                }
 414                signal(SIGINT, remove_tempfile_on_signal);
 415        }
 416
 417        fflush(NULL);
 418        pid = fork();
 419        if (pid < 0)
 420                die("unable to fork");
 421        if (!pid) {
 422                if (pgm) {
 423                        if (one && two) {
 424                                const char *exec_arg[10];
 425                                const char **arg = &exec_arg[0];
 426                                *arg++ = pgm;
 427                                *arg++ = name;
 428                                *arg++ = temp[0].name;
 429                                *arg++ = temp[0].hex;
 430                                *arg++ = temp[0].mode;
 431                                *arg++ = temp[1].name;
 432                                *arg++ = temp[1].hex;
 433                                *arg++ = temp[1].mode;
 434                                if (other) {
 435                                        *arg++ = other;
 436                                        *arg++ = xfrm_msg;
 437                                }
 438                                *arg = NULL;
 439                                execvp(pgm, (char *const*) exec_arg);
 440                        }
 441                        else
 442                                execlp(pgm, pgm, name, NULL);
 443                }
 444                /*
 445                 * otherwise we use the built-in one.
 446                 */
 447                if (one && two)
 448                        builtin_diff(name, other ? : name, temp, xfrm_msg);
 449                else
 450                        printf("* Unmerged path %s\n", name);
 451                exit(0);
 452        }
 453        if (waitpid(pid, &status, 0) < 0 ||
 454            !WIFEXITED(status) || WEXITSTATUS(status)) {
 455                /* Earlier we did not check the exit status because
 456                 * diff exits non-zero if files are different, and
 457                 * we are not interested in knowing that.  It was a
 458                 * mistake which made it harder to quit a diff-*
 459                 * session that uses the git-apply-patch-script as
 460                 * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
 461                 * should also exit non-zero only when it wants to
 462                 * abort the entire diff-* session.
 463                 */
 464                remove_tempfile();
 465                fprintf(stderr, "external diff died, stopping at %s.\n", name);
 466                exit(1);
 467        }
 468        remove_tempfile();
 469}
 470
 471static void run_diff(const char *name,
 472                     const char *other,
 473                     struct diff_filespec *one,
 474                     struct diff_filespec *two,
 475                     const char *xfrm_msg)
 476{
 477        const char *pgm = external_diff();
 478        if (!pgm &&
 479            DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
 480            (S_IFMT & one->mode) != (S_IFMT & two->mode)) {
 481                /* a filepair that changes between file and symlink
 482                 * needs to be split into deletion and creation.
 483                 */
 484                struct diff_filespec *null = alloc_filespec(two->path);
 485                run_external_diff(NULL, name, other, one, null, xfrm_msg);
 486                free(null);
 487                null = alloc_filespec(one->path);
 488                run_external_diff(NULL, name, other, null, two, xfrm_msg);
 489                free(null);
 490        }
 491        else
 492                run_external_diff(pgm, name, other, one, two, xfrm_msg);
 493}
 494
 495void diff_setup(int flags)
 496{
 497        if (flags & DIFF_SETUP_REVERSE)
 498                reverse_diff = 1;
 499}
 500
 501struct diff_queue_struct diff_queued_diff;
 502
 503void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
 504{
 505        if (queue->alloc <= queue->nr) {
 506                queue->alloc = alloc_nr(queue->alloc);
 507                queue->queue = xrealloc(queue->queue,
 508                                        sizeof(dp) * queue->alloc);
 509        }
 510        queue->queue[queue->nr++] = dp;
 511}
 512
 513struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
 514                                 struct diff_filespec *one,
 515                                 struct diff_filespec *two)
 516{
 517        struct diff_filepair *dp = xmalloc(sizeof(*dp));
 518        dp->one = one;
 519        dp->two = two;
 520        dp->score = 0;
 521        diff_q(queue, dp);
 522        return dp;
 523}
 524
 525void diff_free_filepair(struct diff_filepair *p)
 526{
 527        diff_free_filespec_data(p->one);
 528        diff_free_filespec_data(p->two);
 529        free(p);
 530}
 531
 532static void diff_flush_raw(struct diff_filepair *p,
 533                           int line_termination,
 534                           int inter_name_termination)
 535{
 536        int two_paths;
 537        char status[10];
 538
 539        if (line_termination) {
 540                const char *err = "path %s cannot be expressed without -z";
 541                if (strchr(p->one->path, line_termination) ||
 542                    strchr(p->one->path, inter_name_termination))
 543                        die(err, p->one->path);
 544                if (strchr(p->two->path, line_termination) ||
 545                    strchr(p->two->path, inter_name_termination))
 546                        die(err, p->two->path);
 547        }
 548
 549        switch (p->status) {
 550        case 'C': case 'R':
 551                two_paths = 1;
 552                sprintf(status, "%c%03d", p->status,
 553                        (int)(0.5 + p->score * 100.0/MAX_SCORE));
 554                break;
 555        default:
 556                two_paths = 0;
 557                status[0] = p->status;
 558                status[1] = 0;
 559                break;
 560        }
 561        printf(":%06o %06o %s ",
 562               p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
 563        printf("%s %s%c%s",
 564               sha1_to_hex(p->two->sha1),
 565               status,
 566               inter_name_termination,
 567               p->one->path);
 568        if (two_paths)
 569                printf("%c%s", inter_name_termination, p->two->path);
 570        putchar(line_termination);
 571}
 572
 573int diff_unmodified_pair(struct diff_filepair *p)
 574{
 575        /* This function is written stricter than necessary to support
 576         * the currently implemented transformers, but the idea is to
 577         * let transformers to produce diff_filepairs any way they want,
 578         * and filter and clean them up here before producing the output.
 579         */
 580        struct diff_filespec *one, *two;
 581
 582        if (DIFF_PAIR_UNMERGED(p))
 583                return 0; /* unmerged is interesting */
 584
 585        one = p->one;
 586        two = p->two;
 587
 588        /* deletion, addition, mode or type change
 589         * and rename are all interesting.
 590         */
 591        if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
 592            DIFF_PAIR_MODE_CHANGED(p) ||
 593            strcmp(one->path, two->path))
 594                return 0;
 595
 596        /* both are valid and point at the same path.  that is, we are
 597         * dealing with a change.
 598         */
 599        if (one->sha1_valid && two->sha1_valid &&
 600            !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
 601                return 1; /* no change */
 602        if (!one->sha1_valid && !two->sha1_valid)
 603                return 1; /* both look at the same file on the filesystem. */
 604        return 0;
 605}
 606
 607static void diff_flush_patch(struct diff_filepair *p)
 608{
 609        const char *name, *other;
 610        char msg_[PATH_MAX*2+200], *msg;
 611
 612        if (diff_unmodified_pair(p))
 613                return;
 614
 615        name = p->one->path;
 616        other = (strcmp(name, p->two->path) ? p->two->path : NULL);
 617        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
 618            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
 619                return; /* no tree diffs in patch format */ 
 620
 621        switch (p->status) {
 622        case 'C':
 623                sprintf(msg_,
 624                        "similarity index %d%%\n"
 625                        "copy from %s\n"
 626                        "copy to %s",
 627                        (int)(0.5 + p->score * 100.0/MAX_SCORE),
 628                        p->one->path, p->two->path);
 629                msg = msg_;
 630                break;
 631        case 'R':
 632                sprintf(msg_,
 633                        "similarity index %d%%\n"
 634                        "rename old %s\n"
 635                        "rename new %s",
 636                        (int)(0.5 + p->score * 100.0/MAX_SCORE),
 637                        p->one->path, p->two->path);
 638                msg = msg_;
 639                break;
 640        default:
 641                msg = NULL;
 642        }
 643
 644        if (DIFF_PAIR_UNMERGED(p))
 645                run_diff(name, NULL, NULL, NULL, NULL);
 646        else
 647                run_diff(name, other, p->one, p->two, msg);
 648}
 649
 650int diff_queue_is_empty(void)
 651{
 652        struct diff_queue_struct *q = &diff_queued_diff;
 653        int i;
 654        for (i = 0; i < q->nr; i++)
 655                if (!diff_unmodified_pair(q->queue[i]))
 656                        return 0;
 657        return 1;
 658}
 659
 660#if DIFF_DEBUG
 661void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
 662{
 663        fprintf(stderr, "queue[%d] %s (%s) %s %06o %s\n",
 664                x, one ? : "",
 665                s->path,
 666                DIFF_FILE_VALID(s) ? "valid" : "invalid",
 667                s->mode,
 668                s->sha1_valid ? sha1_to_hex(s->sha1) : "");
 669        fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
 670                x, one ? : "",
 671                s->size, s->xfrm_flags);
 672}
 673
 674void diff_debug_filepair(const struct diff_filepair *p, int i)
 675{
 676        diff_debug_filespec(p->one, i, "one");
 677        diff_debug_filespec(p->two, i, "two");
 678        fprintf(stderr, "score %d, status %c\n",
 679                p->score, p->status ? : '?');
 680}
 681
 682void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
 683{
 684        int i;
 685        if (msg)
 686                fprintf(stderr, "%s\n", msg);
 687        fprintf(stderr, "q->nr = %d\n", q->nr);
 688        for (i = 0; i < q->nr; i++) {
 689                struct diff_filepair *p = q->queue[i];
 690                diff_debug_filepair(p, i);
 691        }
 692}
 693#endif
 694
 695static void diff_resolve_rename_copy(void)
 696{
 697        int i, j;
 698        struct diff_filepair *p, *pp;
 699        struct diff_queue_struct *q = &diff_queued_diff;
 700
 701        /* This should not depend on the ordering of things. */
 702
 703        diff_debug_queue("resolve-rename-copy", q);
 704
 705        for (i = 0; i < q->nr; i++) {
 706                p = q->queue[i];
 707                p->status = 0; /* undecided */
 708                if (DIFF_PAIR_UNMERGED(p))
 709                        p->status = 'U';
 710                else if (!DIFF_FILE_VALID((p)->one))
 711                        p->status = 'N';
 712                else if (!DIFF_FILE_VALID((p)->two)) {
 713                        /* Deletion record should be omitted if there
 714                         * are rename/copy entries using this one as
 715                         * the source.  Then we can say one of them
 716                         * is a rename and the rest are copies.
 717                         */
 718                        p->status = 'D';
 719                        for (j = 0; j < q->nr; j++) {
 720                                pp = q->queue[j];
 721                                if (!strcmp(pp->one->path, p->one->path) &&
 722                                    strcmp(pp->one->path, pp->two->path)) {
 723                                        p->status = 'X';
 724                                        break;
 725                                }
 726                        }
 727                }
 728                else if (DIFF_PAIR_TYPE_CHANGED(p))
 729                        p->status = 'T';
 730
 731                /* from this point on, we are dealing with a pair
 732                 * whose both sides are valid and of the same type, i.e.
 733                 * either in-place edit or rename/copy edit.
 734                 */
 735                else if (strcmp(p->one->path, p->two->path)) {
 736                        /* See if there is somebody else anywhere that
 737                         * will keep the path (either modified or
 738                         * unmodified).  If so, we have to be a copy,
 739                         * not a rename.  In addition, if there is
 740                         * some other rename or copy that comes later
 741                         * than us that uses the same source, we
 742                         * have to be a copy, not a rename.
 743                         */
 744                        for (j = 0; j < q->nr; j++) {
 745                                pp = q->queue[j];
 746                                if (strcmp(pp->one->path, p->one->path))
 747                                        continue;
 748                                if (!strcmp(pp->one->path, pp->two->path)) {
 749                                        if (DIFF_FILE_VALID(pp->two)) {
 750                                                /* non-delete */
 751                                                p->status = 'C';
 752                                                break;
 753                                        }
 754                                        continue;
 755                                }
 756                                /* pp is a rename/copy ... */
 757                                if (i < j) {
 758                                        /* ... and comes later than us */
 759                                        p->status = 'C';
 760                                        break;
 761                                }
 762                        }
 763                        if (!p->status)
 764                                p->status = 'R';
 765                }
 766                else if (memcmp(p->one->sha1, p->two->sha1, 20) ||
 767                         p->one->mode != p->two->mode)
 768                        p->status = 'M';
 769                else
 770                        /* this is a "no-change" entry */
 771                        p->status = 'X';
 772        }
 773        diff_debug_queue("resolve-rename-copy done", q);
 774}
 775
 776void diff_flush(int diff_output_style, int resolve_rename_copy)
 777{
 778        struct diff_queue_struct *q = &diff_queued_diff;
 779        int i;
 780        int line_termination = '\n';
 781        int inter_name_termination = '\t';
 782
 783        if (diff_output_style == DIFF_FORMAT_MACHINE)
 784                line_termination = inter_name_termination = 0;
 785        if (resolve_rename_copy)
 786                diff_resolve_rename_copy();
 787
 788        for (i = 0; i < q->nr; i++) {
 789                struct diff_filepair *p = q->queue[i];
 790                if ((diff_output_style == DIFF_FORMAT_NO_OUTPUT) ||
 791                    (p->status == 'X'))
 792                        continue;
 793                if (p->status == 0)
 794                        die("internal error in diff-resolve-rename-copy");
 795                switch (diff_output_style) {
 796                case DIFF_FORMAT_PATCH:
 797                        diff_flush_patch(p);
 798                        break;
 799                case DIFF_FORMAT_HUMAN:
 800                case DIFF_FORMAT_MACHINE:
 801                        diff_flush_raw(p, line_termination,
 802                                       inter_name_termination);
 803                        break;
 804                }
 805        }
 806        for (i = 0; i < q->nr; i++)
 807                diff_free_filepair(q->queue[i]);
 808        free(q->queue);
 809        q->queue = NULL;
 810        q->nr = q->alloc = 0;
 811}
 812
 813void diff_addremove(int addremove, unsigned mode,
 814                    const unsigned char *sha1,
 815                    const char *base, const char *path)
 816{
 817        char concatpath[PATH_MAX];
 818        struct diff_filespec *one, *two;
 819
 820        /* This may look odd, but it is a preparation for
 821         * feeding "there are unchanged files which should
 822         * not produce diffs, but when you are doing copy
 823         * detection you would need them, so here they are"
 824         * entries to the diff-core.  They will be prefixed
 825         * with something like '=' or '*' (I haven't decided
 826         * which but should not make any difference).
 827         * Feeding the same new and old to diff_change() 
 828         * also has the same effect.
 829         * Before the final output happens, they are pruned after
 830         * merged into rename/copy pairs as appropriate.
 831         */
 832        if (reverse_diff)
 833                addremove = (addremove == '+' ? '-' :
 834                             addremove == '-' ? '+' : addremove);
 835
 836        if (!path) path = "";
 837        sprintf(concatpath, "%s%s", base, path);
 838        one = alloc_filespec(concatpath);
 839        two = alloc_filespec(concatpath);
 840
 841        if (addremove != '+')
 842                fill_filespec(one, sha1, mode);
 843        if (addremove != '-')
 844                fill_filespec(two, sha1, mode);
 845
 846        diff_queue(&diff_queued_diff, one, two);
 847}
 848
 849void diff_helper_input(unsigned old_mode,
 850                       unsigned new_mode,
 851                       const unsigned char *old_sha1,
 852                       const unsigned char *new_sha1,
 853                       const char *old_path,
 854                       int status,
 855                       int score,
 856                       const char *new_path)
 857{
 858        struct diff_filespec *one, *two;
 859        struct diff_filepair *dp;
 860
 861        one = alloc_filespec(old_path);
 862        two = alloc_filespec(new_path);
 863        if (old_mode)
 864                fill_filespec(one, old_sha1, old_mode);
 865        if (new_mode)
 866                fill_filespec(two, new_sha1, new_mode);
 867        dp = diff_queue(&diff_queued_diff, one, two);
 868        dp->score = score * MAX_SCORE / 100;
 869        dp->status = status;
 870}
 871
 872void diff_change(unsigned old_mode, unsigned new_mode,
 873                 const unsigned char *old_sha1,
 874                 const unsigned char *new_sha1,
 875                 const char *base, const char *path) 
 876{
 877        char concatpath[PATH_MAX];
 878        struct diff_filespec *one, *two;
 879
 880        if (reverse_diff) {
 881                unsigned tmp;
 882                const unsigned char *tmp_c;
 883                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
 884                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
 885        }
 886        if (!path) path = "";
 887        sprintf(concatpath, "%s%s", base, path);
 888        one = alloc_filespec(concatpath);
 889        two = alloc_filespec(concatpath);
 890        fill_filespec(one, old_sha1, old_mode);
 891        fill_filespec(two, new_sha1, new_mode);
 892
 893        diff_queue(&diff_queued_diff, one, two);
 894}
 895
 896void diff_unmerge(const char *path)
 897{
 898        struct diff_filespec *one, *two;
 899        one = alloc_filespec(path);
 900        two = alloc_filespec(path);
 901        diff_queue(&diff_queued_diff, one, two);
 902}