Code

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