diff.con commit diff.c: do not use a separate "size cache". (6e0b8ed)
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "quote.h"
   6#include "diff.h"
   7#include "diffcore.h"
   8#include "delta.h"
   9#include "xdiff-interface.h"
  10#include "color.h"
  11#include "attr.h"
  12
  13#ifdef NO_FAST_WORKING_DIRECTORY
  14#define FAST_WORKING_DIRECTORY 0
  15#else
  16#define FAST_WORKING_DIRECTORY 1
  17#endif
  18
  19static int diff_detect_rename_default;
  20static int diff_rename_limit_default = -1;
  21static int diff_use_color_default;
  22
  23static char diff_colors[][COLOR_MAXLEN] = {
  24        "\033[m",       /* reset */
  25        "",             /* PLAIN (normal) */
  26        "\033[1m",      /* METAINFO (bold) */
  27        "\033[36m",     /* FRAGINFO (cyan) */
  28        "\033[31m",     /* OLD (red) */
  29        "\033[32m",     /* NEW (green) */
  30        "\033[33m",     /* COMMIT (yellow) */
  31        "\033[41m",     /* WHITESPACE (red background) */
  32};
  33
  34static int parse_diff_color_slot(const char *var, int ofs)
  35{
  36        if (!strcasecmp(var+ofs, "plain"))
  37                return DIFF_PLAIN;
  38        if (!strcasecmp(var+ofs, "meta"))
  39                return DIFF_METAINFO;
  40        if (!strcasecmp(var+ofs, "frag"))
  41                return DIFF_FRAGINFO;
  42        if (!strcasecmp(var+ofs, "old"))
  43                return DIFF_FILE_OLD;
  44        if (!strcasecmp(var+ofs, "new"))
  45                return DIFF_FILE_NEW;
  46        if (!strcasecmp(var+ofs, "commit"))
  47                return DIFF_COMMIT;
  48        if (!strcasecmp(var+ofs, "whitespace"))
  49                return DIFF_WHITESPACE;
  50        die("bad config variable '%s'", var);
  51}
  52
  53static struct ll_diff_driver {
  54        const char *name;
  55        struct ll_diff_driver *next;
  56        char *cmd;
  57} *user_diff, **user_diff_tail;
  58
  59/*
  60 * Currently there is only "diff.<drivername>.command" variable;
  61 * because there are "diff.color.<slot>" variables, we are parsing
  62 * this in a bit convoluted way to allow low level diff driver
  63 * called "color".
  64 */
  65static int parse_lldiff_command(const char *var, const char *ep, const char *value)
  66{
  67        const char *name;
  68        int namelen;
  69        struct ll_diff_driver *drv;
  70
  71        name = var + 5;
  72        namelen = ep - name;
  73        for (drv = user_diff; drv; drv = drv->next)
  74                if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
  75                        break;
  76        if (!drv) {
  77                char *namebuf;
  78                drv = xcalloc(1, sizeof(struct ll_diff_driver));
  79                namebuf = xmalloc(namelen + 1);
  80                memcpy(namebuf, name, namelen);
  81                namebuf[namelen] = 0;
  82                drv->name = namebuf;
  83                drv->next = NULL;
  84                if (!user_diff_tail)
  85                        user_diff_tail = &user_diff;
  86                *user_diff_tail = drv;
  87                user_diff_tail = &(drv->next);
  88        }
  89
  90        if (!value)
  91                return error("%s: lacks value", var);
  92        drv->cmd = strdup(value);
  93        return 0;
  94}
  95
  96/*
  97 * These are to give UI layer defaults.
  98 * The core-level commands such as git-diff-files should
  99 * never be affected by the setting of diff.renames
 100 * the user happens to have in the configuration file.
 101 */
 102int git_diff_ui_config(const char *var, const char *value)
 103{
 104        if (!strcmp(var, "diff.renamelimit")) {
 105                diff_rename_limit_default = git_config_int(var, value);
 106                return 0;
 107        }
 108        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
 109                diff_use_color_default = git_config_colorbool(var, value);
 110                return 0;
 111        }
 112        if (!strcmp(var, "diff.renames")) {
 113                if (!value)
 114                        diff_detect_rename_default = DIFF_DETECT_RENAME;
 115                else if (!strcasecmp(value, "copies") ||
 116                         !strcasecmp(value, "copy"))
 117                        diff_detect_rename_default = DIFF_DETECT_COPY;
 118                else if (git_config_bool(var,value))
 119                        diff_detect_rename_default = DIFF_DETECT_RENAME;
 120                return 0;
 121        }
 122        if (!prefixcmp(var, "diff.")) {
 123                const char *ep = strrchr(var, '.');
 124
 125                if (ep != var + 4 && !strcmp(ep, ".command"))
 126                        return parse_lldiff_command(var, ep, value);
 127        }
 128        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
 129                int slot = parse_diff_color_slot(var, 11);
 130                color_parse(value, var, diff_colors[slot]);
 131                return 0;
 132        }
 133
 134        return git_default_config(var, value);
 135}
 136
 137static char *quote_one(const char *str)
 138{
 139        int needlen;
 140        char *xp;
 141
 142        if (!str)
 143                return NULL;
 144        needlen = quote_c_style(str, NULL, NULL, 0);
 145        if (!needlen)
 146                return xstrdup(str);
 147        xp = xmalloc(needlen + 1);
 148        quote_c_style(str, xp, NULL, 0);
 149        return xp;
 150}
 151
 152static char *quote_two(const char *one, const char *two)
 153{
 154        int need_one = quote_c_style(one, NULL, NULL, 1);
 155        int need_two = quote_c_style(two, NULL, NULL, 1);
 156        char *xp;
 157
 158        if (need_one + need_two) {
 159                if (!need_one) need_one = strlen(one);
 160                if (!need_two) need_one = strlen(two);
 161
 162                xp = xmalloc(need_one + need_two + 3);
 163                xp[0] = '"';
 164                quote_c_style(one, xp + 1, NULL, 1);
 165                quote_c_style(two, xp + need_one + 1, NULL, 1);
 166                strcpy(xp + need_one + need_two + 1, "\"");
 167                return xp;
 168        }
 169        need_one = strlen(one);
 170        need_two = strlen(two);
 171        xp = xmalloc(need_one + need_two + 1);
 172        strcpy(xp, one);
 173        strcpy(xp + need_one, two);
 174        return xp;
 175}
 176
 177static const char *external_diff(void)
 178{
 179        static const char *external_diff_cmd = NULL;
 180        static int done_preparing = 0;
 181
 182        if (done_preparing)
 183                return external_diff_cmd;
 184        external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
 185        done_preparing = 1;
 186        return external_diff_cmd;
 187}
 188
 189#define TEMPFILE_PATH_LEN               50
 190
 191static struct diff_tempfile {
 192        const char *name; /* filename external diff should read from */
 193        char hex[41];
 194        char mode[10];
 195        char tmp_path[TEMPFILE_PATH_LEN];
 196} diff_temp[2];
 197
 198static int count_lines(const char *data, int size)
 199{
 200        int count, ch, completely_empty = 1, nl_just_seen = 0;
 201        count = 0;
 202        while (0 < size--) {
 203                ch = *data++;
 204                if (ch == '\n') {
 205                        count++;
 206                        nl_just_seen = 1;
 207                        completely_empty = 0;
 208                }
 209                else {
 210                        nl_just_seen = 0;
 211                        completely_empty = 0;
 212                }
 213        }
 214        if (completely_empty)
 215                return 0;
 216        if (!nl_just_seen)
 217                count++; /* no trailing newline */
 218        return count;
 219}
 220
 221static void print_line_count(int count)
 222{
 223        switch (count) {
 224        case 0:
 225                printf("0,0");
 226                break;
 227        case 1:
 228                printf("1");
 229                break;
 230        default:
 231                printf("1,%d", count);
 232                break;
 233        }
 234}
 235
 236static void copy_file(int prefix, const char *data, int size,
 237                const char *set, const char *reset)
 238{
 239        int ch, nl_just_seen = 1;
 240        while (0 < size--) {
 241                ch = *data++;
 242                if (nl_just_seen) {
 243                        fputs(set, stdout);
 244                        putchar(prefix);
 245                }
 246                if (ch == '\n') {
 247                        nl_just_seen = 1;
 248                        fputs(reset, stdout);
 249                } else
 250                        nl_just_seen = 0;
 251                putchar(ch);
 252        }
 253        if (!nl_just_seen)
 254                printf("%s\n\\ No newline at end of file\n", reset);
 255}
 256
 257static void emit_rewrite_diff(const char *name_a,
 258                              const char *name_b,
 259                              struct diff_filespec *one,
 260                              struct diff_filespec *two,
 261                              int color_diff)
 262{
 263        int lc_a, lc_b;
 264        const char *name_a_tab, *name_b_tab;
 265        const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
 266        const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
 267        const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
 268        const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
 269        const char *reset = diff_get_color(color_diff, DIFF_RESET);
 270
 271        name_a += (*name_a == '/');
 272        name_b += (*name_b == '/');
 273        name_a_tab = strchr(name_a, ' ') ? "\t" : "";
 274        name_b_tab = strchr(name_b, ' ') ? "\t" : "";
 275
 276        diff_populate_filespec(one, 0);
 277        diff_populate_filespec(two, 0);
 278        lc_a = count_lines(one->data, one->size);
 279        lc_b = count_lines(two->data, two->size);
 280        printf("%s--- a/%s%s%s\n%s+++ b/%s%s%s\n%s@@ -",
 281               metainfo, name_a, name_a_tab, reset,
 282               metainfo, name_b, name_b_tab, reset, fraginfo);
 283        print_line_count(lc_a);
 284        printf(" +");
 285        print_line_count(lc_b);
 286        printf(" @@%s\n", reset);
 287        if (lc_a)
 288                copy_file('-', one->data, one->size, old, reset);
 289        if (lc_b)
 290                copy_file('+', two->data, two->size, new, reset);
 291}
 292
 293static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
 294{
 295        if (!DIFF_FILE_VALID(one)) {
 296                mf->ptr = (char *)""; /* does not matter */
 297                mf->size = 0;
 298                return 0;
 299        }
 300        else if (diff_populate_filespec(one, 0))
 301                return -1;
 302        mf->ptr = one->data;
 303        mf->size = one->size;
 304        return 0;
 305}
 306
 307struct diff_words_buffer {
 308        mmfile_t text;
 309        long alloc;
 310        long current; /* output pointer */
 311        int suppressed_newline;
 312};
 313
 314static void diff_words_append(char *line, unsigned long len,
 315                struct diff_words_buffer *buffer)
 316{
 317        if (buffer->text.size + len > buffer->alloc) {
 318                buffer->alloc = (buffer->text.size + len) * 3 / 2;
 319                buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc);
 320        }
 321        line++;
 322        len--;
 323        memcpy(buffer->text.ptr + buffer->text.size, line, len);
 324        buffer->text.size += len;
 325}
 326
 327struct diff_words_data {
 328        struct xdiff_emit_state xm;
 329        struct diff_words_buffer minus, plus;
 330};
 331
 332static void print_word(struct diff_words_buffer *buffer, int len, int color,
 333                int suppress_newline)
 334{
 335        const char *ptr;
 336        int eol = 0;
 337
 338        if (len == 0)
 339                return;
 340
 341        ptr  = buffer->text.ptr + buffer->current;
 342        buffer->current += len;
 343
 344        if (ptr[len - 1] == '\n') {
 345                eol = 1;
 346                len--;
 347        }
 348
 349        fputs(diff_get_color(1, color), stdout);
 350        fwrite(ptr, len, 1, stdout);
 351        fputs(diff_get_color(1, DIFF_RESET), stdout);
 352
 353        if (eol) {
 354                if (suppress_newline)
 355                        buffer->suppressed_newline = 1;
 356                else
 357                        putchar('\n');
 358        }
 359}
 360
 361static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
 362{
 363        struct diff_words_data *diff_words = priv;
 364
 365        if (diff_words->minus.suppressed_newline) {
 366                if (line[0] != '+')
 367                        putchar('\n');
 368                diff_words->minus.suppressed_newline = 0;
 369        }
 370
 371        len--;
 372        switch (line[0]) {
 373                case '-':
 374                        print_word(&diff_words->minus, len, DIFF_FILE_OLD, 1);
 375                        break;
 376                case '+':
 377                        print_word(&diff_words->plus, len, DIFF_FILE_NEW, 0);
 378                        break;
 379                case ' ':
 380                        print_word(&diff_words->plus, len, DIFF_PLAIN, 0);
 381                        diff_words->minus.current += len;
 382                        break;
 383        }
 384}
 385
 386/* this executes the word diff on the accumulated buffers */
 387static void diff_words_show(struct diff_words_data *diff_words)
 388{
 389        xpparam_t xpp;
 390        xdemitconf_t xecfg;
 391        xdemitcb_t ecb;
 392        mmfile_t minus, plus;
 393        int i;
 394
 395        minus.size = diff_words->minus.text.size;
 396        minus.ptr = xmalloc(minus.size);
 397        memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
 398        for (i = 0; i < minus.size; i++)
 399                if (isspace(minus.ptr[i]))
 400                        minus.ptr[i] = '\n';
 401        diff_words->minus.current = 0;
 402
 403        plus.size = diff_words->plus.text.size;
 404        plus.ptr = xmalloc(plus.size);
 405        memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
 406        for (i = 0; i < plus.size; i++)
 407                if (isspace(plus.ptr[i]))
 408                        plus.ptr[i] = '\n';
 409        diff_words->plus.current = 0;
 410
 411        xpp.flags = XDF_NEED_MINIMAL;
 412        xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
 413        xecfg.flags = 0;
 414        ecb.outf = xdiff_outf;
 415        ecb.priv = diff_words;
 416        diff_words->xm.consume = fn_out_diff_words_aux;
 417        xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 418
 419        free(minus.ptr);
 420        free(plus.ptr);
 421        diff_words->minus.text.size = diff_words->plus.text.size = 0;
 422
 423        if (diff_words->minus.suppressed_newline) {
 424                putchar('\n');
 425                diff_words->minus.suppressed_newline = 0;
 426        }
 427}
 428
 429struct emit_callback {
 430        struct xdiff_emit_state xm;
 431        int nparents, color_diff;
 432        const char **label_path;
 433        struct diff_words_data *diff_words;
 434        int *found_changesp;
 435};
 436
 437static void free_diff_words_data(struct emit_callback *ecbdata)
 438{
 439        if (ecbdata->diff_words) {
 440                /* flush buffers */
 441                if (ecbdata->diff_words->minus.text.size ||
 442                                ecbdata->diff_words->plus.text.size)
 443                        diff_words_show(ecbdata->diff_words);
 444
 445                if (ecbdata->diff_words->minus.text.ptr)
 446                        free (ecbdata->diff_words->minus.text.ptr);
 447                if (ecbdata->diff_words->plus.text.ptr)
 448                        free (ecbdata->diff_words->plus.text.ptr);
 449                free(ecbdata->diff_words);
 450                ecbdata->diff_words = NULL;
 451        }
 452}
 453
 454const char *diff_get_color(int diff_use_color, enum color_diff ix)
 455{
 456        if (diff_use_color)
 457                return diff_colors[ix];
 458        return "";
 459}
 460
 461static void emit_line(const char *set, const char *reset, const char *line, int len)
 462{
 463        if (len > 0 && line[len-1] == '\n')
 464                len--;
 465        fputs(set, stdout);
 466        fwrite(line, len, 1, stdout);
 467        puts(reset);
 468}
 469
 470static void emit_line_with_ws(int nparents,
 471                const char *set, const char *reset, const char *ws,
 472                const char *line, int len)
 473{
 474        int col0 = nparents;
 475        int last_tab_in_indent = -1;
 476        int last_space_in_indent = -1;
 477        int i;
 478        int tail = len;
 479        int need_highlight_leading_space = 0;
 480        /* The line is a newly added line.  Does it have funny leading
 481         * whitespaces?  In indent, SP should never precede a TAB.
 482         */
 483        for (i = col0; i < len; i++) {
 484                if (line[i] == '\t') {
 485                        last_tab_in_indent = i;
 486                        if (0 <= last_space_in_indent)
 487                                need_highlight_leading_space = 1;
 488                }
 489                else if (line[i] == ' ')
 490                        last_space_in_indent = i;
 491                else
 492                        break;
 493        }
 494        fputs(set, stdout);
 495        fwrite(line, col0, 1, stdout);
 496        fputs(reset, stdout);
 497        if (((i == len) || line[i] == '\n') && i != col0) {
 498                /* The whole line was indent */
 499                emit_line(ws, reset, line + col0, len - col0);
 500                return;
 501        }
 502        i = col0;
 503        if (need_highlight_leading_space) {
 504                while (i < last_tab_in_indent) {
 505                        if (line[i] == ' ') {
 506                                fputs(ws, stdout);
 507                                putchar(' ');
 508                                fputs(reset, stdout);
 509                        }
 510                        else
 511                                putchar(line[i]);
 512                        i++;
 513                }
 514        }
 515        tail = len - 1;
 516        if (line[tail] == '\n' && i < tail)
 517                tail--;
 518        while (i < tail) {
 519                if (!isspace(line[tail]))
 520                        break;
 521                tail--;
 522        }
 523        if ((i < tail && line[tail + 1] != '\n')) {
 524                /* This has whitespace between tail+1..len */
 525                fputs(set, stdout);
 526                fwrite(line + i, tail - i + 1, 1, stdout);
 527                fputs(reset, stdout);
 528                emit_line(ws, reset, line + tail + 1, len - tail - 1);
 529        }
 530        else
 531                emit_line(set, reset, line + i, len - i);
 532}
 533
 534static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
 535{
 536        const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
 537        const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
 538
 539        if (!*ws)
 540                emit_line(set, reset, line, len);
 541        else
 542                emit_line_with_ws(ecbdata->nparents, set, reset, ws,
 543                                line, len);
 544}
 545
 546static void fn_out_consume(void *priv, char *line, unsigned long len)
 547{
 548        int i;
 549        int color;
 550        struct emit_callback *ecbdata = priv;
 551        const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
 552        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
 553
 554        *(ecbdata->found_changesp) = 1;
 555
 556        if (ecbdata->label_path[0]) {
 557                const char *name_a_tab, *name_b_tab;
 558
 559                name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : "";
 560                name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : "";
 561
 562                printf("%s--- %s%s%s\n",
 563                       set, ecbdata->label_path[0], reset, name_a_tab);
 564                printf("%s+++ %s%s%s\n",
 565                       set, ecbdata->label_path[1], reset, name_b_tab);
 566                ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
 567        }
 568
 569        /* This is not really necessary for now because
 570         * this codepath only deals with two-way diffs.
 571         */
 572        for (i = 0; i < len && line[i] == '@'; i++)
 573                ;
 574        if (2 <= i && i < len && line[i] == ' ') {
 575                ecbdata->nparents = i - 1;
 576                emit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
 577                          reset, line, len);
 578                return;
 579        }
 580
 581        if (len < ecbdata->nparents) {
 582                set = reset;
 583                emit_line(reset, reset, line, len);
 584                return;
 585        }
 586
 587        color = DIFF_PLAIN;
 588        if (ecbdata->diff_words && ecbdata->nparents != 1)
 589                /* fall back to normal diff */
 590                free_diff_words_data(ecbdata);
 591        if (ecbdata->diff_words) {
 592                if (line[0] == '-') {
 593                        diff_words_append(line, len,
 594                                          &ecbdata->diff_words->minus);
 595                        return;
 596                } else if (line[0] == '+') {
 597                        diff_words_append(line, len,
 598                                          &ecbdata->diff_words->plus);
 599                        return;
 600                }
 601                if (ecbdata->diff_words->minus.text.size ||
 602                    ecbdata->diff_words->plus.text.size)
 603                        diff_words_show(ecbdata->diff_words);
 604                line++;
 605                len--;
 606                emit_line(set, reset, line, len);
 607                return;
 608        }
 609        for (i = 0; i < ecbdata->nparents && len; i++) {
 610                if (line[i] == '-')
 611                        color = DIFF_FILE_OLD;
 612                else if (line[i] == '+')
 613                        color = DIFF_FILE_NEW;
 614        }
 615
 616        if (color != DIFF_FILE_NEW) {
 617                emit_line(diff_get_color(ecbdata->color_diff, color),
 618                          reset, line, len);
 619                return;
 620        }
 621        emit_add_line(reset, ecbdata, line, len);
 622}
 623
 624static char *pprint_rename(const char *a, const char *b)
 625{
 626        const char *old = a;
 627        const char *new = b;
 628        char *name = NULL;
 629        int pfx_length, sfx_length;
 630        int len_a = strlen(a);
 631        int len_b = strlen(b);
 632        int qlen_a = quote_c_style(a, NULL, NULL, 0);
 633        int qlen_b = quote_c_style(b, NULL, NULL, 0);
 634
 635        if (qlen_a || qlen_b) {
 636                if (qlen_a) len_a = qlen_a;
 637                if (qlen_b) len_b = qlen_b;
 638                name = xmalloc( len_a + len_b + 5 );
 639                if (qlen_a)
 640                        quote_c_style(a, name, NULL, 0);
 641                else
 642                        memcpy(name, a, len_a);
 643                memcpy(name + len_a, " => ", 4);
 644                if (qlen_b)
 645                        quote_c_style(b, name + len_a + 4, NULL, 0);
 646                else
 647                        memcpy(name + len_a + 4, b, len_b + 1);
 648                return name;
 649        }
 650
 651        /* Find common prefix */
 652        pfx_length = 0;
 653        while (*old && *new && *old == *new) {
 654                if (*old == '/')
 655                        pfx_length = old - a + 1;
 656                old++;
 657                new++;
 658        }
 659
 660        /* Find common suffix */
 661        old = a + len_a;
 662        new = b + len_b;
 663        sfx_length = 0;
 664        while (a <= old && b <= new && *old == *new) {
 665                if (*old == '/')
 666                        sfx_length = len_a - (old - a);
 667                old--;
 668                new--;
 669        }
 670
 671        /*
 672         * pfx{mid-a => mid-b}sfx
 673         * {pfx-a => pfx-b}sfx
 674         * pfx{sfx-a => sfx-b}
 675         * name-a => name-b
 676         */
 677        if (pfx_length + sfx_length) {
 678                int a_midlen = len_a - pfx_length - sfx_length;
 679                int b_midlen = len_b - pfx_length - sfx_length;
 680                if (a_midlen < 0) a_midlen = 0;
 681                if (b_midlen < 0) b_midlen = 0;
 682
 683                name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7);
 684                sprintf(name, "%.*s{%.*s => %.*s}%s",
 685                        pfx_length, a,
 686                        a_midlen, a + pfx_length,
 687                        b_midlen, b + pfx_length,
 688                        a + len_a - sfx_length);
 689        }
 690        else {
 691                name = xmalloc(len_a + len_b + 5);
 692                sprintf(name, "%s => %s", a, b);
 693        }
 694        return name;
 695}
 696
 697struct diffstat_t {
 698        struct xdiff_emit_state xm;
 699
 700        int nr;
 701        int alloc;
 702        struct diffstat_file {
 703                char *name;
 704                unsigned is_unmerged:1;
 705                unsigned is_binary:1;
 706                unsigned is_renamed:1;
 707                unsigned int added, deleted;
 708        } **files;
 709};
 710
 711static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
 712                                          const char *name_a,
 713                                          const char *name_b)
 714{
 715        struct diffstat_file *x;
 716        x = xcalloc(sizeof (*x), 1);
 717        if (diffstat->nr == diffstat->alloc) {
 718                diffstat->alloc = alloc_nr(diffstat->alloc);
 719                diffstat->files = xrealloc(diffstat->files,
 720                                diffstat->alloc * sizeof(x));
 721        }
 722        diffstat->files[diffstat->nr++] = x;
 723        if (name_b) {
 724                x->name = pprint_rename(name_a, name_b);
 725                x->is_renamed = 1;
 726        }
 727        else
 728                x->name = xstrdup(name_a);
 729        return x;
 730}
 731
 732static void diffstat_consume(void *priv, char *line, unsigned long len)
 733{
 734        struct diffstat_t *diffstat = priv;
 735        struct diffstat_file *x = diffstat->files[diffstat->nr - 1];
 736
 737        if (line[0] == '+')
 738                x->added++;
 739        else if (line[0] == '-')
 740                x->deleted++;
 741}
 742
 743const char mime_boundary_leader[] = "------------";
 744
 745static int scale_linear(int it, int width, int max_change)
 746{
 747        /*
 748         * make sure that at least one '-' is printed if there were deletions,
 749         * and likewise for '+'.
 750         */
 751        if (max_change < 2)
 752                return it;
 753        return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1);
 754}
 755
 756static void show_name(const char *prefix, const char *name, int len,
 757                      const char *reset, const char *set)
 758{
 759        printf(" %s%s%-*s%s |", set, prefix, len, name, reset);
 760}
 761
 762static void show_graph(char ch, int cnt, const char *set, const char *reset)
 763{
 764        if (cnt <= 0)
 765                return;
 766        printf("%s", set);
 767        while (cnt--)
 768                putchar(ch);
 769        printf("%s", reset);
 770}
 771
 772static void show_stats(struct diffstat_t* data, struct diff_options *options)
 773{
 774        int i, len, add, del, total, adds = 0, dels = 0;
 775        int max_change = 0, max_len = 0;
 776        int total_files = data->nr;
 777        int width, name_width;
 778        const char *reset, *set, *add_c, *del_c;
 779
 780        if (data->nr == 0)
 781                return;
 782
 783        width = options->stat_width ? options->stat_width : 80;
 784        name_width = options->stat_name_width ? options->stat_name_width : 50;
 785
 786        /* Sanity: give at least 5 columns to the graph,
 787         * but leave at least 10 columns for the name.
 788         */
 789        if (width < name_width + 15) {
 790                if (name_width <= 25)
 791                        width = name_width + 15;
 792                else
 793                        name_width = width - 15;
 794        }
 795
 796        /* Find the longest filename and max number of changes */
 797        reset = diff_get_color(options->color_diff, DIFF_RESET);
 798        set = diff_get_color(options->color_diff, DIFF_PLAIN);
 799        add_c = diff_get_color(options->color_diff, DIFF_FILE_NEW);
 800        del_c = diff_get_color(options->color_diff, DIFF_FILE_OLD);
 801
 802        for (i = 0; i < data->nr; i++) {
 803                struct diffstat_file *file = data->files[i];
 804                int change = file->added + file->deleted;
 805
 806                if (!file->is_renamed) {  /* renames are already quoted by pprint_rename */
 807                        len = quote_c_style(file->name, NULL, NULL, 0);
 808                        if (len) {
 809                                char *qname = xmalloc(len + 1);
 810                                quote_c_style(file->name, qname, NULL, 0);
 811                                free(file->name);
 812                                file->name = qname;
 813                        }
 814                }
 815
 816                len = strlen(file->name);
 817                if (max_len < len)
 818                        max_len = len;
 819
 820                if (file->is_binary || file->is_unmerged)
 821                        continue;
 822                if (max_change < change)
 823                        max_change = change;
 824        }
 825
 826        /* Compute the width of the graph part;
 827         * 10 is for one blank at the beginning of the line plus
 828         * " | count " between the name and the graph.
 829         *
 830         * From here on, name_width is the width of the name area,
 831         * and width is the width of the graph area.
 832         */
 833        name_width = (name_width < max_len) ? name_width : max_len;
 834        if (width < (name_width + 10) + max_change)
 835                width = width - (name_width + 10);
 836        else
 837                width = max_change;
 838
 839        for (i = 0; i < data->nr; i++) {
 840                const char *prefix = "";
 841                char *name = data->files[i]->name;
 842                int added = data->files[i]->added;
 843                int deleted = data->files[i]->deleted;
 844                int name_len;
 845
 846                /*
 847                 * "scale" the filename
 848                 */
 849                len = name_width;
 850                name_len = strlen(name);
 851                if (name_width < name_len) {
 852                        char *slash;
 853                        prefix = "...";
 854                        len -= 3;
 855                        name += name_len - len;
 856                        slash = strchr(name, '/');
 857                        if (slash)
 858                                name = slash;
 859                }
 860
 861                if (data->files[i]->is_binary) {
 862                        show_name(prefix, name, len, reset, set);
 863                        printf("  Bin ");
 864                        printf("%s%d%s", del_c, deleted, reset);
 865                        printf(" -> ");
 866                        printf("%s%d%s", add_c, added, reset);
 867                        printf(" bytes");
 868                        printf("\n");
 869                        goto free_diffstat_file;
 870                }
 871                else if (data->files[i]->is_unmerged) {
 872                        show_name(prefix, name, len, reset, set);
 873                        printf("  Unmerged\n");
 874                        goto free_diffstat_file;
 875                }
 876                else if (!data->files[i]->is_renamed &&
 877                         (added + deleted == 0)) {
 878                        total_files--;
 879                        goto free_diffstat_file;
 880                }
 881
 882                /*
 883                 * scale the add/delete
 884                 */
 885                add = added;
 886                del = deleted;
 887                total = add + del;
 888                adds += add;
 889                dels += del;
 890
 891                if (width <= max_change) {
 892                        add = scale_linear(add, width, max_change);
 893                        del = scale_linear(del, width, max_change);
 894                        total = add + del;
 895                }
 896                show_name(prefix, name, len, reset, set);
 897                printf("%5d ", added + deleted);
 898                show_graph('+', add, add_c, reset);
 899                show_graph('-', del, del_c, reset);
 900                putchar('\n');
 901        free_diffstat_file:
 902                free(data->files[i]->name);
 903                free(data->files[i]);
 904        }
 905        free(data->files);
 906        printf("%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
 907               set, total_files, adds, dels, reset);
 908}
 909
 910static void show_shortstats(struct diffstat_t* data)
 911{
 912        int i, adds = 0, dels = 0, total_files = data->nr;
 913
 914        if (data->nr == 0)
 915                return;
 916
 917        for (i = 0; i < data->nr; i++) {
 918                if (!data->files[i]->is_binary &&
 919                    !data->files[i]->is_unmerged) {
 920                        int added = data->files[i]->added;
 921                        int deleted= data->files[i]->deleted;
 922                        if (!data->files[i]->is_renamed &&
 923                            (added + deleted == 0)) {
 924                                total_files--;
 925                        } else {
 926                                adds += added;
 927                                dels += deleted;
 928                        }
 929                }
 930                free(data->files[i]->name);
 931                free(data->files[i]);
 932        }
 933        free(data->files);
 934
 935        printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
 936               total_files, adds, dels);
 937}
 938
 939static void show_numstat(struct diffstat_t* data, struct diff_options *options)
 940{
 941        int i;
 942
 943        for (i = 0; i < data->nr; i++) {
 944                struct diffstat_file *file = data->files[i];
 945
 946                if (file->is_binary)
 947                        printf("-\t-\t");
 948                else
 949                        printf("%d\t%d\t", file->added, file->deleted);
 950                if (options->line_termination && !file->is_renamed &&
 951                    quote_c_style(file->name, NULL, NULL, 0))
 952                        quote_c_style(file->name, NULL, stdout, 0);
 953                else
 954                        fputs(file->name, stdout);
 955                putchar(options->line_termination);
 956        }
 957}
 958
 959struct checkdiff_t {
 960        struct xdiff_emit_state xm;
 961        const char *filename;
 962        int lineno, color_diff;
 963};
 964
 965static void checkdiff_consume(void *priv, char *line, unsigned long len)
 966{
 967        struct checkdiff_t *data = priv;
 968        const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);
 969        const char *reset = diff_get_color(data->color_diff, DIFF_RESET);
 970        const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);
 971
 972        if (line[0] == '+') {
 973                int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
 974
 975                /* check space before tab */
 976                for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
 977                        if (line[i] == ' ')
 978                                spaces++;
 979                if (line[i - 1] == '\t' && spaces)
 980                        space_before_tab = 1;
 981
 982                /* check white space at line end */
 983                if (line[len - 1] == '\n')
 984                        len--;
 985                if (isspace(line[len - 1]))
 986                        white_space_at_end = 1;
 987
 988                if (space_before_tab || white_space_at_end) {
 989                        printf("%s:%d: %s", data->filename, data->lineno, ws);
 990                        if (space_before_tab) {
 991                                printf("space before tab");
 992                                if (white_space_at_end)
 993                                        putchar(',');
 994                        }
 995                        if (white_space_at_end)
 996                                printf("white space at end");
 997                        printf(":%s ", reset);
 998                        emit_line_with_ws(1, set, reset, ws, line, len);
 999                }
1000
1001                data->lineno++;
1002        } else if (line[0] == ' ')
1003                data->lineno++;
1004        else if (line[0] == '@') {
1005                char *plus = strchr(line, '+');
1006                if (plus)
1007                        data->lineno = strtol(plus, NULL, 10);
1008                else
1009                        die("invalid diff");
1010        }
1011}
1012
1013static unsigned char *deflate_it(char *data,
1014                                 unsigned long size,
1015                                 unsigned long *result_size)
1016{
1017        int bound;
1018        unsigned char *deflated;
1019        z_stream stream;
1020
1021        memset(&stream, 0, sizeof(stream));
1022        deflateInit(&stream, zlib_compression_level);
1023        bound = deflateBound(&stream, size);
1024        deflated = xmalloc(bound);
1025        stream.next_out = deflated;
1026        stream.avail_out = bound;
1027
1028        stream.next_in = (unsigned char *)data;
1029        stream.avail_in = size;
1030        while (deflate(&stream, Z_FINISH) == Z_OK)
1031                ; /* nothing */
1032        deflateEnd(&stream);
1033        *result_size = stream.total_out;
1034        return deflated;
1035}
1036
1037static void emit_binary_diff_body(mmfile_t *one, mmfile_t *two)
1038{
1039        void *cp;
1040        void *delta;
1041        void *deflated;
1042        void *data;
1043        unsigned long orig_size;
1044        unsigned long delta_size;
1045        unsigned long deflate_size;
1046        unsigned long data_size;
1047
1048        /* We could do deflated delta, or we could do just deflated two,
1049         * whichever is smaller.
1050         */
1051        delta = NULL;
1052        deflated = deflate_it(two->ptr, two->size, &deflate_size);
1053        if (one->size && two->size) {
1054                delta = diff_delta(one->ptr, one->size,
1055                                   two->ptr, two->size,
1056                                   &delta_size, deflate_size);
1057                if (delta) {
1058                        void *to_free = delta;
1059                        orig_size = delta_size;
1060                        delta = deflate_it(delta, delta_size, &delta_size);
1061                        free(to_free);
1062                }
1063        }
1064
1065        if (delta && delta_size < deflate_size) {
1066                printf("delta %lu\n", orig_size);
1067                free(deflated);
1068                data = delta;
1069                data_size = delta_size;
1070        }
1071        else {
1072                printf("literal %lu\n", two->size);
1073                free(delta);
1074                data = deflated;
1075                data_size = deflate_size;
1076        }
1077
1078        /* emit data encoded in base85 */
1079        cp = data;
1080        while (data_size) {
1081                int bytes = (52 < data_size) ? 52 : data_size;
1082                char line[70];
1083                data_size -= bytes;
1084                if (bytes <= 26)
1085                        line[0] = bytes + 'A' - 1;
1086                else
1087                        line[0] = bytes - 26 + 'a' - 1;
1088                encode_85(line + 1, cp, bytes);
1089                cp = (char *) cp + bytes;
1090                puts(line);
1091        }
1092        printf("\n");
1093        free(data);
1094}
1095
1096static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
1097{
1098        printf("GIT binary patch\n");
1099        emit_binary_diff_body(one, two);
1100        emit_binary_diff_body(two, one);
1101}
1102
1103static void setup_diff_attr_check(struct git_attr_check *check)
1104{
1105        static struct git_attr *attr_diff;
1106
1107        if (!attr_diff)
1108                attr_diff = git_attr("diff", 4);
1109        check->attr = attr_diff;
1110}
1111
1112#define FIRST_FEW_BYTES 8000
1113static int file_is_binary(struct diff_filespec *one)
1114{
1115        unsigned long sz;
1116        struct git_attr_check attr_diff_check;
1117
1118        setup_diff_attr_check(&attr_diff_check);
1119        if (!git_checkattr(one->path, 1, &attr_diff_check)) {
1120                const char *value = attr_diff_check.value;
1121                if (ATTR_TRUE(value))
1122                        return 0;
1123                else if (ATTR_FALSE(value))
1124                        return 1;
1125        }
1126
1127        if (!one->data) {
1128                if (!DIFF_FILE_VALID(one))
1129                        return 0;
1130                diff_populate_filespec(one, 0);
1131        }
1132        sz = one->size;
1133        if (FIRST_FEW_BYTES < sz)
1134                sz = FIRST_FEW_BYTES;
1135        return !!memchr(one->data, 0, sz);
1136}
1137
1138static void builtin_diff(const char *name_a,
1139                         const char *name_b,
1140                         struct diff_filespec *one,
1141                         struct diff_filespec *two,
1142                         const char *xfrm_msg,
1143                         struct diff_options *o,
1144                         int complete_rewrite)
1145{
1146        mmfile_t mf1, mf2;
1147        const char *lbl[2];
1148        char *a_one, *b_two;
1149        const char *set = diff_get_color(o->color_diff, DIFF_METAINFO);
1150        const char *reset = diff_get_color(o->color_diff, DIFF_RESET);
1151
1152        a_one = quote_two("a/", name_a + (*name_a == '/'));
1153        b_two = quote_two("b/", name_b + (*name_b == '/'));
1154        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
1155        lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
1156        printf("%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
1157        if (lbl[0][0] == '/') {
1158                /* /dev/null */
1159                printf("%snew file mode %06o%s\n", set, two->mode, reset);
1160                if (xfrm_msg && xfrm_msg[0])
1161                        printf("%s%s%s\n", set, xfrm_msg, reset);
1162        }
1163        else if (lbl[1][0] == '/') {
1164                printf("%sdeleted file mode %06o%s\n", set, one->mode, reset);
1165                if (xfrm_msg && xfrm_msg[0])
1166                        printf("%s%s%s\n", set, xfrm_msg, reset);
1167        }
1168        else {
1169                if (one->mode != two->mode) {
1170                        printf("%sold mode %06o%s\n", set, one->mode, reset);
1171                        printf("%snew mode %06o%s\n", set, two->mode, reset);
1172                }
1173                if (xfrm_msg && xfrm_msg[0])
1174                        printf("%s%s%s\n", set, xfrm_msg, reset);
1175                /*
1176                 * we do not run diff between different kind
1177                 * of objects.
1178                 */
1179                if ((one->mode ^ two->mode) & S_IFMT)
1180                        goto free_ab_and_return;
1181                if (complete_rewrite) {
1182                        emit_rewrite_diff(name_a, name_b, one, two,
1183                                        o->color_diff);
1184                        o->found_changes = 1;
1185                        goto free_ab_and_return;
1186                }
1187        }
1188
1189        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
1190                die("unable to read files to diff");
1191
1192        if (!o->text && (file_is_binary(one) || file_is_binary(two))) {
1193                /* Quite common confusing case */
1194                if (mf1.size == mf2.size &&
1195                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
1196                        goto free_ab_and_return;
1197                if (o->binary)
1198                        emit_binary_diff(&mf1, &mf2);
1199                else
1200                        printf("Binary files %s and %s differ\n",
1201                               lbl[0], lbl[1]);
1202                o->found_changes = 1;
1203        }
1204        else {
1205                /* Crazy xdl interfaces.. */
1206                const char *diffopts = getenv("GIT_DIFF_OPTS");
1207                xpparam_t xpp;
1208                xdemitconf_t xecfg;
1209                xdemitcb_t ecb;
1210                struct emit_callback ecbdata;
1211
1212                memset(&ecbdata, 0, sizeof(ecbdata));
1213                ecbdata.label_path = lbl;
1214                ecbdata.color_diff = o->color_diff;
1215                ecbdata.found_changesp = &o->found_changes;
1216                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
1217                xecfg.ctxlen = o->context;
1218                xecfg.flags = XDL_EMIT_FUNCNAMES;
1219                if (!diffopts)
1220                        ;
1221                else if (!prefixcmp(diffopts, "--unified="))
1222                        xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
1223                else if (!prefixcmp(diffopts, "-u"))
1224                        xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
1225                ecb.outf = xdiff_outf;
1226                ecb.priv = &ecbdata;
1227                ecbdata.xm.consume = fn_out_consume;
1228                if (o->color_diff_words)
1229                        ecbdata.diff_words =
1230                                xcalloc(1, sizeof(struct diff_words_data));
1231                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
1232                if (o->color_diff_words)
1233                        free_diff_words_data(&ecbdata);
1234        }
1235
1236 free_ab_and_return:
1237        diff_free_filespec_data(one);
1238        diff_free_filespec_data(two);
1239        free(a_one);
1240        free(b_two);
1241        return;
1242}
1243
1244static void builtin_diffstat(const char *name_a, const char *name_b,
1245                             struct diff_filespec *one,
1246                             struct diff_filespec *two,
1247                             struct diffstat_t *diffstat,
1248                             struct diff_options *o,
1249                             int complete_rewrite)
1250{
1251        mmfile_t mf1, mf2;
1252        struct diffstat_file *data;
1253
1254        data = diffstat_add(diffstat, name_a, name_b);
1255
1256        if (!one || !two) {
1257                data->is_unmerged = 1;
1258                return;
1259        }
1260        if (complete_rewrite) {
1261                diff_populate_filespec(one, 0);
1262                diff_populate_filespec(two, 0);
1263                data->deleted = count_lines(one->data, one->size);
1264                data->added = count_lines(two->data, two->size);
1265                goto free_and_return;
1266        }
1267        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
1268                die("unable to read files to diff");
1269
1270        if (file_is_binary(one) || file_is_binary(two)) {
1271                data->is_binary = 1;
1272                data->added = mf2.size;
1273                data->deleted = mf1.size;
1274        } else {
1275                /* Crazy xdl interfaces.. */
1276                xpparam_t xpp;
1277                xdemitconf_t xecfg;
1278                xdemitcb_t ecb;
1279
1280                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
1281                xecfg.ctxlen = 0;
1282                xecfg.flags = 0;
1283                ecb.outf = xdiff_outf;
1284                ecb.priv = diffstat;
1285                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
1286        }
1287
1288 free_and_return:
1289        diff_free_filespec_data(one);
1290        diff_free_filespec_data(two);
1291}
1292
1293static void builtin_checkdiff(const char *name_a, const char *name_b,
1294                             struct diff_filespec *one,
1295                             struct diff_filespec *two, struct diff_options *o)
1296{
1297        mmfile_t mf1, mf2;
1298        struct checkdiff_t data;
1299
1300        if (!two)
1301                return;
1302
1303        memset(&data, 0, sizeof(data));
1304        data.xm.consume = checkdiff_consume;
1305        data.filename = name_b ? name_b : name_a;
1306        data.lineno = 0;
1307        data.color_diff = o->color_diff;
1308
1309        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
1310                die("unable to read files to diff");
1311
1312        if (file_is_binary(two))
1313                goto free_and_return;
1314        else {
1315                /* Crazy xdl interfaces.. */
1316                xpparam_t xpp;
1317                xdemitconf_t xecfg;
1318                xdemitcb_t ecb;
1319
1320                xpp.flags = XDF_NEED_MINIMAL;
1321                xecfg.ctxlen = 0;
1322                xecfg.flags = 0;
1323                ecb.outf = xdiff_outf;
1324                ecb.priv = &data;
1325                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
1326        }
1327 free_and_return:
1328        diff_free_filespec_data(one);
1329        diff_free_filespec_data(two);
1330}
1331
1332struct diff_filespec *alloc_filespec(const char *path)
1333{
1334        int namelen = strlen(path);
1335        struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
1336
1337        memset(spec, 0, sizeof(*spec));
1338        spec->path = (char *)(spec + 1);
1339        memcpy(spec->path, path, namelen+1);
1340        return spec;
1341}
1342
1343void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
1344                   unsigned short mode)
1345{
1346        if (mode) {
1347                spec->mode = canon_mode(mode);
1348                hashcpy(spec->sha1, sha1);
1349                spec->sha1_valid = !is_null_sha1(sha1);
1350        }
1351}
1352
1353/*
1354 * Given a name and sha1 pair, if the dircache tells us the file in
1355 * the work tree has that object contents, return true, so that
1356 * prepare_temp_file() does not have to inflate and extract.
1357 */
1358static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
1359{
1360        struct cache_entry *ce;
1361        struct stat st;
1362        int pos, len;
1363
1364        /* We do not read the cache ourselves here, because the
1365         * benchmark with my previous version that always reads cache
1366         * shows that it makes things worse for diff-tree comparing
1367         * two linux-2.6 kernel trees in an already checked out work
1368         * tree.  This is because most diff-tree comparisons deal with
1369         * only a small number of files, while reading the cache is
1370         * expensive for a large project, and its cost outweighs the
1371         * savings we get by not inflating the object to a temporary
1372         * file.  Practically, this code only helps when we are used
1373         * by diff-cache --cached, which does read the cache before
1374         * calling us.
1375         */
1376        if (!active_cache)
1377                return 0;
1378
1379        /* We want to avoid the working directory if our caller
1380         * doesn't need the data in a normal file, this system
1381         * is rather slow with its stat/open/mmap/close syscalls,
1382         * and the object is contained in a pack file.  The pack
1383         * is probably already open and will be faster to obtain
1384         * the data through than the working directory.  Loose
1385         * objects however would tend to be slower as they need
1386         * to be individually opened and inflated.
1387         */
1388        if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL))
1389                return 0;
1390
1391        len = strlen(name);
1392        pos = cache_name_pos(name, len);
1393        if (pos < 0)
1394                return 0;
1395        ce = active_cache[pos];
1396        if ((lstat(name, &st) < 0) ||
1397            !S_ISREG(st.st_mode) || /* careful! */
1398            ce_match_stat(ce, &st, 0) ||
1399            hashcmp(sha1, ce->sha1))
1400                return 0;
1401        /* we return 1 only when we can stat, it is a regular file,
1402         * stat information matches, and sha1 recorded in the cache
1403         * matches.  I.e. we know the file in the work tree really is
1404         * the same as the <name, sha1> pair.
1405         */
1406        return 1;
1407}
1408
1409static int populate_from_stdin(struct diff_filespec *s)
1410{
1411#define INCREMENT 1024
1412        char *buf;
1413        unsigned long size;
1414        int got;
1415
1416        size = 0;
1417        buf = NULL;
1418        while (1) {
1419                buf = xrealloc(buf, size + INCREMENT);
1420                got = xread(0, buf + size, INCREMENT);
1421                if (!got)
1422                        break; /* EOF */
1423                if (got < 0)
1424                        return error("error while reading from stdin %s",
1425                                     strerror(errno));
1426                size += got;
1427        }
1428        s->should_munmap = 0;
1429        s->data = buf;
1430        s->size = size;
1431        s->should_free = 1;
1432        return 0;
1433}
1434
1435static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
1436{
1437        int len;
1438        char *data = xmalloc(100);
1439        len = snprintf(data, 100,
1440                "Subproject commit %s\n", sha1_to_hex(s->sha1));
1441        s->data = data;
1442        s->size = len;
1443        s->should_free = 1;
1444        if (size_only) {
1445                s->data = NULL;
1446                free(data);
1447        }
1448        return 0;
1449}
1450
1451/*
1452 * While doing rename detection and pickaxe operation, we may need to
1453 * grab the data for the blob (or file) for our own in-core comparison.
1454 * diff_filespec has data and size fields for this purpose.
1455 */
1456int diff_populate_filespec(struct diff_filespec *s, int size_only)
1457{
1458        int err = 0;
1459        if (!DIFF_FILE_VALID(s))
1460                die("internal error: asking to populate invalid file.");
1461        if (S_ISDIR(s->mode))
1462                return -1;
1463
1464        if (s->data)
1465                return 0;
1466
1467        if (size_only && 0 < s->size)
1468                return 0;
1469
1470        if (S_ISDIRLNK(s->mode))
1471                return diff_populate_gitlink(s, size_only);
1472
1473        if (!s->sha1_valid ||
1474            reuse_worktree_file(s->path, s->sha1, 0)) {
1475                struct stat st;
1476                int fd;
1477                char *buf;
1478                unsigned long size;
1479
1480                if (!strcmp(s->path, "-"))
1481                        return populate_from_stdin(s);
1482
1483                if (lstat(s->path, &st) < 0) {
1484                        if (errno == ENOENT) {
1485                        err_empty:
1486                                err = -1;
1487                        empty:
1488                                s->data = (char *)"";
1489                                s->size = 0;
1490                                return err;
1491                        }
1492                }
1493                s->size = xsize_t(st.st_size);
1494                if (!s->size)
1495                        goto empty;
1496                if (size_only)
1497                        return 0;
1498                if (S_ISLNK(st.st_mode)) {
1499                        int ret;
1500                        s->data = xmalloc(s->size);
1501                        s->should_free = 1;
1502                        ret = readlink(s->path, s->data, s->size);
1503                        if (ret < 0) {
1504                                free(s->data);
1505                                goto err_empty;
1506                        }
1507                        return 0;
1508                }
1509                fd = open(s->path, O_RDONLY);
1510                if (fd < 0)
1511                        goto err_empty;
1512                s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
1513                close(fd);
1514                s->should_munmap = 1;
1515
1516                /*
1517                 * Convert from working tree format to canonical git format
1518                 */
1519                size = s->size;
1520                buf = convert_to_git(s->path, s->data, &size);
1521                if (buf) {
1522                        munmap(s->data, s->size);
1523                        s->should_munmap = 0;
1524                        s->data = buf;
1525                        s->size = size;
1526                        s->should_free = 1;
1527                }
1528        }
1529        else {
1530                enum object_type type;
1531                if (size_only)
1532                        type = sha1_object_info(s->sha1, &s->size);
1533                else {
1534                        s->data = read_sha1_file(s->sha1, &type, &s->size);
1535                        s->should_free = 1;
1536                }
1537        }
1538        return 0;
1539}
1540
1541void diff_free_filespec_data(struct diff_filespec *s)
1542{
1543        if (s->should_free)
1544                free(s->data);
1545        else if (s->should_munmap)
1546                munmap(s->data, s->size);
1547
1548        if (s->should_free || s->should_munmap) {
1549                s->should_free = s->should_munmap = 0;
1550                s->data = NULL;
1551        }
1552        free(s->cnt_data);
1553        s->cnt_data = NULL;
1554}
1555
1556static void prep_temp_blob(struct diff_tempfile *temp,
1557                           void *blob,
1558                           unsigned long size,
1559                           const unsigned char *sha1,
1560                           int mode)
1561{
1562        int fd;
1563
1564        fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
1565        if (fd < 0)
1566                die("unable to create temp-file");
1567        if (write_in_full(fd, blob, size) != size)
1568                die("unable to write temp-file");
1569        close(fd);
1570        temp->name = temp->tmp_path;
1571        strcpy(temp->hex, sha1_to_hex(sha1));
1572        temp->hex[40] = 0;
1573        sprintf(temp->mode, "%06o", mode);
1574}
1575
1576static void prepare_temp_file(const char *name,
1577                              struct diff_tempfile *temp,
1578                              struct diff_filespec *one)
1579{
1580        if (!DIFF_FILE_VALID(one)) {
1581        not_a_valid_file:
1582                /* A '-' entry produces this for file-2, and
1583                 * a '+' entry produces this for file-1.
1584                 */
1585                temp->name = "/dev/null";
1586                strcpy(temp->hex, ".");
1587                strcpy(temp->mode, ".");
1588                return;
1589        }
1590
1591        if (!one->sha1_valid ||
1592            reuse_worktree_file(name, one->sha1, 1)) {
1593                struct stat st;
1594                if (lstat(name, &st) < 0) {
1595                        if (errno == ENOENT)
1596                                goto not_a_valid_file;
1597                        die("stat(%s): %s", name, strerror(errno));
1598                }
1599                if (S_ISLNK(st.st_mode)) {
1600                        int ret;
1601                        char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
1602                        size_t sz = xsize_t(st.st_size);
1603                        if (sizeof(buf) <= st.st_size)
1604                                die("symlink too long: %s", name);
1605                        ret = readlink(name, buf, sz);
1606                        if (ret < 0)
1607                                die("readlink(%s)", name);
1608                        prep_temp_blob(temp, buf, sz,
1609                                       (one->sha1_valid ?
1610                                        one->sha1 : null_sha1),
1611                                       (one->sha1_valid ?
1612                                        one->mode : S_IFLNK));
1613                }
1614                else {
1615                        /* we can borrow from the file in the work tree */
1616                        temp->name = name;
1617                        if (!one->sha1_valid)
1618                                strcpy(temp->hex, sha1_to_hex(null_sha1));
1619                        else
1620                                strcpy(temp->hex, sha1_to_hex(one->sha1));
1621                        /* Even though we may sometimes borrow the
1622                         * contents from the work tree, we always want
1623                         * one->mode.  mode is trustworthy even when
1624                         * !(one->sha1_valid), as long as
1625                         * DIFF_FILE_VALID(one).
1626                         */
1627                        sprintf(temp->mode, "%06o", one->mode);
1628                }
1629                return;
1630        }
1631        else {
1632                if (diff_populate_filespec(one, 0))
1633                        die("cannot read data blob for %s", one->path);
1634                prep_temp_blob(temp, one->data, one->size,
1635                               one->sha1, one->mode);
1636        }
1637}
1638
1639static void remove_tempfile(void)
1640{
1641        int i;
1642
1643        for (i = 0; i < 2; i++)
1644                if (diff_temp[i].name == diff_temp[i].tmp_path) {
1645                        unlink(diff_temp[i].name);
1646                        diff_temp[i].name = NULL;
1647                }
1648}
1649
1650static void remove_tempfile_on_signal(int signo)
1651{
1652        remove_tempfile();
1653        signal(SIGINT, SIG_DFL);
1654        raise(signo);
1655}
1656
1657static int spawn_prog(const char *pgm, const char **arg)
1658{
1659        pid_t pid;
1660        int status;
1661
1662        fflush(NULL);
1663        pid = fork();
1664        if (pid < 0)
1665                die("unable to fork");
1666        if (!pid) {
1667                execvp(pgm, (char *const*) arg);
1668                exit(255);
1669        }
1670
1671        while (waitpid(pid, &status, 0) < 0) {
1672                if (errno == EINTR)
1673                        continue;
1674                return -1;
1675        }
1676
1677        /* Earlier we did not check the exit status because
1678         * diff exits non-zero if files are different, and
1679         * we are not interested in knowing that.  It was a
1680         * mistake which made it harder to quit a diff-*
1681         * session that uses the git-apply-patch-script as
1682         * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
1683         * should also exit non-zero only when it wants to
1684         * abort the entire diff-* session.
1685         */
1686        if (WIFEXITED(status) && !WEXITSTATUS(status))
1687                return 0;
1688        return -1;
1689}
1690
1691/* An external diff command takes:
1692 *
1693 * diff-cmd name infile1 infile1-sha1 infile1-mode \
1694 *               infile2 infile2-sha1 infile2-mode [ rename-to ]
1695 *
1696 */
1697static void run_external_diff(const char *pgm,
1698                              const char *name,
1699                              const char *other,
1700                              struct diff_filespec *one,
1701                              struct diff_filespec *two,
1702                              const char *xfrm_msg,
1703                              int complete_rewrite)
1704{
1705        const char *spawn_arg[10];
1706        struct diff_tempfile *temp = diff_temp;
1707        int retval;
1708        static int atexit_asked = 0;
1709        const char *othername;
1710        const char **arg = &spawn_arg[0];
1711
1712        othername = (other? other : name);
1713        if (one && two) {
1714                prepare_temp_file(name, &temp[0], one);
1715                prepare_temp_file(othername, &temp[1], two);
1716                if (! atexit_asked &&
1717                    (temp[0].name == temp[0].tmp_path ||
1718                     temp[1].name == temp[1].tmp_path)) {
1719                        atexit_asked = 1;
1720                        atexit(remove_tempfile);
1721                }
1722                signal(SIGINT, remove_tempfile_on_signal);
1723        }
1724
1725        if (one && two) {
1726                *arg++ = pgm;
1727                *arg++ = name;
1728                *arg++ = temp[0].name;
1729                *arg++ = temp[0].hex;
1730                *arg++ = temp[0].mode;
1731                *arg++ = temp[1].name;
1732                *arg++ = temp[1].hex;
1733                *arg++ = temp[1].mode;
1734                if (other) {
1735                        *arg++ = other;
1736                        *arg++ = xfrm_msg;
1737                }
1738        } else {
1739                *arg++ = pgm;
1740                *arg++ = name;
1741        }
1742        *arg = NULL;
1743        retval = spawn_prog(pgm, spawn_arg);
1744        remove_tempfile();
1745        if (retval) {
1746                fprintf(stderr, "external diff died, stopping at %s.\n", name);
1747                exit(1);
1748        }
1749}
1750
1751static const char *external_diff_attr(const char *name)
1752{
1753        struct git_attr_check attr_diff_check;
1754
1755        setup_diff_attr_check(&attr_diff_check);
1756        if (!git_checkattr(name, 1, &attr_diff_check)) {
1757                const char *value = attr_diff_check.value;
1758                if (!ATTR_TRUE(value) &&
1759                    !ATTR_FALSE(value) &&
1760                    !ATTR_UNSET(value)) {
1761                        struct ll_diff_driver *drv;
1762
1763                        if (!user_diff_tail) {
1764                                user_diff_tail = &user_diff;
1765                                git_config(git_diff_ui_config);
1766                        }
1767                        for (drv = user_diff; drv; drv = drv->next)
1768                                if (!strcmp(drv->name, value))
1769                                        return drv->cmd;
1770                }
1771        }
1772        return NULL;
1773}
1774
1775static void run_diff_cmd(const char *pgm,
1776                         const char *name,
1777                         const char *other,
1778                         struct diff_filespec *one,
1779                         struct diff_filespec *two,
1780                         const char *xfrm_msg,
1781                         struct diff_options *o,
1782                         int complete_rewrite)
1783{
1784        if (!o->allow_external)
1785                pgm = NULL;
1786        else {
1787                const char *cmd = external_diff_attr(name);
1788                if (cmd)
1789                        pgm = cmd;
1790        }
1791
1792        if (pgm) {
1793                run_external_diff(pgm, name, other, one, two, xfrm_msg,
1794                                  complete_rewrite);
1795                return;
1796        }
1797        if (one && two)
1798                builtin_diff(name, other ? other : name,
1799                             one, two, xfrm_msg, o, complete_rewrite);
1800        else
1801                printf("* Unmerged path %s\n", name);
1802}
1803
1804static void diff_fill_sha1_info(struct diff_filespec *one)
1805{
1806        if (DIFF_FILE_VALID(one)) {
1807                if (!one->sha1_valid) {
1808                        struct stat st;
1809                        if (!strcmp(one->path, "-")) {
1810                                hashcpy(one->sha1, null_sha1);
1811                                return;
1812                        }
1813                        if (lstat(one->path, &st) < 0)
1814                                die("stat %s", one->path);
1815                        if (index_path(one->sha1, one->path, &st, 0))
1816                                die("cannot hash %s\n", one->path);
1817                }
1818        }
1819        else
1820                hashclr(one->sha1);
1821}
1822
1823static void run_diff(struct diff_filepair *p, struct diff_options *o)
1824{
1825        const char *pgm = external_diff();
1826        char msg[PATH_MAX*2+300], *xfrm_msg;
1827        struct diff_filespec *one;
1828        struct diff_filespec *two;
1829        const char *name;
1830        const char *other;
1831        char *name_munged, *other_munged;
1832        int complete_rewrite = 0;
1833        int len;
1834
1835        if (DIFF_PAIR_UNMERGED(p)) {
1836                /* unmerged */
1837                run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
1838                return;
1839        }
1840
1841        name = p->one->path;
1842        other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1843        name_munged = quote_one(name);
1844        other_munged = quote_one(other);
1845        one = p->one; two = p->two;
1846
1847        diff_fill_sha1_info(one);
1848        diff_fill_sha1_info(two);
1849
1850        len = 0;
1851        switch (p->status) {
1852        case DIFF_STATUS_COPIED:
1853                len += snprintf(msg + len, sizeof(msg) - len,
1854                                "similarity index %d%%\n"
1855                                "copy from %s\n"
1856                                "copy to %s\n",
1857                                (int)(0.5 + p->score * 100.0/MAX_SCORE),
1858                                name_munged, other_munged);
1859                break;
1860        case DIFF_STATUS_RENAMED:
1861                len += snprintf(msg + len, sizeof(msg) - len,
1862                                "similarity index %d%%\n"
1863                                "rename from %s\n"
1864                                "rename to %s\n",
1865                                (int)(0.5 + p->score * 100.0/MAX_SCORE),
1866                                name_munged, other_munged);
1867                break;
1868        case DIFF_STATUS_MODIFIED:
1869                if (p->score) {
1870                        len += snprintf(msg + len, sizeof(msg) - len,
1871                                        "dissimilarity index %d%%\n",
1872                                        (int)(0.5 + p->score *
1873                                              100.0/MAX_SCORE));
1874                        complete_rewrite = 1;
1875                        break;
1876                }
1877                /* fallthru */
1878        default:
1879                /* nothing */
1880                ;
1881        }
1882
1883        if (hashcmp(one->sha1, two->sha1)) {
1884                int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
1885
1886                if (o->binary) {
1887                        mmfile_t mf;
1888                        if ((!fill_mmfile(&mf, one) && file_is_binary(one)) ||
1889                            (!fill_mmfile(&mf, two) && file_is_binary(two)))
1890                                abbrev = 40;
1891                }
1892                len += snprintf(msg + len, sizeof(msg) - len,
1893                                "index %.*s..%.*s",
1894                                abbrev, sha1_to_hex(one->sha1),
1895                                abbrev, sha1_to_hex(two->sha1));
1896                if (one->mode == two->mode)
1897                        len += snprintf(msg + len, sizeof(msg) - len,
1898                                        " %06o", one->mode);
1899                len += snprintf(msg + len, sizeof(msg) - len, "\n");
1900        }
1901
1902        if (len)
1903                msg[--len] = 0;
1904        xfrm_msg = len ? msg : NULL;
1905
1906        if (!pgm &&
1907            DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
1908            (S_IFMT & one->mode) != (S_IFMT & two->mode)) {
1909                /* a filepair that changes between file and symlink
1910                 * needs to be split into deletion and creation.
1911                 */
1912                struct diff_filespec *null = alloc_filespec(two->path);
1913                run_diff_cmd(NULL, name, other, one, null, xfrm_msg, o, 0);
1914                free(null);
1915                null = alloc_filespec(one->path);
1916                run_diff_cmd(NULL, name, other, null, two, xfrm_msg, o, 0);
1917                free(null);
1918        }
1919        else
1920                run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
1921                             complete_rewrite);
1922
1923        free(name_munged);
1924        free(other_munged);
1925}
1926
1927static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
1928                         struct diffstat_t *diffstat)
1929{
1930        const char *name;
1931        const char *other;
1932        int complete_rewrite = 0;
1933
1934        if (DIFF_PAIR_UNMERGED(p)) {
1935                /* unmerged */
1936                builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);
1937                return;
1938        }
1939
1940        name = p->one->path;
1941        other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1942
1943        diff_fill_sha1_info(p->one);
1944        diff_fill_sha1_info(p->two);
1945
1946        if (p->status == DIFF_STATUS_MODIFIED && p->score)
1947                complete_rewrite = 1;
1948        builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);
1949}
1950
1951static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
1952{
1953        const char *name;
1954        const char *other;
1955
1956        if (DIFF_PAIR_UNMERGED(p)) {
1957                /* unmerged */
1958                return;
1959        }
1960
1961        name = p->one->path;
1962        other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1963
1964        diff_fill_sha1_info(p->one);
1965        diff_fill_sha1_info(p->two);
1966
1967        builtin_checkdiff(name, other, p->one, p->two, o);
1968}
1969
1970void diff_setup(struct diff_options *options)
1971{
1972        memset(options, 0, sizeof(*options));
1973        options->line_termination = '\n';
1974        options->break_opt = -1;
1975        options->rename_limit = -1;
1976        options->context = 3;
1977        options->msg_sep = "";
1978
1979        options->change = diff_change;
1980        options->add_remove = diff_addremove;
1981        options->color_diff = diff_use_color_default;
1982        options->detect_rename = diff_detect_rename_default;
1983}
1984
1985int diff_setup_done(struct diff_options *options)
1986{
1987        int count = 0;
1988
1989        if (options->output_format & DIFF_FORMAT_NAME)
1990                count++;
1991        if (options->output_format & DIFF_FORMAT_NAME_STATUS)
1992                count++;
1993        if (options->output_format & DIFF_FORMAT_CHECKDIFF)
1994                count++;
1995        if (options->output_format & DIFF_FORMAT_NO_OUTPUT)
1996                count++;
1997        if (count > 1)
1998                die("--name-only, --name-status, --check and -s are mutually exclusive");
1999
2000        if (options->find_copies_harder)
2001                options->detect_rename = DIFF_DETECT_COPY;
2002
2003        if (options->output_format & (DIFF_FORMAT_NAME |
2004                                      DIFF_FORMAT_NAME_STATUS |
2005                                      DIFF_FORMAT_CHECKDIFF |
2006                                      DIFF_FORMAT_NO_OUTPUT))
2007                options->output_format &= ~(DIFF_FORMAT_RAW |
2008                                            DIFF_FORMAT_NUMSTAT |
2009                                            DIFF_FORMAT_DIFFSTAT |
2010                                            DIFF_FORMAT_SHORTSTAT |
2011                                            DIFF_FORMAT_SUMMARY |
2012                                            DIFF_FORMAT_PATCH);
2013
2014        /*
2015         * These cases always need recursive; we do not drop caller-supplied
2016         * recursive bits for other formats here.
2017         */
2018        if (options->output_format & (DIFF_FORMAT_PATCH |
2019                                      DIFF_FORMAT_NUMSTAT |
2020                                      DIFF_FORMAT_DIFFSTAT |
2021                                      DIFF_FORMAT_SHORTSTAT |
2022                                      DIFF_FORMAT_SUMMARY |
2023                                      DIFF_FORMAT_CHECKDIFF))
2024                options->recursive = 1;
2025        /*
2026         * Also pickaxe would not work very well if you do not say recursive
2027         */
2028        if (options->pickaxe)
2029                options->recursive = 1;
2030
2031        if (options->detect_rename && options->rename_limit < 0)
2032                options->rename_limit = diff_rename_limit_default;
2033        if (options->setup & DIFF_SETUP_USE_CACHE) {
2034                if (!active_cache)
2035                        /* read-cache does not die even when it fails
2036                         * so it is safe for us to do this here.  Also
2037                         * it does not smudge active_cache or active_nr
2038                         * when it fails, so we do not have to worry about
2039                         * cleaning it up ourselves either.
2040                         */
2041                        read_cache();
2042        }
2043        if (options->abbrev <= 0 || 40 < options->abbrev)
2044                options->abbrev = 40; /* full */
2045
2046        /*
2047         * It does not make sense to show the first hit we happened
2048         * to have found.  It does not make sense not to return with
2049         * exit code in such a case either.
2050         */
2051        if (options->quiet) {
2052                options->output_format = DIFF_FORMAT_NO_OUTPUT;
2053                options->exit_with_status = 1;
2054        }
2055
2056        /*
2057         * If we postprocess in diffcore, we cannot simply return
2058         * upon the first hit.  We need to run diff as usual.
2059         */
2060        if (options->pickaxe || options->filter)
2061                options->quiet = 0;
2062
2063        return 0;
2064}
2065
2066static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
2067{
2068        char c, *eq;
2069        int len;
2070
2071        if (*arg != '-')
2072                return 0;
2073        c = *++arg;
2074        if (!c)
2075                return 0;
2076        if (c == arg_short) {
2077                c = *++arg;
2078                if (!c)
2079                        return 1;
2080                if (val && isdigit(c)) {
2081                        char *end;
2082                        int n = strtoul(arg, &end, 10);
2083                        if (*end)
2084                                return 0;
2085                        *val = n;
2086                        return 1;
2087                }
2088                return 0;
2089        }
2090        if (c != '-')
2091                return 0;
2092        arg++;
2093        eq = strchr(arg, '=');
2094        if (eq)
2095                len = eq - arg;
2096        else
2097                len = strlen(arg);
2098        if (!len || strncmp(arg, arg_long, len))
2099                return 0;
2100        if (eq) {
2101                int n;
2102                char *end;
2103                if (!isdigit(*++eq))
2104                        return 0;
2105                n = strtoul(eq, &end, 10);
2106                if (*end)
2107                        return 0;
2108                *val = n;
2109        }
2110        return 1;
2111}
2112
2113int diff_opt_parse(struct diff_options *options, const char **av, int ac)
2114{
2115        const char *arg = av[0];
2116        if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
2117                options->output_format |= DIFF_FORMAT_PATCH;
2118        else if (opt_arg(arg, 'U', "unified", &options->context))
2119                options->output_format |= DIFF_FORMAT_PATCH;
2120        else if (!strcmp(arg, "--raw"))
2121                options->output_format |= DIFF_FORMAT_RAW;
2122        else if (!strcmp(arg, "--patch-with-raw")) {
2123                options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
2124        }
2125        else if (!strcmp(arg, "--numstat")) {
2126                options->output_format |= DIFF_FORMAT_NUMSTAT;
2127        }
2128        else if (!strcmp(arg, "--shortstat")) {
2129                options->output_format |= DIFF_FORMAT_SHORTSTAT;
2130        }
2131        else if (!prefixcmp(arg, "--stat")) {
2132                char *end;
2133                int width = options->stat_width;
2134                int name_width = options->stat_name_width;
2135                arg += 6;
2136                end = (char *)arg;
2137
2138                switch (*arg) {
2139                case '-':
2140                        if (!prefixcmp(arg, "-width="))
2141                                width = strtoul(arg + 7, &end, 10);
2142                        else if (!prefixcmp(arg, "-name-width="))
2143                                name_width = strtoul(arg + 12, &end, 10);
2144                        break;
2145                case '=':
2146                        width = strtoul(arg+1, &end, 10);
2147                        if (*end == ',')
2148                                name_width = strtoul(end+1, &end, 10);
2149                }
2150
2151                /* Important! This checks all the error cases! */
2152                if (*end)
2153                        return 0;
2154                options->output_format |= DIFF_FORMAT_DIFFSTAT;
2155                options->stat_name_width = name_width;
2156                options->stat_width = width;
2157        }
2158        else if (!strcmp(arg, "--check"))
2159                options->output_format |= DIFF_FORMAT_CHECKDIFF;
2160        else if (!strcmp(arg, "--summary"))
2161                options->output_format |= DIFF_FORMAT_SUMMARY;
2162        else if (!strcmp(arg, "--patch-with-stat")) {
2163                options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
2164        }
2165        else if (!strcmp(arg, "-z"))
2166                options->line_termination = 0;
2167        else if (!prefixcmp(arg, "-l"))
2168                options->rename_limit = strtoul(arg+2, NULL, 10);
2169        else if (!strcmp(arg, "--full-index"))
2170                options->full_index = 1;
2171        else if (!strcmp(arg, "--binary")) {
2172                options->output_format |= DIFF_FORMAT_PATCH;
2173                options->binary = 1;
2174        }
2175        else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) {
2176                options->text = 1;
2177        }
2178        else if (!strcmp(arg, "--name-only"))
2179                options->output_format |= DIFF_FORMAT_NAME;
2180        else if (!strcmp(arg, "--name-status"))
2181                options->output_format |= DIFF_FORMAT_NAME_STATUS;
2182        else if (!strcmp(arg, "-R"))
2183                options->reverse_diff = 1;
2184        else if (!prefixcmp(arg, "-S"))
2185                options->pickaxe = arg + 2;
2186        else if (!strcmp(arg, "-s")) {
2187                options->output_format |= DIFF_FORMAT_NO_OUTPUT;
2188        }
2189        else if (!prefixcmp(arg, "-O"))
2190                options->orderfile = arg + 2;
2191        else if (!prefixcmp(arg, "--diff-filter="))
2192                options->filter = arg + 14;
2193        else if (!strcmp(arg, "--pickaxe-all"))
2194                options->pickaxe_opts = DIFF_PICKAXE_ALL;
2195        else if (!strcmp(arg, "--pickaxe-regex"))
2196                options->pickaxe_opts = DIFF_PICKAXE_REGEX;
2197        else if (!prefixcmp(arg, "-B")) {
2198                if ((options->break_opt =
2199                     diff_scoreopt_parse(arg)) == -1)
2200                        return -1;
2201        }
2202        else if (!prefixcmp(arg, "-M")) {
2203                if ((options->rename_score =
2204                     diff_scoreopt_parse(arg)) == -1)
2205                        return -1;
2206                options->detect_rename = DIFF_DETECT_RENAME;
2207        }
2208        else if (!prefixcmp(arg, "-C")) {
2209                if ((options->rename_score =
2210                     diff_scoreopt_parse(arg)) == -1)
2211                        return -1;
2212                options->detect_rename = DIFF_DETECT_COPY;
2213        }
2214        else if (!strcmp(arg, "--find-copies-harder"))
2215                options->find_copies_harder = 1;
2216        else if (!strcmp(arg, "--abbrev"))
2217                options->abbrev = DEFAULT_ABBREV;
2218        else if (!prefixcmp(arg, "--abbrev=")) {
2219                options->abbrev = strtoul(arg + 9, NULL, 10);
2220                if (options->abbrev < MINIMUM_ABBREV)
2221                        options->abbrev = MINIMUM_ABBREV;
2222                else if (40 < options->abbrev)
2223                        options->abbrev = 40;
2224        }
2225        else if (!strcmp(arg, "--color"))
2226                options->color_diff = 1;
2227        else if (!strcmp(arg, "--no-color"))
2228                options->color_diff = 0;
2229        else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
2230                options->xdl_opts |= XDF_IGNORE_WHITESPACE;
2231        else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
2232                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
2233        else if (!strcmp(arg, "--ignore-space-at-eol"))
2234                options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
2235        else if (!strcmp(arg, "--color-words"))
2236                options->color_diff = options->color_diff_words = 1;
2237        else if (!strcmp(arg, "--no-renames"))
2238                options->detect_rename = 0;
2239        else if (!strcmp(arg, "--exit-code"))
2240                options->exit_with_status = 1;
2241        else if (!strcmp(arg, "--quiet"))
2242                options->quiet = 1;
2243        else
2244                return 0;
2245        return 1;
2246}
2247
2248static int parse_num(const char **cp_p)
2249{
2250        unsigned long num, scale;
2251        int ch, dot;
2252        const char *cp = *cp_p;
2253
2254        num = 0;
2255        scale = 1;
2256        dot = 0;
2257        for(;;) {
2258                ch = *cp;
2259                if ( !dot && ch == '.' ) {
2260                        scale = 1;
2261                        dot = 1;
2262                } else if ( ch == '%' ) {
2263                        scale = dot ? scale*100 : 100;
2264                        cp++;   /* % is always at the end */
2265                        break;
2266                } else if ( ch >= '0' && ch <= '9' ) {
2267                        if ( scale < 100000 ) {
2268                                scale *= 10;
2269                                num = (num*10) + (ch-'0');
2270                        }
2271                } else {
2272                        break;
2273                }
2274                cp++;
2275        }
2276        *cp_p = cp;
2277
2278        /* user says num divided by scale and we say internally that
2279         * is MAX_SCORE * num / scale.
2280         */
2281        return (int)((num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale));
2282}
2283
2284int diff_scoreopt_parse(const char *opt)
2285{
2286        int opt1, opt2, cmd;
2287
2288        if (*opt++ != '-')
2289                return -1;
2290        cmd = *opt++;
2291        if (cmd != 'M' && cmd != 'C' && cmd != 'B')
2292                return -1; /* that is not a -M, -C nor -B option */
2293
2294        opt1 = parse_num(&opt);
2295        if (cmd != 'B')
2296                opt2 = 0;
2297        else {
2298                if (*opt == 0)
2299                        opt2 = 0;
2300                else if (*opt != '/')
2301                        return -1; /* we expect -B80/99 or -B80 */
2302                else {
2303                        opt++;
2304                        opt2 = parse_num(&opt);
2305                }
2306        }
2307        if (*opt != 0)
2308                return -1;
2309        return opt1 | (opt2 << 16);
2310}
2311
2312struct diff_queue_struct diff_queued_diff;
2313
2314void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
2315{
2316        if (queue->alloc <= queue->nr) {
2317                queue->alloc = alloc_nr(queue->alloc);
2318                queue->queue = xrealloc(queue->queue,
2319                                        sizeof(dp) * queue->alloc);
2320        }
2321        queue->queue[queue->nr++] = dp;
2322}
2323
2324struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
2325                                 struct diff_filespec *one,
2326                                 struct diff_filespec *two)
2327{
2328        struct diff_filepair *dp = xcalloc(1, sizeof(*dp));
2329        dp->one = one;
2330        dp->two = two;
2331        if (queue)
2332                diff_q(queue, dp);
2333        return dp;
2334}
2335
2336void diff_free_filepair(struct diff_filepair *p)
2337{
2338        diff_free_filespec_data(p->one);
2339        diff_free_filespec_data(p->two);
2340        free(p->one);
2341        free(p->two);
2342        free(p);
2343}
2344
2345/* This is different from find_unique_abbrev() in that
2346 * it stuffs the result with dots for alignment.
2347 */
2348const char *diff_unique_abbrev(const unsigned char *sha1, int len)
2349{
2350        int abblen;
2351        const char *abbrev;
2352        if (len == 40)
2353                return sha1_to_hex(sha1);
2354
2355        abbrev = find_unique_abbrev(sha1, len);
2356        if (!abbrev)
2357                return sha1_to_hex(sha1);
2358        abblen = strlen(abbrev);
2359        if (abblen < 37) {
2360                static char hex[41];
2361                if (len < abblen && abblen <= len + 2)
2362                        sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
2363                else
2364                        sprintf(hex, "%s...", abbrev);
2365                return hex;
2366        }
2367        return sha1_to_hex(sha1);
2368}
2369
2370static void diff_flush_raw(struct diff_filepair *p,
2371                           struct diff_options *options)
2372{
2373        int two_paths;
2374        char status[10];
2375        int abbrev = options->abbrev;
2376        const char *path_one, *path_two;
2377        int inter_name_termination = '\t';
2378        int line_termination = options->line_termination;
2379
2380        if (!line_termination)
2381                inter_name_termination = 0;
2382
2383        path_one = p->one->path;
2384        path_two = p->two->path;
2385        if (line_termination) {
2386                path_one = quote_one(path_one);
2387                path_two = quote_one(path_two);
2388        }
2389
2390        if (p->score)
2391                sprintf(status, "%c%03d", p->status,
2392                        (int)(0.5 + p->score * 100.0/MAX_SCORE));
2393        else {
2394                status[0] = p->status;
2395                status[1] = 0;
2396        }
2397        switch (p->status) {
2398        case DIFF_STATUS_COPIED:
2399        case DIFF_STATUS_RENAMED:
2400                two_paths = 1;
2401                break;
2402        case DIFF_STATUS_ADDED:
2403        case DIFF_STATUS_DELETED:
2404                two_paths = 0;
2405                break;
2406        default:
2407                two_paths = 0;
2408                break;
2409        }
2410        if (!(options->output_format & DIFF_FORMAT_NAME_STATUS)) {
2411                printf(":%06o %06o %s ",
2412                       p->one->mode, p->two->mode,
2413                       diff_unique_abbrev(p->one->sha1, abbrev));
2414                printf("%s ",
2415                       diff_unique_abbrev(p->two->sha1, abbrev));
2416        }
2417        printf("%s%c%s", status, inter_name_termination, path_one);
2418        if (two_paths)
2419                printf("%c%s", inter_name_termination, path_two);
2420        putchar(line_termination);
2421        if (path_one != p->one->path)
2422                free((void*)path_one);
2423        if (path_two != p->two->path)
2424                free((void*)path_two);
2425}
2426
2427static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt)
2428{
2429        char *path = p->two->path;
2430
2431        if (opt->line_termination)
2432                path = quote_one(p->two->path);
2433        printf("%s%c", path, opt->line_termination);
2434        if (p->two->path != path)
2435                free(path);
2436}
2437
2438int diff_unmodified_pair(struct diff_filepair *p)
2439{
2440        /* This function is written stricter than necessary to support
2441         * the currently implemented transformers, but the idea is to
2442         * let transformers to produce diff_filepairs any way they want,
2443         * and filter and clean them up here before producing the output.
2444         */
2445        struct diff_filespec *one, *two;
2446
2447        if (DIFF_PAIR_UNMERGED(p))
2448                return 0; /* unmerged is interesting */
2449
2450        one = p->one;
2451        two = p->two;
2452
2453        /* deletion, addition, mode or type change
2454         * and rename are all interesting.
2455         */
2456        if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
2457            DIFF_PAIR_MODE_CHANGED(p) ||
2458            strcmp(one->path, two->path))
2459                return 0;
2460
2461        /* both are valid and point at the same path.  that is, we are
2462         * dealing with a change.
2463         */
2464        if (one->sha1_valid && two->sha1_valid &&
2465            !hashcmp(one->sha1, two->sha1))
2466                return 1; /* no change */
2467        if (!one->sha1_valid && !two->sha1_valid)
2468                return 1; /* both look at the same file on the filesystem. */
2469        return 0;
2470}
2471
2472static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
2473{
2474        if (diff_unmodified_pair(p))
2475                return;
2476
2477        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
2478            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
2479                return; /* no tree diffs in patch format */
2480
2481        run_diff(p, o);
2482}
2483
2484static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
2485                            struct diffstat_t *diffstat)
2486{
2487        if (diff_unmodified_pair(p))
2488                return;
2489
2490        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
2491            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
2492                return; /* no tree diffs in patch format */
2493
2494        run_diffstat(p, o, diffstat);
2495}
2496
2497static void diff_flush_checkdiff(struct diff_filepair *p,
2498                struct diff_options *o)
2499{
2500        if (diff_unmodified_pair(p))
2501                return;
2502
2503        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
2504            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
2505                return; /* no tree diffs in patch format */
2506
2507        run_checkdiff(p, o);
2508}
2509
2510int diff_queue_is_empty(void)
2511{
2512        struct diff_queue_struct *q = &diff_queued_diff;
2513        int i;
2514        for (i = 0; i < q->nr; i++)
2515                if (!diff_unmodified_pair(q->queue[i]))
2516                        return 0;
2517        return 1;
2518}
2519
2520#if DIFF_DEBUG
2521void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
2522{
2523        fprintf(stderr, "queue[%d] %s (%s) %s %06o %s\n",
2524                x, one ? one : "",
2525                s->path,
2526                DIFF_FILE_VALID(s) ? "valid" : "invalid",
2527                s->mode,
2528                s->sha1_valid ? sha1_to_hex(s->sha1) : "");
2529        fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
2530                x, one ? one : "",
2531                s->size, s->xfrm_flags);
2532}
2533
2534void diff_debug_filepair(const struct diff_filepair *p, int i)
2535{
2536        diff_debug_filespec(p->one, i, "one");
2537        diff_debug_filespec(p->two, i, "two");
2538        fprintf(stderr, "score %d, status %c stays %d broken %d\n",
2539                p->score, p->status ? p->status : '?',
2540                p->source_stays, p->broken_pair);
2541}
2542
2543void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
2544{
2545        int i;
2546        if (msg)
2547                fprintf(stderr, "%s\n", msg);
2548        fprintf(stderr, "q->nr = %d\n", q->nr);
2549        for (i = 0; i < q->nr; i++) {
2550                struct diff_filepair *p = q->queue[i];
2551                diff_debug_filepair(p, i);
2552        }
2553}
2554#endif
2555
2556static void diff_resolve_rename_copy(void)
2557{
2558        int i, j;
2559        struct diff_filepair *p, *pp;
2560        struct diff_queue_struct *q = &diff_queued_diff;
2561
2562        diff_debug_queue("resolve-rename-copy", q);
2563
2564        for (i = 0; i < q->nr; i++) {
2565                p = q->queue[i];
2566                p->status = 0; /* undecided */
2567                if (DIFF_PAIR_UNMERGED(p))
2568                        p->status = DIFF_STATUS_UNMERGED;
2569                else if (!DIFF_FILE_VALID(p->one))
2570                        p->status = DIFF_STATUS_ADDED;
2571                else if (!DIFF_FILE_VALID(p->two))
2572                        p->status = DIFF_STATUS_DELETED;
2573                else if (DIFF_PAIR_TYPE_CHANGED(p))
2574                        p->status = DIFF_STATUS_TYPE_CHANGED;
2575
2576                /* from this point on, we are dealing with a pair
2577                 * whose both sides are valid and of the same type, i.e.
2578                 * either in-place edit or rename/copy edit.
2579                 */
2580                else if (DIFF_PAIR_RENAME(p)) {
2581                        if (p->source_stays) {
2582                                p->status = DIFF_STATUS_COPIED;
2583                                continue;
2584                        }
2585                        /* See if there is some other filepair that
2586                         * copies from the same source as us.  If so
2587                         * we are a copy.  Otherwise we are either a
2588                         * copy if the path stays, or a rename if it
2589                         * does not, but we already handled "stays" case.
2590                         */
2591                        for (j = i + 1; j < q->nr; j++) {
2592                                pp = q->queue[j];
2593                                if (strcmp(pp->one->path, p->one->path))
2594                                        continue; /* not us */
2595                                if (!DIFF_PAIR_RENAME(pp))
2596                                        continue; /* not a rename/copy */
2597                                /* pp is a rename/copy from the same source */
2598                                p->status = DIFF_STATUS_COPIED;
2599                                break;
2600                        }
2601                        if (!p->status)
2602                                p->status = DIFF_STATUS_RENAMED;
2603                }
2604                else if (hashcmp(p->one->sha1, p->two->sha1) ||
2605                         p->one->mode != p->two->mode ||
2606                         is_null_sha1(p->one->sha1))
2607                        p->status = DIFF_STATUS_MODIFIED;
2608                else {
2609                        /* This is a "no-change" entry and should not
2610                         * happen anymore, but prepare for broken callers.
2611                         */
2612                        error("feeding unmodified %s to diffcore",
2613                              p->one->path);
2614                        p->status = DIFF_STATUS_UNKNOWN;
2615                }
2616        }
2617        diff_debug_queue("resolve-rename-copy done", q);
2618}
2619
2620static int check_pair_status(struct diff_filepair *p)
2621{
2622        switch (p->status) {
2623        case DIFF_STATUS_UNKNOWN:
2624                return 0;
2625        case 0:
2626                die("internal error in diff-resolve-rename-copy");
2627        default:
2628                return 1;
2629        }
2630}
2631
2632static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
2633{
2634        int fmt = opt->output_format;
2635
2636        if (fmt & DIFF_FORMAT_CHECKDIFF)
2637                diff_flush_checkdiff(p, opt);
2638        else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
2639                diff_flush_raw(p, opt);
2640        else if (fmt & DIFF_FORMAT_NAME)
2641                diff_flush_name(p, opt);
2642}
2643
2644static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
2645{
2646        char *name = quote_one(fs->path);
2647        if (fs->mode)
2648                printf(" %s mode %06o %s\n", newdelete, fs->mode, name);
2649        else
2650                printf(" %s %s\n", newdelete, name);
2651        free(name);
2652}
2653
2654
2655static void show_mode_change(struct diff_filepair *p, int show_name)
2656{
2657        if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
2658                if (show_name) {
2659                        char *name = quote_one(p->two->path);
2660                        printf(" mode change %06o => %06o %s\n",
2661                               p->one->mode, p->two->mode, name);
2662                        free(name);
2663                }
2664                else
2665                        printf(" mode change %06o => %06o\n",
2666                               p->one->mode, p->two->mode);
2667        }
2668}
2669
2670static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
2671{
2672        char *names = pprint_rename(p->one->path, p->two->path);
2673
2674        printf(" %s %s (%d%%)\n", renamecopy, names,
2675               (int)(0.5 + p->score * 100.0/MAX_SCORE));
2676        free(names);
2677        show_mode_change(p, 0);
2678}
2679
2680static void diff_summary(struct diff_filepair *p)
2681{
2682        switch(p->status) {
2683        case DIFF_STATUS_DELETED:
2684                show_file_mode_name("delete", p->one);
2685                break;
2686        case DIFF_STATUS_ADDED:
2687                show_file_mode_name("create", p->two);
2688                break;
2689        case DIFF_STATUS_COPIED:
2690                show_rename_copy("copy", p);
2691                break;
2692        case DIFF_STATUS_RENAMED:
2693                show_rename_copy("rename", p);
2694                break;
2695        default:
2696                if (p->score) {
2697                        char *name = quote_one(p->two->path);
2698                        printf(" rewrite %s (%d%%)\n", name,
2699                                (int)(0.5 + p->score * 100.0/MAX_SCORE));
2700                        free(name);
2701                        show_mode_change(p, 0);
2702                } else  show_mode_change(p, 1);
2703                break;
2704        }
2705}
2706
2707struct patch_id_t {
2708        struct xdiff_emit_state xm;
2709        SHA_CTX *ctx;
2710        int patchlen;
2711};
2712
2713static int remove_space(char *line, int len)
2714{
2715        int i;
2716        char *dst = line;
2717        unsigned char c;
2718
2719        for (i = 0; i < len; i++)
2720                if (!isspace((c = line[i])))
2721                        *dst++ = c;
2722
2723        return dst - line;
2724}
2725
2726static void patch_id_consume(void *priv, char *line, unsigned long len)
2727{
2728        struct patch_id_t *data = priv;
2729        int new_len;
2730
2731        /* Ignore line numbers when computing the SHA1 of the patch */
2732        if (!prefixcmp(line, "@@ -"))
2733                return;
2734
2735        new_len = remove_space(line, len);
2736
2737        SHA1_Update(data->ctx, line, new_len);
2738        data->patchlen += new_len;
2739}
2740
2741/* returns 0 upon success, and writes result into sha1 */
2742static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
2743{
2744        struct diff_queue_struct *q = &diff_queued_diff;
2745        int i;
2746        SHA_CTX ctx;
2747        struct patch_id_t data;
2748        char buffer[PATH_MAX * 4 + 20];
2749
2750        SHA1_Init(&ctx);
2751        memset(&data, 0, sizeof(struct patch_id_t));
2752        data.ctx = &ctx;
2753        data.xm.consume = patch_id_consume;
2754
2755        for (i = 0; i < q->nr; i++) {
2756                xpparam_t xpp;
2757                xdemitconf_t xecfg;
2758                xdemitcb_t ecb;
2759                mmfile_t mf1, mf2;
2760                struct diff_filepair *p = q->queue[i];
2761                int len1, len2;
2762
2763                if (p->status == 0)
2764                        return error("internal diff status error");
2765                if (p->status == DIFF_STATUS_UNKNOWN)
2766                        continue;
2767                if (diff_unmodified_pair(p))
2768                        continue;
2769                if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
2770                    (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
2771                        continue;
2772                if (DIFF_PAIR_UNMERGED(p))
2773                        continue;
2774
2775                diff_fill_sha1_info(p->one);
2776                diff_fill_sha1_info(p->two);
2777                if (fill_mmfile(&mf1, p->one) < 0 ||
2778                                fill_mmfile(&mf2, p->two) < 0)
2779                        return error("unable to read files to diff");
2780
2781                /* Maybe hash p->two? into the patch id? */
2782                if (file_is_binary(p->two))
2783                        continue;
2784
2785                len1 = remove_space(p->one->path, strlen(p->one->path));
2786                len2 = remove_space(p->two->path, strlen(p->two->path));
2787                if (p->one->mode == 0)
2788                        len1 = snprintf(buffer, sizeof(buffer),
2789                                        "diff--gita/%.*sb/%.*s"
2790                                        "newfilemode%06o"
2791                                        "---/dev/null"
2792                                        "+++b/%.*s",
2793                                        len1, p->one->path,
2794                                        len2, p->two->path,
2795                                        p->two->mode,
2796                                        len2, p->two->path);
2797                else if (p->two->mode == 0)
2798                        len1 = snprintf(buffer, sizeof(buffer),
2799                                        "diff--gita/%.*sb/%.*s"
2800                                        "deletedfilemode%06o"
2801                                        "---a/%.*s"
2802                                        "+++/dev/null",
2803                                        len1, p->one->path,
2804                                        len2, p->two->path,
2805                                        p->one->mode,
2806                                        len1, p->one->path);
2807                else
2808                        len1 = snprintf(buffer, sizeof(buffer),
2809                                        "diff--gita/%.*sb/%.*s"
2810                                        "---a/%.*s"
2811                                        "+++b/%.*s",
2812                                        len1, p->one->path,
2813                                        len2, p->two->path,
2814                                        len1, p->one->path,
2815                                        len2, p->two->path);
2816                SHA1_Update(&ctx, buffer, len1);
2817
2818                xpp.flags = XDF_NEED_MINIMAL;
2819                xecfg.ctxlen = 3;
2820                xecfg.flags = XDL_EMIT_FUNCNAMES;
2821                ecb.outf = xdiff_outf;
2822                ecb.priv = &data;
2823                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
2824        }
2825
2826        SHA1_Final(sha1, &ctx);
2827        return 0;
2828}
2829
2830int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
2831{
2832        struct diff_queue_struct *q = &diff_queued_diff;
2833        int i;
2834        int result = diff_get_patch_id(options, sha1);
2835
2836        for (i = 0; i < q->nr; i++)
2837                diff_free_filepair(q->queue[i]);
2838
2839        free(q->queue);
2840        q->queue = NULL;
2841        q->nr = q->alloc = 0;
2842
2843        return result;
2844}
2845
2846static int is_summary_empty(const struct diff_queue_struct *q)
2847{
2848        int i;
2849
2850        for (i = 0; i < q->nr; i++) {
2851                const struct diff_filepair *p = q->queue[i];
2852
2853                switch (p->status) {
2854                case DIFF_STATUS_DELETED:
2855                case DIFF_STATUS_ADDED:
2856                case DIFF_STATUS_COPIED:
2857                case DIFF_STATUS_RENAMED:
2858                        return 0;
2859                default:
2860                        if (p->score)
2861                                return 0;
2862                        if (p->one->mode && p->two->mode &&
2863                            p->one->mode != p->two->mode)
2864                                return 0;
2865                        break;
2866                }
2867        }
2868        return 1;
2869}
2870
2871void diff_flush(struct diff_options *options)
2872{
2873        struct diff_queue_struct *q = &diff_queued_diff;
2874        int i, output_format = options->output_format;
2875        int separator = 0;
2876
2877        /*
2878         * Order: raw, stat, summary, patch
2879         * or:    name/name-status/checkdiff (other bits clear)
2880         */
2881        if (!q->nr)
2882                goto free_queue;
2883
2884        if (output_format & (DIFF_FORMAT_RAW |
2885                             DIFF_FORMAT_NAME |
2886                             DIFF_FORMAT_NAME_STATUS |
2887                             DIFF_FORMAT_CHECKDIFF)) {
2888                for (i = 0; i < q->nr; i++) {
2889                        struct diff_filepair *p = q->queue[i];
2890                        if (check_pair_status(p))
2891                                flush_one_pair(p, options);
2892                }
2893                separator++;
2894        }
2895
2896        if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) {
2897                struct diffstat_t diffstat;
2898
2899                memset(&diffstat, 0, sizeof(struct diffstat_t));
2900                diffstat.xm.consume = diffstat_consume;
2901                for (i = 0; i < q->nr; i++) {
2902                        struct diff_filepair *p = q->queue[i];
2903                        if (check_pair_status(p))
2904                                diff_flush_stat(p, options, &diffstat);
2905                }
2906                if (output_format & DIFF_FORMAT_NUMSTAT)
2907                        show_numstat(&diffstat, options);
2908                if (output_format & DIFF_FORMAT_DIFFSTAT)
2909                        show_stats(&diffstat, options);
2910                else if (output_format & DIFF_FORMAT_SHORTSTAT)
2911                        show_shortstats(&diffstat);
2912                separator++;
2913        }
2914
2915        if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
2916                for (i = 0; i < q->nr; i++)
2917                        diff_summary(q->queue[i]);
2918                separator++;
2919        }
2920
2921        if (output_format & DIFF_FORMAT_PATCH) {
2922                if (separator) {
2923                        if (options->stat_sep) {
2924                                /* attach patch instead of inline */
2925                                fputs(options->stat_sep, stdout);
2926                        } else {
2927                                putchar(options->line_termination);
2928                        }
2929                }
2930
2931                for (i = 0; i < q->nr; i++) {
2932                        struct diff_filepair *p = q->queue[i];
2933                        if (check_pair_status(p))
2934                                diff_flush_patch(p, options);
2935                }
2936        }
2937
2938        if (output_format & DIFF_FORMAT_CALLBACK)
2939                options->format_callback(q, options, options->format_callback_data);
2940
2941        for (i = 0; i < q->nr; i++)
2942                diff_free_filepair(q->queue[i]);
2943free_queue:
2944        free(q->queue);
2945        q->queue = NULL;
2946        q->nr = q->alloc = 0;
2947}
2948
2949static void diffcore_apply_filter(const char *filter)
2950{
2951        int i;
2952        struct diff_queue_struct *q = &diff_queued_diff;
2953        struct diff_queue_struct outq;
2954        outq.queue = NULL;
2955        outq.nr = outq.alloc = 0;
2956
2957        if (!filter)
2958                return;
2959
2960        if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
2961                int found;
2962                for (i = found = 0; !found && i < q->nr; i++) {
2963                        struct diff_filepair *p = q->queue[i];
2964                        if (((p->status == DIFF_STATUS_MODIFIED) &&
2965                             ((p->score &&
2966                               strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
2967                              (!p->score &&
2968                               strchr(filter, DIFF_STATUS_MODIFIED)))) ||
2969                            ((p->status != DIFF_STATUS_MODIFIED) &&
2970                             strchr(filter, p->status)))
2971                                found++;
2972                }
2973                if (found)
2974                        return;
2975
2976                /* otherwise we will clear the whole queue
2977                 * by copying the empty outq at the end of this
2978                 * function, but first clear the current entries
2979                 * in the queue.
2980                 */
2981                for (i = 0; i < q->nr; i++)
2982                        diff_free_filepair(q->queue[i]);
2983        }
2984        else {
2985                /* Only the matching ones */
2986                for (i = 0; i < q->nr; i++) {
2987                        struct diff_filepair *p = q->queue[i];
2988
2989                        if (((p->status == DIFF_STATUS_MODIFIED) &&
2990                             ((p->score &&
2991                               strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
2992                              (!p->score &&
2993                               strchr(filter, DIFF_STATUS_MODIFIED)))) ||
2994                            ((p->status != DIFF_STATUS_MODIFIED) &&
2995                             strchr(filter, p->status)))
2996                                diff_q(&outq, p);
2997                        else
2998                                diff_free_filepair(p);
2999                }
3000        }
3001        free(q->queue);
3002        *q = outq;
3003}
3004
3005void diffcore_std(struct diff_options *options)
3006{
3007        if (options->quiet)
3008                return;
3009        if (options->break_opt != -1)
3010                diffcore_break(options->break_opt);
3011        if (options->detect_rename)
3012                diffcore_rename(options);
3013        if (options->break_opt != -1)
3014                diffcore_merge_broken();
3015        if (options->pickaxe)
3016                diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
3017        if (options->orderfile)
3018                diffcore_order(options->orderfile);
3019        diff_resolve_rename_copy();
3020        diffcore_apply_filter(options->filter);
3021
3022        options->has_changes = !!diff_queued_diff.nr;
3023}
3024
3025
3026void diff_addremove(struct diff_options *options,
3027                    int addremove, unsigned mode,
3028                    const unsigned char *sha1,
3029                    const char *base, const char *path)
3030{
3031        char concatpath[PATH_MAX];
3032        struct diff_filespec *one, *two;
3033
3034        /* This may look odd, but it is a preparation for
3035         * feeding "there are unchanged files which should
3036         * not produce diffs, but when you are doing copy
3037         * detection you would need them, so here they are"
3038         * entries to the diff-core.  They will be prefixed
3039         * with something like '=' or '*' (I haven't decided
3040         * which but should not make any difference).
3041         * Feeding the same new and old to diff_change() 
3042         * also has the same effect.
3043         * Before the final output happens, they are pruned after
3044         * merged into rename/copy pairs as appropriate.
3045         */
3046        if (options->reverse_diff)
3047                addremove = (addremove == '+' ? '-' :
3048                             addremove == '-' ? '+' : addremove);
3049
3050        if (!path) path = "";
3051        sprintf(concatpath, "%s%s", base, path);
3052        one = alloc_filespec(concatpath);
3053        two = alloc_filespec(concatpath);
3054
3055        if (addremove != '+')
3056                fill_filespec(one, sha1, mode);
3057        if (addremove != '-')
3058                fill_filespec(two, sha1, mode);
3059
3060        diff_queue(&diff_queued_diff, one, two);
3061        options->has_changes = 1;
3062}
3063
3064void diff_change(struct diff_options *options,
3065                 unsigned old_mode, unsigned new_mode,
3066                 const unsigned char *old_sha1,
3067                 const unsigned char *new_sha1,
3068                 const char *base, const char *path) 
3069{
3070        char concatpath[PATH_MAX];
3071        struct diff_filespec *one, *two;
3072
3073        if (options->reverse_diff) {
3074                unsigned tmp;
3075                const unsigned char *tmp_c;
3076                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
3077                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
3078        }
3079        if (!path) path = "";
3080        sprintf(concatpath, "%s%s", base, path);
3081        one = alloc_filespec(concatpath);
3082        two = alloc_filespec(concatpath);
3083        fill_filespec(one, old_sha1, old_mode);
3084        fill_filespec(two, new_sha1, new_mode);
3085
3086        diff_queue(&diff_queued_diff, one, two);
3087        options->has_changes = 1;
3088}
3089
3090void diff_unmerge(struct diff_options *options,
3091                  const char *path,
3092                  unsigned mode, const unsigned char *sha1)
3093{
3094        struct diff_filespec *one, *two;
3095        one = alloc_filespec(path);
3096        two = alloc_filespec(path);
3097        fill_filespec(one, sha1, mode);
3098        diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1;
3099}