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