Code

Merge branch 'jn/web' into next
[git.git] / diff.c
1 /*
2  * Copyright (C) 2005 Junio C Hamano
3  */
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <signal.h>
7 #include "cache.h"
8 #include "quote.h"
9 #include "diff.h"
10 #include "diffcore.h"
11 #include "delta.h"
12 #include "xdiff-interface.h"
14 static int use_size_cache;
16 int diff_rename_limit_default = -1;
18 int git_diff_config(const char *var, const char *value)
19 {
20         if (!strcmp(var, "diff.renamelimit")) {
21                 diff_rename_limit_default = git_config_int(var, value);
22                 return 0;
23         }
25         return git_default_config(var, value);
26 }
28 enum color_diff {
29         DIFF_PLAIN = 0,
30         DIFF_METAINFO = 1,
31         DIFF_FILE_OLD = 2,
32         DIFF_FILE_NEW = 3,
33 };
35 static const char *diff_colors[] = {
36         "\033[0;0m",
37         "\033[1;35m",
38         "\033[1;31m",
39         "\033[1;34m",
40 };
42 static char *quote_one(const char *str)
43 {
44         int needlen;
45         char *xp;
47         if (!str)
48                 return NULL;
49         needlen = quote_c_style(str, NULL, NULL, 0);
50         if (!needlen)
51                 return strdup(str);
52         xp = xmalloc(needlen + 1);
53         quote_c_style(str, xp, NULL, 0);
54         return xp;
55 }
57 static char *quote_two(const char *one, const char *two)
58 {
59         int need_one = quote_c_style(one, NULL, NULL, 1);
60         int need_two = quote_c_style(two, NULL, NULL, 1);
61         char *xp;
63         if (need_one + need_two) {
64                 if (!need_one) need_one = strlen(one);
65                 if (!need_two) need_one = strlen(two);
67                 xp = xmalloc(need_one + need_two + 3);
68                 xp[0] = '"';
69                 quote_c_style(one, xp + 1, NULL, 1);
70                 quote_c_style(two, xp + need_one + 1, NULL, 1);
71                 strcpy(xp + need_one + need_two + 1, "\"");
72                 return xp;
73         }
74         need_one = strlen(one);
75         need_two = strlen(two);
76         xp = xmalloc(need_one + need_two + 1);
77         strcpy(xp, one);
78         strcpy(xp + need_one, two);
79         return xp;
80 }
82 static const char *external_diff(void)
83 {
84         static const char *external_diff_cmd = NULL;
85         static int done_preparing = 0;
87         if (done_preparing)
88                 return external_diff_cmd;
89         external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
90         done_preparing = 1;
91         return external_diff_cmd;
92 }
94 #define TEMPFILE_PATH_LEN               50
96 static struct diff_tempfile {
97         const char *name; /* filename external diff should read from */
98         char hex[41];
99         char mode[10];
100         char tmp_path[TEMPFILE_PATH_LEN];
101 } diff_temp[2];
103 static int count_lines(const char *data, int size)
105         int count, ch, completely_empty = 1, nl_just_seen = 0;
106         count = 0;
107         while (0 < size--) {
108                 ch = *data++;
109                 if (ch == '\n') {
110                         count++;
111                         nl_just_seen = 1;
112                         completely_empty = 0;
113                 }
114                 else {
115                         nl_just_seen = 0;
116                         completely_empty = 0;
117                 }
118         }
119         if (completely_empty)
120                 return 0;
121         if (!nl_just_seen)
122                 count++; /* no trailing newline */
123         return count;
126 static void print_line_count(int count)
128         switch (count) {
129         case 0:
130                 printf("0,0");
131                 break;
132         case 1:
133                 printf("1");
134                 break;
135         default:
136                 printf("1,%d", count);
137                 break;
138         }
141 static void copy_file(int prefix, const char *data, int size)
143         int ch, nl_just_seen = 1;
144         while (0 < size--) {
145                 ch = *data++;
146                 if (nl_just_seen)
147                         putchar(prefix);
148                 putchar(ch);
149                 if (ch == '\n')
150                         nl_just_seen = 1;
151                 else
152                         nl_just_seen = 0;
153         }
154         if (!nl_just_seen)
155                 printf("\n\\ No newline at end of file\n");
158 static void emit_rewrite_diff(const char *name_a,
159                               const char *name_b,
160                               struct diff_filespec *one,
161                               struct diff_filespec *two)
163         int lc_a, lc_b;
164         diff_populate_filespec(one, 0);
165         diff_populate_filespec(two, 0);
166         lc_a = count_lines(one->data, one->size);
167         lc_b = count_lines(two->data, two->size);
168         printf("--- %s\n+++ %s\n@@ -", name_a, name_b);
169         print_line_count(lc_a);
170         printf(" +");
171         print_line_count(lc_b);
172         printf(" @@\n");
173         if (lc_a)
174                 copy_file('-', one->data, one->size);
175         if (lc_b)
176                 copy_file('+', two->data, two->size);
179 static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
181         if (!DIFF_FILE_VALID(one)) {
182                 mf->ptr = ""; /* does not matter */
183                 mf->size = 0;
184                 return 0;
185         }
186         else if (diff_populate_filespec(one, 0))
187                 return -1;
188         mf->ptr = one->data;
189         mf->size = one->size;
190         return 0;
193 struct emit_callback {
194         struct xdiff_emit_state xm;
195         int nparents, color_diff;
196         const char **label_path;
197 };
199 static inline void color_diff(int diff_use_color, enum color_diff ix)
201         if (diff_use_color)
202                 fputs(diff_colors[ix], stdout);
205 static void fn_out_consume(void *priv, char *line, unsigned long len)
207         int i;
208         struct emit_callback *ecbdata = priv;
210         if (ecbdata->label_path[0]) {
211                 color_diff(ecbdata->color_diff, DIFF_METAINFO);
212                 printf("--- %s\n", ecbdata->label_path[0]);
213                 color_diff(ecbdata->color_diff, DIFF_METAINFO);
214                 printf("+++ %s\n", ecbdata->label_path[1]);
215                 ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
216         }
218         /* This is not really necessary for now because
219          * this codepath only deals with two-way diffs.
220          */
221         for (i = 0; i < len && line[i] == '@'; i++)
222                 ;
223         if (2 <= i && i < len && line[i] == ' ') {
224                 ecbdata->nparents = i - 1;
225                 color_diff(ecbdata->color_diff, DIFF_METAINFO);
226         }
227         else if (len < ecbdata->nparents)
228                 color_diff(ecbdata->color_diff, DIFF_PLAIN);
229         else {
230                 int nparents = ecbdata->nparents;
231                 int color = DIFF_PLAIN;
232                 for (i = 0; i < nparents && len; i++) {
233                         if (line[i] == '-')
234                                 color = DIFF_FILE_OLD;
235                         else if (line[i] == '+')
236                                 color = DIFF_FILE_NEW;
237                 }
238                 color_diff(ecbdata->color_diff, color);
239         }
240         fwrite(line, len, 1, stdout);
241         color_diff(ecbdata->color_diff, DIFF_PLAIN);
244 static char *pprint_rename(const char *a, const char *b)
246         const char *old = a;
247         const char *new = b;
248         char *name = NULL;
249         int pfx_length, sfx_length;
250         int len_a = strlen(a);
251         int len_b = strlen(b);
253         /* Find common prefix */
254         pfx_length = 0;
255         while (*old && *new && *old == *new) {
256                 if (*old == '/')
257                         pfx_length = old - a + 1;
258                 old++;
259                 new++;
260         }
262         /* Find common suffix */
263         old = a + len_a;
264         new = b + len_b;
265         sfx_length = 0;
266         while (a <= old && b <= new && *old == *new) {
267                 if (*old == '/')
268                         sfx_length = len_a - (old - a);
269                 old--;
270                 new--;
271         }
273         /*
274          * pfx{mid-a => mid-b}sfx
275          * {pfx-a => pfx-b}sfx
276          * pfx{sfx-a => sfx-b}
277          * name-a => name-b
278          */
279         if (pfx_length + sfx_length) {
280                 int a_midlen = len_a - pfx_length - sfx_length;
281                 int b_midlen = len_b - pfx_length - sfx_length;
282                 if (a_midlen < 0) a_midlen = 0;
283                 if (b_midlen < 0) b_midlen = 0;
285                 name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7);
286                 sprintf(name, "%.*s{%.*s => %.*s}%s",
287                         pfx_length, a,
288                         a_midlen, a + pfx_length,
289                         b_midlen, b + pfx_length,
290                         a + len_a - sfx_length);
291         }
292         else {
293                 name = xmalloc(len_a + len_b + 5);
294                 sprintf(name, "%s => %s", a, b);
295         }
296         return name;
299 struct diffstat_t {
300         struct xdiff_emit_state xm;
302         int nr;
303         int alloc;
304         struct diffstat_file {
305                 char *name;
306                 unsigned is_unmerged:1;
307                 unsigned is_binary:1;
308                 unsigned is_renamed:1;
309                 unsigned int added, deleted;
310         } **files;
311 };
313 static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
314                                           const char *name_a,
315                                           const char *name_b)
317         struct diffstat_file *x;
318         x = xcalloc(sizeof (*x), 1);
319         if (diffstat->nr == diffstat->alloc) {
320                 diffstat->alloc = alloc_nr(diffstat->alloc);
321                 diffstat->files = xrealloc(diffstat->files,
322                                 diffstat->alloc * sizeof(x));
323         }
324         diffstat->files[diffstat->nr++] = x;
325         if (name_b) {
326                 x->name = pprint_rename(name_a, name_b);
327                 x->is_renamed = 1;
328         }
329         else
330                 x->name = strdup(name_a);
331         return x;
334 static void diffstat_consume(void *priv, char *line, unsigned long len)
336         struct diffstat_t *diffstat = priv;
337         struct diffstat_file *x = diffstat->files[diffstat->nr - 1];
339         if (line[0] == '+')
340                 x->added++;
341         else if (line[0] == '-')
342                 x->deleted++;
345 static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
346 static const char minuses[]= "----------------------------------------------------------------------";
347 const char mime_boundary_leader[] = "------------";
349 static void show_stats(struct diffstat_t* data)
351         int i, len, add, del, total, adds = 0, dels = 0;
352         int max, max_change = 0, max_len = 0;
353         int total_files = data->nr;
355         if (data->nr == 0)
356                 return;
358         for (i = 0; i < data->nr; i++) {
359                 struct diffstat_file *file = data->files[i];
361                 len = strlen(file->name);
362                 if (max_len < len)
363                         max_len = len;
365                 if (file->is_binary || file->is_unmerged)
366                         continue;
367                 if (max_change < file->added + file->deleted)
368                         max_change = file->added + file->deleted;
369         }
371         for (i = 0; i < data->nr; i++) {
372                 char *prefix = "";
373                 char *name = data->files[i]->name;
374                 int added = data->files[i]->added;
375                 int deleted = data->files[i]->deleted;
377                 if (0 < (len = quote_c_style(name, NULL, NULL, 0))) {
378                         char *qname = xmalloc(len + 1);
379                         quote_c_style(name, qname, NULL, 0);
380                         free(name);
381                         data->files[i]->name = name = qname;
382                 }
384                 /*
385                  * "scale" the filename
386                  */
387                 len = strlen(name);
388                 max = max_len;
389                 if (max > 50)
390                         max = 50;
391                 if (len > max) {
392                         char *slash;
393                         prefix = "...";
394                         max -= 3;
395                         name += len - max;
396                         slash = strchr(name, '/');
397                         if (slash)
398                                 name = slash;
399                 }
400                 len = max;
402                 /*
403                  * scale the add/delete
404                  */
405                 max = max_change;
406                 if (max + len > 70)
407                         max = 70 - len;
409                 if (data->files[i]->is_binary) {
410                         printf(" %s%-*s |  Bin\n", prefix, len, name);
411                         goto free_diffstat_file;
412                 }
413                 else if (data->files[i]->is_unmerged) {
414                         printf(" %s%-*s |  Unmerged\n", prefix, len, name);
415                         goto free_diffstat_file;
416                 }
417                 else if (!data->files[i]->is_renamed &&
418                          (added + deleted == 0)) {
419                         total_files--;
420                         goto free_diffstat_file;
421                 }
423                 add = added;
424                 del = deleted;
425                 total = add + del;
426                 adds += add;
427                 dels += del;
429                 if (max_change > 0) {
430                         total = (total * max + max_change / 2) / max_change;
431                         add = (add * max + max_change / 2) / max_change;
432                         del = total - add;
433                 }
434                 printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
435                                 len, name, added + deleted,
436                                 add, pluses, del, minuses);
437         free_diffstat_file:
438                 free(data->files[i]->name);
439                 free(data->files[i]);
440         }
441         free(data->files);
442         printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
443                         total_files, adds, dels);
446 struct checkdiff_t {
447         struct xdiff_emit_state xm;
448         const char *filename;
449         int lineno;
450 };
452 static void checkdiff_consume(void *priv, char *line, unsigned long len)
454         struct checkdiff_t *data = priv;
456         if (line[0] == '+') {
457                 int i, spaces = 0;
459                 data->lineno++;
461                 /* check space before tab */
462                 for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
463                         if (line[i] == ' ')
464                                 spaces++;
465                 if (line[i - 1] == '\t' && spaces)
466                         printf("%s:%d: space before tab:%.*s\n",
467                                 data->filename, data->lineno, (int)len, line);
469                 /* check white space at line end */
470                 if (line[len - 1] == '\n')
471                         len--;
472                 if (isspace(line[len - 1]))
473                         printf("%s:%d: white space at end: %.*s\n",
474                                 data->filename, data->lineno, (int)len, line);
475         } else if (line[0] == ' ')
476                 data->lineno++;
477         else if (line[0] == '@') {
478                 char *plus = strchr(line, '+');
479                 if (plus)
480                         data->lineno = strtol(plus, NULL, 10);
481                 else
482                         die("invalid diff");
483         }
486 static unsigned char *deflate_it(char *data,
487                                  unsigned long size,
488                                  unsigned long *result_size)
490         int bound;
491         unsigned char *deflated;
492         z_stream stream;
494         memset(&stream, 0, sizeof(stream));
495         deflateInit(&stream, Z_BEST_COMPRESSION);
496         bound = deflateBound(&stream, size);
497         deflated = xmalloc(bound);
498         stream.next_out = deflated;
499         stream.avail_out = bound;
501         stream.next_in = (unsigned char *)data;
502         stream.avail_in = size;
503         while (deflate(&stream, Z_FINISH) == Z_OK)
504                 ; /* nothing */
505         deflateEnd(&stream);
506         *result_size = stream.total_out;
507         return deflated;
510 static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
512         void *cp;
513         void *delta;
514         void *deflated;
515         void *data;
516         unsigned long orig_size;
517         unsigned long delta_size;
518         unsigned long deflate_size;
519         unsigned long data_size;
521         printf("GIT binary patch\n");
522         /* We could do deflated delta, or we could do just deflated two,
523          * whichever is smaller.
524          */
525         delta = NULL;
526         deflated = deflate_it(two->ptr, two->size, &deflate_size);
527         if (one->size && two->size) {
528                 delta = diff_delta(one->ptr, one->size,
529                                    two->ptr, two->size,
530                                    &delta_size, deflate_size);
531                 if (delta) {
532                         void *to_free = delta;
533                         orig_size = delta_size;
534                         delta = deflate_it(delta, delta_size, &delta_size);
535                         free(to_free);
536                 }
537         }
539         if (delta && delta_size < deflate_size) {
540                 printf("delta %lu\n", orig_size);
541                 free(deflated);
542                 data = delta;
543                 data_size = delta_size;
544         }
545         else {
546                 printf("literal %lu\n", two->size);
547                 free(delta);
548                 data = deflated;
549                 data_size = deflate_size;
550         }
552         /* emit data encoded in base85 */
553         cp = data;
554         while (data_size) {
555                 int bytes = (52 < data_size) ? 52 : data_size;
556                 char line[70];
557                 data_size -= bytes;
558                 if (bytes <= 26)
559                         line[0] = bytes + 'A' - 1;
560                 else
561                         line[0] = bytes - 26 + 'a' - 1;
562                 encode_85(line + 1, cp, bytes);
563                 cp += bytes;
564                 puts(line);
565         }
566         printf("\n");
567         free(data);
570 #define FIRST_FEW_BYTES 8000
571 static int mmfile_is_binary(mmfile_t *mf)
573         long sz = mf->size;
574         if (FIRST_FEW_BYTES < sz)
575                 sz = FIRST_FEW_BYTES;
576         if (memchr(mf->ptr, 0, sz))
577                 return 1;
578         return 0;
581 static void builtin_diff(const char *name_a,
582                          const char *name_b,
583                          struct diff_filespec *one,
584                          struct diff_filespec *two,
585                          const char *xfrm_msg,
586                          struct diff_options *o,
587                          int complete_rewrite)
589         mmfile_t mf1, mf2;
590         const char *lbl[2];
591         char *a_one, *b_two;
593         a_one = quote_two("a/", name_a);
594         b_two = quote_two("b/", name_b);
595         lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
596         lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
597         color_diff(o->color_diff, DIFF_METAINFO);
598         printf("diff --git %s %s\n", a_one, b_two);
599         if (lbl[0][0] == '/') {
600                 /* /dev/null */
601                 color_diff(o->color_diff, DIFF_METAINFO);
602                 printf("new file mode %06o\n", two->mode);
603                 if (xfrm_msg && xfrm_msg[0]) {
604                         color_diff(o->color_diff, DIFF_METAINFO);
605                         puts(xfrm_msg);
606                 }
607         }
608         else if (lbl[1][0] == '/') {
609                 printf("deleted file mode %06o\n", one->mode);
610                 if (xfrm_msg && xfrm_msg[0]) {
611                         color_diff(o->color_diff, DIFF_METAINFO);
612                         puts(xfrm_msg);
613                 }
614         }
615         else {
616                 if (one->mode != two->mode) {
617                         color_diff(o->color_diff, DIFF_METAINFO);
618                         printf("old mode %06o\n", one->mode);
619                         color_diff(o->color_diff, DIFF_METAINFO);
620                         printf("new mode %06o\n", two->mode);
621                 }
622                 if (xfrm_msg && xfrm_msg[0]) {
623                         color_diff(o->color_diff, DIFF_METAINFO);
624                         puts(xfrm_msg);
625                 }
626                 /*
627                  * we do not run diff between different kind
628                  * of objects.
629                  */
630                 if ((one->mode ^ two->mode) & S_IFMT)
631                         goto free_ab_and_return;
632                 if (complete_rewrite) {
633                         color_diff(o->color_diff, DIFF_PLAIN);
634                         emit_rewrite_diff(name_a, name_b, one, two);
635                         goto free_ab_and_return;
636                 }
637         }
639         if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
640                 die("unable to read files to diff");
642         if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) {
643                 /* Quite common confusing case */
644                 if (mf1.size == mf2.size &&
645                     !memcmp(mf1.ptr, mf2.ptr, mf1.size))
646                         goto free_ab_and_return;
647                 if (o->binary)
648                         emit_binary_diff(&mf1, &mf2);
649                 else
650                         printf("Binary files %s and %s differ\n",
651                                lbl[0], lbl[1]);
652         }
653         else {
654                 /* Crazy xdl interfaces.. */
655                 const char *diffopts = getenv("GIT_DIFF_OPTS");
656                 xpparam_t xpp;
657                 xdemitconf_t xecfg;
658                 xdemitcb_t ecb;
659                 struct emit_callback ecbdata;
661                 memset(&ecbdata, 0, sizeof(ecbdata));
662                 ecbdata.label_path = lbl;
663                 ecbdata.color_diff = o->color_diff;
664                 xpp.flags = XDF_NEED_MINIMAL;
665                 xecfg.ctxlen = o->context;
666                 xecfg.flags = XDL_EMIT_FUNCNAMES;
667                 if (!diffopts)
668                         ;
669                 else if (!strncmp(diffopts, "--unified=", 10))
670                         xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
671                 else if (!strncmp(diffopts, "-u", 2))
672                         xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
673                 ecb.outf = xdiff_outf;
674                 ecb.priv = &ecbdata;
675                 ecbdata.xm.consume = fn_out_consume;
676                 xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
677         }
679  free_ab_and_return:
680         free(a_one);
681         free(b_two);
682         return;
685 static void builtin_diffstat(const char *name_a, const char *name_b,
686                              struct diff_filespec *one,
687                              struct diff_filespec *two,
688                              struct diffstat_t *diffstat,
689                              int complete_rewrite)
691         mmfile_t mf1, mf2;
692         struct diffstat_file *data;
694         data = diffstat_add(diffstat, name_a, name_b);
696         if (!one || !two) {
697                 data->is_unmerged = 1;
698                 return;
699         }
700         if (complete_rewrite) {
701                 diff_populate_filespec(one, 0);
702                 diff_populate_filespec(two, 0);
703                 data->deleted = count_lines(one->data, one->size);
704                 data->added = count_lines(two->data, two->size);
705                 return;
706         }
707         if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
708                 die("unable to read files to diff");
710         if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))
711                 data->is_binary = 1;
712         else {
713                 /* Crazy xdl interfaces.. */
714                 xpparam_t xpp;
715                 xdemitconf_t xecfg;
716                 xdemitcb_t ecb;
718                 xpp.flags = XDF_NEED_MINIMAL;
719                 xecfg.ctxlen = 0;
720                 xecfg.flags = 0;
721                 ecb.outf = xdiff_outf;
722                 ecb.priv = diffstat;
723                 xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
724         }
727 static void builtin_checkdiff(const char *name_a, const char *name_b,
728                              struct diff_filespec *one,
729                              struct diff_filespec *two)
731         mmfile_t mf1, mf2;
732         struct checkdiff_t data;
734         if (!two)
735                 return;
737         memset(&data, 0, sizeof(data));
738         data.xm.consume = checkdiff_consume;
739         data.filename = name_b ? name_b : name_a;
740         data.lineno = 0;
742         if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
743                 die("unable to read files to diff");
745         if (mmfile_is_binary(&mf2))
746                 return;
747         else {
748                 /* Crazy xdl interfaces.. */
749                 xpparam_t xpp;
750                 xdemitconf_t xecfg;
751                 xdemitcb_t ecb;
753                 xpp.flags = XDF_NEED_MINIMAL;
754                 xecfg.ctxlen = 0;
755                 xecfg.flags = 0;
756                 ecb.outf = xdiff_outf;
757                 ecb.priv = &data;
758                 xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
759         }
762 struct diff_filespec *alloc_filespec(const char *path)
764         int namelen = strlen(path);
765         struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
767         memset(spec, 0, sizeof(*spec));
768         spec->path = (char *)(spec + 1);
769         memcpy(spec->path, path, namelen+1);
770         return spec;
773 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
774                    unsigned short mode)
776         if (mode) {
777                 spec->mode = canon_mode(mode);
778                 memcpy(spec->sha1, sha1, 20);
779                 spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
780         }
783 /*
784  * Given a name and sha1 pair, if the dircache tells us the file in
785  * the work tree has that object contents, return true, so that
786  * prepare_temp_file() does not have to inflate and extract.
787  */
788 static int work_tree_matches(const char *name, const unsigned char *sha1)
790         struct cache_entry *ce;
791         struct stat st;
792         int pos, len;
794         /* We do not read the cache ourselves here, because the
795          * benchmark with my previous version that always reads cache
796          * shows that it makes things worse for diff-tree comparing
797          * two linux-2.6 kernel trees in an already checked out work
798          * tree.  This is because most diff-tree comparisons deal with
799          * only a small number of files, while reading the cache is
800          * expensive for a large project, and its cost outweighs the
801          * savings we get by not inflating the object to a temporary
802          * file.  Practically, this code only helps when we are used
803          * by diff-cache --cached, which does read the cache before
804          * calling us.
805          */
806         if (!active_cache)
807                 return 0;
809         len = strlen(name);
810         pos = cache_name_pos(name, len);
811         if (pos < 0)
812                 return 0;
813         ce = active_cache[pos];
814         if ((lstat(name, &st) < 0) ||
815             !S_ISREG(st.st_mode) || /* careful! */
816             ce_match_stat(ce, &st, 0) ||
817             memcmp(sha1, ce->sha1, 20))
818                 return 0;
819         /* we return 1 only when we can stat, it is a regular file,
820          * stat information matches, and sha1 recorded in the cache
821          * matches.  I.e. we know the file in the work tree really is
822          * the same as the <name, sha1> pair.
823          */
824         return 1;
827 static struct sha1_size_cache {
828         unsigned char sha1[20];
829         unsigned long size;
830 } **sha1_size_cache;
831 static int sha1_size_cache_nr, sha1_size_cache_alloc;
833 static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
834                                                  int find_only,
835                                                  unsigned long size)
837         int first, last;
838         struct sha1_size_cache *e;
840         first = 0;
841         last = sha1_size_cache_nr;
842         while (last > first) {
843                 int cmp, next = (last + first) >> 1;
844                 e = sha1_size_cache[next];
845                 cmp = memcmp(e->sha1, sha1, 20);
846                 if (!cmp)
847                         return e;
848                 if (cmp < 0) {
849                         last = next;
850                         continue;
851                 }
852                 first = next+1;
853         }
854         /* not found */
855         if (find_only)
856                 return NULL;
857         /* insert to make it at "first" */
858         if (sha1_size_cache_alloc <= sha1_size_cache_nr) {
859                 sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc);
860                 sha1_size_cache = xrealloc(sha1_size_cache,
861                                            sha1_size_cache_alloc *
862                                            sizeof(*sha1_size_cache));
863         }
864         sha1_size_cache_nr++;
865         if (first < sha1_size_cache_nr)
866                 memmove(sha1_size_cache + first + 1, sha1_size_cache + first,
867                         (sha1_size_cache_nr - first - 1) *
868                         sizeof(*sha1_size_cache));
869         e = xmalloc(sizeof(struct sha1_size_cache));
870         sha1_size_cache[first] = e;
871         memcpy(e->sha1, sha1, 20);
872         e->size = size;
873         return e;
876 /*
877  * While doing rename detection and pickaxe operation, we may need to
878  * grab the data for the blob (or file) for our own in-core comparison.
879  * diff_filespec has data and size fields for this purpose.
880  */
881 int diff_populate_filespec(struct diff_filespec *s, int size_only)
883         int err = 0;
884         if (!DIFF_FILE_VALID(s))
885                 die("internal error: asking to populate invalid file.");
886         if (S_ISDIR(s->mode))
887                 return -1;
889         if (!use_size_cache)
890                 size_only = 0;
892         if (s->data)
893                 return err;
894         if (!s->sha1_valid ||
895             work_tree_matches(s->path, s->sha1)) {
896                 struct stat st;
897                 int fd;
898                 if (lstat(s->path, &st) < 0) {
899                         if (errno == ENOENT) {
900                         err_empty:
901                                 err = -1;
902                         empty:
903                                 s->data = "";
904                                 s->size = 0;
905                                 return err;
906                         }
907                 }
908                 s->size = st.st_size;
909                 if (!s->size)
910                         goto empty;
911                 if (size_only)
912                         return 0;
913                 if (S_ISLNK(st.st_mode)) {
914                         int ret;
915                         s->data = xmalloc(s->size);
916                         s->should_free = 1;
917                         ret = readlink(s->path, s->data, s->size);
918                         if (ret < 0) {
919                                 free(s->data);
920                                 goto err_empty;
921                         }
922                         return 0;
923                 }
924                 fd = open(s->path, O_RDONLY);
925                 if (fd < 0)
926                         goto err_empty;
927                 s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
928                 close(fd);
929                 if (s->data == MAP_FAILED)
930                         goto err_empty;
931                 s->should_munmap = 1;
932         }
933         else {
934                 char type[20];
935                 struct sha1_size_cache *e;
937                 if (size_only) {
938                         e = locate_size_cache(s->sha1, 1, 0);
939                         if (e) {
940                                 s->size = e->size;
941                                 return 0;
942                         }
943                         if (!sha1_object_info(s->sha1, type, &s->size))
944                                 locate_size_cache(s->sha1, 0, s->size);
945                 }
946                 else {
947                         s->data = read_sha1_file(s->sha1, type, &s->size);
948                         s->should_free = 1;
949                 }
950         }
951         return 0;
954 void diff_free_filespec_data(struct diff_filespec *s)
956         if (s->should_free)
957                 free(s->data);
958         else if (s->should_munmap)
959                 munmap(s->data, s->size);
960         s->should_free = s->should_munmap = 0;
961         s->data = NULL;
962         free(s->cnt_data);
963         s->cnt_data = NULL;
966 static void prep_temp_blob(struct diff_tempfile *temp,
967                            void *blob,
968                            unsigned long size,
969                            const unsigned char *sha1,
970                            int mode)
972         int fd;
974         fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
975         if (fd < 0)
976                 die("unable to create temp-file");
977         if (write(fd, blob, size) != size)
978                 die("unable to write temp-file");
979         close(fd);
980         temp->name = temp->tmp_path;
981         strcpy(temp->hex, sha1_to_hex(sha1));
982         temp->hex[40] = 0;
983         sprintf(temp->mode, "%06o", mode);
986 static void prepare_temp_file(const char *name,
987                               struct diff_tempfile *temp,
988                               struct diff_filespec *one)
990         if (!DIFF_FILE_VALID(one)) {
991         not_a_valid_file:
992                 /* A '-' entry produces this for file-2, and
993                  * a '+' entry produces this for file-1.
994                  */
995                 temp->name = "/dev/null";
996                 strcpy(temp->hex, ".");
997                 strcpy(temp->mode, ".");
998                 return;
999         }
1001         if (!one->sha1_valid ||
1002             work_tree_matches(name, one->sha1)) {
1003                 struct stat st;
1004                 if (lstat(name, &st) < 0) {
1005                         if (errno == ENOENT)
1006                                 goto not_a_valid_file;
1007                         die("stat(%s): %s", name, strerror(errno));
1008                 }
1009                 if (S_ISLNK(st.st_mode)) {
1010                         int ret;
1011                         char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
1012                         if (sizeof(buf) <= st.st_size)
1013                                 die("symlink too long: %s", name);
1014                         ret = readlink(name, buf, st.st_size);
1015                         if (ret < 0)
1016                                 die("readlink(%s)", name);
1017                         prep_temp_blob(temp, buf, st.st_size,
1018                                        (one->sha1_valid ?
1019                                         one->sha1 : null_sha1),
1020                                        (one->sha1_valid ?
1021                                         one->mode : S_IFLNK));
1022                 }
1023                 else {
1024                         /* we can borrow from the file in the work tree */
1025                         temp->name = name;
1026                         if (!one->sha1_valid)
1027                                 strcpy(temp->hex, sha1_to_hex(null_sha1));
1028                         else
1029                                 strcpy(temp->hex, sha1_to_hex(one->sha1));
1030                         /* Even though we may sometimes borrow the
1031                          * contents from the work tree, we always want
1032                          * one->mode.  mode is trustworthy even when
1033                          * !(one->sha1_valid), as long as
1034                          * DIFF_FILE_VALID(one).
1035                          */
1036                         sprintf(temp->mode, "%06o", one->mode);
1037                 }
1038                 return;
1039         }
1040         else {
1041                 if (diff_populate_filespec(one, 0))
1042                         die("cannot read data blob for %s", one->path);
1043                 prep_temp_blob(temp, one->data, one->size,
1044                                one->sha1, one->mode);
1045         }
1048 static void remove_tempfile(void)
1050         int i;
1052         for (i = 0; i < 2; i++)
1053                 if (diff_temp[i].name == diff_temp[i].tmp_path) {
1054                         unlink(diff_temp[i].name);
1055                         diff_temp[i].name = NULL;
1056                 }
1059 static void remove_tempfile_on_signal(int signo)
1061         remove_tempfile();
1062         signal(SIGINT, SIG_DFL);
1063         raise(signo);
1066 static int spawn_prog(const char *pgm, const char **arg)
1068         pid_t pid;
1069         int status;
1071         fflush(NULL);
1072         pid = fork();
1073         if (pid < 0)
1074                 die("unable to fork");
1075         if (!pid) {
1076                 execvp(pgm, (char *const*) arg);
1077                 exit(255);
1078         }
1080         while (waitpid(pid, &status, 0) < 0) {
1081                 if (errno == EINTR)
1082                         continue;
1083                 return -1;
1084         }
1086         /* Earlier we did not check the exit status because
1087          * diff exits non-zero if files are different, and
1088          * we are not interested in knowing that.  It was a
1089          * mistake which made it harder to quit a diff-*
1090          * session that uses the git-apply-patch-script as
1091          * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
1092          * should also exit non-zero only when it wants to
1093          * abort the entire diff-* session.
1094          */
1095         if (WIFEXITED(status) && !WEXITSTATUS(status))
1096                 return 0;
1097         return -1;
1100 /* An external diff command takes:
1101  *
1102  * diff-cmd name infile1 infile1-sha1 infile1-mode \
1103  *               infile2 infile2-sha1 infile2-mode [ rename-to ]
1104  *
1105  */
1106 static void run_external_diff(const char *pgm,
1107                               const char *name,
1108                               const char *other,
1109                               struct diff_filespec *one,
1110                               struct diff_filespec *two,
1111                               const char *xfrm_msg,
1112                               int complete_rewrite)
1114         const char *spawn_arg[10];
1115         struct diff_tempfile *temp = diff_temp;
1116         int retval;
1117         static int atexit_asked = 0;
1118         const char *othername;
1119         const char **arg = &spawn_arg[0];
1121         othername = (other? other : name);
1122         if (one && two) {
1123                 prepare_temp_file(name, &temp[0], one);
1124                 prepare_temp_file(othername, &temp[1], two);
1125                 if (! atexit_asked &&
1126                     (temp[0].name == temp[0].tmp_path ||
1127                      temp[1].name == temp[1].tmp_path)) {
1128                         atexit_asked = 1;
1129                         atexit(remove_tempfile);
1130                 }
1131                 signal(SIGINT, remove_tempfile_on_signal);
1132         }
1134         if (one && two) {
1135                 *arg++ = pgm;
1136                 *arg++ = name;
1137                 *arg++ = temp[0].name;
1138                 *arg++ = temp[0].hex;
1139                 *arg++ = temp[0].mode;
1140                 *arg++ = temp[1].name;
1141                 *arg++ = temp[1].hex;
1142                 *arg++ = temp[1].mode;
1143                 if (other) {
1144                         *arg++ = other;
1145                         *arg++ = xfrm_msg;
1146                 }
1147         } else {
1148                 *arg++ = pgm;
1149                 *arg++ = name;
1150         }
1151         *arg = NULL;
1152         retval = spawn_prog(pgm, spawn_arg);
1153         remove_tempfile();
1154         if (retval) {
1155                 fprintf(stderr, "external diff died, stopping at %s.\n", name);
1156                 exit(1);
1157         }
1160 static void run_diff_cmd(const char *pgm,
1161                          const char *name,
1162                          const char *other,
1163                          struct diff_filespec *one,
1164                          struct diff_filespec *two,
1165                          const char *xfrm_msg,
1166                          struct diff_options *o,
1167                          int complete_rewrite)
1169         if (pgm) {
1170                 run_external_diff(pgm, name, other, one, two, xfrm_msg,
1171                                   complete_rewrite);
1172                 return;
1173         }
1174         if (one && two)
1175                 builtin_diff(name, other ? other : name,
1176                              one, two, xfrm_msg, o, complete_rewrite);
1177         else
1178                 printf("* Unmerged path %s\n", name);
1181 static void diff_fill_sha1_info(struct diff_filespec *one)
1183         if (DIFF_FILE_VALID(one)) {
1184                 if (!one->sha1_valid) {
1185                         struct stat st;
1186                         if (lstat(one->path, &st) < 0)
1187                                 die("stat %s", one->path);
1188                         if (index_path(one->sha1, one->path, &st, 0))
1189                                 die("cannot hash %s\n", one->path);
1190                 }
1191         }
1192         else
1193                 memset(one->sha1, 0, 20);
1196 static void run_diff(struct diff_filepair *p, struct diff_options *o)
1198         const char *pgm = external_diff();
1199         char msg[PATH_MAX*2+300], *xfrm_msg;
1200         struct diff_filespec *one;
1201         struct diff_filespec *two;
1202         const char *name;
1203         const char *other;
1204         char *name_munged, *other_munged;
1205         int complete_rewrite = 0;
1206         int len;
1208         if (DIFF_PAIR_UNMERGED(p)) {
1209                 /* unmerged */
1210                 run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
1211                 return;
1212         }
1214         name = p->one->path;
1215         other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1216         name_munged = quote_one(name);
1217         other_munged = quote_one(other);
1218         one = p->one; two = p->two;
1220         diff_fill_sha1_info(one);
1221         diff_fill_sha1_info(two);
1223         len = 0;
1224         switch (p->status) {
1225         case DIFF_STATUS_COPIED:
1226                 len += snprintf(msg + len, sizeof(msg) - len,
1227                                 "similarity index %d%%\n"
1228                                 "copy from %s\n"
1229                                 "copy to %s\n",
1230                                 (int)(0.5 + p->score * 100.0/MAX_SCORE),
1231                                 name_munged, other_munged);
1232                 break;
1233         case DIFF_STATUS_RENAMED:
1234                 len += snprintf(msg + len, sizeof(msg) - len,
1235                                 "similarity index %d%%\n"
1236                                 "rename from %s\n"
1237                                 "rename to %s\n",
1238                                 (int)(0.5 + p->score * 100.0/MAX_SCORE),
1239                                 name_munged, other_munged);
1240                 break;
1241         case DIFF_STATUS_MODIFIED:
1242                 if (p->score) {
1243                         len += snprintf(msg + len, sizeof(msg) - len,
1244                                         "dissimilarity index %d%%\n",
1245                                         (int)(0.5 + p->score *
1246                                               100.0/MAX_SCORE));
1247                         complete_rewrite = 1;
1248                         break;
1249                 }
1250                 /* fallthru */
1251         default:
1252                 /* nothing */
1253                 ;
1254         }
1256         if (memcmp(one->sha1, two->sha1, 20)) {
1257                 int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
1259                 len += snprintf(msg + len, sizeof(msg) - len,
1260                                 "index %.*s..%.*s",
1261                                 abbrev, sha1_to_hex(one->sha1),
1262                                 abbrev, sha1_to_hex(two->sha1));
1263                 if (one->mode == two->mode)
1264                         len += snprintf(msg + len, sizeof(msg) - len,
1265                                         " %06o", one->mode);
1266                 len += snprintf(msg + len, sizeof(msg) - len, "\n");
1267         }
1269         if (len)
1270                 msg[--len] = 0;
1271         xfrm_msg = len ? msg : NULL;
1273         if (!pgm &&
1274             DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
1275             (S_IFMT & one->mode) != (S_IFMT & two->mode)) {
1276                 /* a filepair that changes between file and symlink
1277                  * needs to be split into deletion and creation.
1278                  */
1279                 struct diff_filespec *null = alloc_filespec(two->path);
1280                 run_diff_cmd(NULL, name, other, one, null, xfrm_msg, o, 0);
1281                 free(null);
1282                 null = alloc_filespec(one->path);
1283                 run_diff_cmd(NULL, name, other, null, two, xfrm_msg, o, 0);
1284                 free(null);
1285         }
1286         else
1287                 run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
1288                              complete_rewrite);
1290         free(name_munged);
1291         free(other_munged);
1294 static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
1295                          struct diffstat_t *diffstat)
1297         const char *name;
1298         const char *other;
1299         int complete_rewrite = 0;
1301         if (DIFF_PAIR_UNMERGED(p)) {
1302                 /* unmerged */
1303                 builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, 0);
1304                 return;
1305         }
1307         name = p->one->path;
1308         other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1310         diff_fill_sha1_info(p->one);
1311         diff_fill_sha1_info(p->two);
1313         if (p->status == DIFF_STATUS_MODIFIED && p->score)
1314                 complete_rewrite = 1;
1315         builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite);
1318 static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
1320         const char *name;
1321         const char *other;
1323         if (DIFF_PAIR_UNMERGED(p)) {
1324                 /* unmerged */
1325                 return;
1326         }
1328         name = p->one->path;
1329         other = (strcmp(name, p->two->path) ? p->two->path : NULL);
1331         diff_fill_sha1_info(p->one);
1332         diff_fill_sha1_info(p->two);
1334         builtin_checkdiff(name, other, p->one, p->two);
1337 void diff_setup(struct diff_options *options)
1339         memset(options, 0, sizeof(*options));
1340         options->output_format = DIFF_FORMAT_RAW;
1341         options->line_termination = '\n';
1342         options->break_opt = -1;
1343         options->rename_limit = -1;
1344         options->context = 3;
1346         options->change = diff_change;
1347         options->add_remove = diff_addremove;
1350 int diff_setup_done(struct diff_options *options)
1352         if ((options->find_copies_harder &&
1353              options->detect_rename != DIFF_DETECT_COPY) ||
1354             (0 <= options->rename_limit && !options->detect_rename))
1355                 return -1;
1357         /*
1358          * These cases always need recursive; we do not drop caller-supplied
1359          * recursive bits for other formats here.
1360          */
1361         if ((options->output_format == DIFF_FORMAT_PATCH) ||
1362             (options->output_format == DIFF_FORMAT_DIFFSTAT) ||
1363             (options->output_format == DIFF_FORMAT_CHECKDIFF))
1364                 options->recursive = 1;
1366         /*
1367          * These combinations do not make sense.
1368          */
1369         if (options->output_format == DIFF_FORMAT_RAW)
1370                 options->with_raw = 0;
1371         if (options->output_format == DIFF_FORMAT_DIFFSTAT)
1372                 options->with_stat  = 0;
1374         if (options->detect_rename && options->rename_limit < 0)
1375                 options->rename_limit = diff_rename_limit_default;
1376         if (options->setup & DIFF_SETUP_USE_CACHE) {
1377                 if (!active_cache)
1378                         /* read-cache does not die even when it fails
1379                          * so it is safe for us to do this here.  Also
1380                          * it does not smudge active_cache or active_nr
1381                          * when it fails, so we do not have to worry about
1382                          * cleaning it up ourselves either.
1383                          */
1384                         read_cache();
1385         }
1386         if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
1387                 use_size_cache = 1;
1388         if (options->abbrev <= 0 || 40 < options->abbrev)
1389                 options->abbrev = 40; /* full */
1391         return 0;
1394 int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
1396         char c, *eq;
1397         int len;
1399         if (*arg != '-')
1400                 return 0;
1401         c = *++arg;
1402         if (!c)
1403                 return 0;
1404         if (c == arg_short) {
1405                 c = *++arg;
1406                 if (!c)
1407                         return 1;
1408                 if (val && isdigit(c)) {
1409                         char *end;
1410                         int n = strtoul(arg, &end, 10);
1411                         if (*end)
1412                                 return 0;
1413                         *val = n;
1414                         return 1;
1415                 }
1416                 return 0;
1417         }
1418         if (c != '-')
1419                 return 0;
1420         arg++;
1421         eq = strchr(arg, '=');
1422         if (eq)
1423                 len = eq - arg;
1424         else
1425                 len = strlen(arg);
1426         if (!len || strncmp(arg, arg_long, len))
1427                 return 0;
1428         if (eq) {
1429                 int n;
1430                 char *end;
1431                 if (!isdigit(*++eq))
1432                         return 0;
1433                 n = strtoul(eq, &end, 10);
1434                 if (*end)
1435                         return 0;
1436                 *val = n;
1437         }
1438         return 1;
1441 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
1443         const char *arg = av[0];
1444         if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
1445                 options->output_format = DIFF_FORMAT_PATCH;
1446         else if (opt_arg(arg, 'U', "unified", &options->context))
1447                 options->output_format = DIFF_FORMAT_PATCH;
1448         else if (!strcmp(arg, "--patch-with-raw")) {
1449                 options->output_format = DIFF_FORMAT_PATCH;
1450                 options->with_raw = 1;
1451         }
1452         else if (!strcmp(arg, "--stat"))
1453                 options->output_format = DIFF_FORMAT_DIFFSTAT;
1454         else if (!strcmp(arg, "--check"))
1455                 options->output_format = DIFF_FORMAT_CHECKDIFF;
1456         else if (!strcmp(arg, "--summary"))
1457                 options->summary = 1;
1458         else if (!strcmp(arg, "--patch-with-stat")) {
1459                 options->output_format = DIFF_FORMAT_PATCH;
1460                 options->with_stat = 1;
1461         }
1462         else if (!strcmp(arg, "-z"))
1463                 options->line_termination = 0;
1464         else if (!strncmp(arg, "-l", 2))
1465                 options->rename_limit = strtoul(arg+2, NULL, 10);
1466         else if (!strcmp(arg, "--full-index"))
1467                 options->full_index = 1;
1468         else if (!strcmp(arg, "--binary")) {
1469                 options->output_format = DIFF_FORMAT_PATCH;
1470                 options->full_index = options->binary = 1;
1471         }
1472         else if (!strcmp(arg, "--name-only"))
1473                 options->output_format = DIFF_FORMAT_NAME;
1474         else if (!strcmp(arg, "--name-status"))
1475                 options->output_format = DIFF_FORMAT_NAME_STATUS;
1476         else if (!strcmp(arg, "-R"))
1477                 options->reverse_diff = 1;
1478         else if (!strncmp(arg, "-S", 2))
1479                 options->pickaxe = arg + 2;
1480         else if (!strcmp(arg, "-s"))
1481                 options->output_format = DIFF_FORMAT_NO_OUTPUT;
1482         else if (!strncmp(arg, "-O", 2))
1483                 options->orderfile = arg + 2;
1484         else if (!strncmp(arg, "--diff-filter=", 14))
1485                 options->filter = arg + 14;
1486         else if (!strcmp(arg, "--pickaxe-all"))
1487                 options->pickaxe_opts = DIFF_PICKAXE_ALL;
1488         else if (!strcmp(arg, "--pickaxe-regex"))
1489                 options->pickaxe_opts = DIFF_PICKAXE_REGEX;
1490         else if (!strncmp(arg, "-B", 2)) {
1491                 if ((options->break_opt =
1492                      diff_scoreopt_parse(arg)) == -1)
1493                         return -1;
1494         }
1495         else if (!strncmp(arg, "-M", 2)) {
1496                 if ((options->rename_score =
1497                      diff_scoreopt_parse(arg)) == -1)
1498                         return -1;
1499                 options->detect_rename = DIFF_DETECT_RENAME;
1500         }
1501         else if (!strncmp(arg, "-C", 2)) {
1502                 if ((options->rename_score =
1503                      diff_scoreopt_parse(arg)) == -1)
1504                         return -1;
1505                 options->detect_rename = DIFF_DETECT_COPY;
1506         }
1507         else if (!strcmp(arg, "--find-copies-harder"))
1508                 options->find_copies_harder = 1;
1509         else if (!strcmp(arg, "--abbrev"))
1510                 options->abbrev = DEFAULT_ABBREV;
1511         else if (!strncmp(arg, "--abbrev=", 9)) {
1512                 options->abbrev = strtoul(arg + 9, NULL, 10);
1513                 if (options->abbrev < MINIMUM_ABBREV)
1514                         options->abbrev = MINIMUM_ABBREV;
1515                 else if (40 < options->abbrev)
1516                         options->abbrev = 40;
1517         }
1518         else if (!strcmp(arg, "--color"))
1519                 options->color_diff = 1;
1520         else
1521                 return 0;
1522         return 1;
1525 static int parse_num(const char **cp_p)
1527         unsigned long num, scale;
1528         int ch, dot;
1529         const char *cp = *cp_p;
1531         num = 0;
1532         scale = 1;
1533         dot = 0;
1534         for(;;) {
1535                 ch = *cp;
1536                 if ( !dot && ch == '.' ) {
1537                         scale = 1;
1538                         dot = 1;
1539                 } else if ( ch == '%' ) {
1540                         scale = dot ? scale*100 : 100;
1541                         cp++;   /* % is always at the end */
1542                         break;
1543                 } else if ( ch >= '0' && ch <= '9' ) {
1544                         if ( scale < 100000 ) {
1545                                 scale *= 10;
1546                                 num = (num*10) + (ch-'0');
1547                         }
1548                 } else {
1549                         break;
1550                 }
1551                 cp++;
1552         }
1553         *cp_p = cp;
1555         /* user says num divided by scale and we say internally that
1556          * is MAX_SCORE * num / scale.
1557          */
1558         return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
1561 int diff_scoreopt_parse(const char *opt)
1563         int opt1, opt2, cmd;
1565         if (*opt++ != '-')
1566                 return -1;
1567         cmd = *opt++;
1568         if (cmd != 'M' && cmd != 'C' && cmd != 'B')
1569                 return -1; /* that is not a -M, -C nor -B option */
1571         opt1 = parse_num(&opt);
1572         if (cmd != 'B')
1573                 opt2 = 0;
1574         else {
1575                 if (*opt == 0)
1576                         opt2 = 0;
1577                 else if (*opt != '/')
1578                         return -1; /* we expect -B80/99 or -B80 */
1579                 else {
1580                         opt++;
1581                         opt2 = parse_num(&opt);
1582                 }
1583         }
1584         if (*opt != 0)
1585                 return -1;
1586         return opt1 | (opt2 << 16);
1589 struct diff_queue_struct diff_queued_diff;
1591 void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
1593         if (queue->alloc <= queue->nr) {
1594                 queue->alloc = alloc_nr(queue->alloc);
1595                 queue->queue = xrealloc(queue->queue,
1596                                         sizeof(dp) * queue->alloc);
1597         }
1598         queue->queue[queue->nr++] = dp;
1601 struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
1602                                  struct diff_filespec *one,
1603                                  struct diff_filespec *two)
1605         struct diff_filepair *dp = xmalloc(sizeof(*dp));
1606         dp->one = one;
1607         dp->two = two;
1608         dp->score = 0;
1609         dp->status = 0;
1610         dp->source_stays = 0;
1611         dp->broken_pair = 0;
1612         if (queue)
1613                 diff_q(queue, dp);
1614         return dp;
1617 void diff_free_filepair(struct diff_filepair *p)
1619         diff_free_filespec_data(p->one);
1620         diff_free_filespec_data(p->two);
1621         free(p->one);
1622         free(p->two);
1623         free(p);
1626 /* This is different from find_unique_abbrev() in that
1627  * it stuffs the result with dots for alignment.
1628  */
1629 const char *diff_unique_abbrev(const unsigned char *sha1, int len)
1631         int abblen;
1632         const char *abbrev;
1633         if (len == 40)
1634                 return sha1_to_hex(sha1);
1636         abbrev = find_unique_abbrev(sha1, len);
1637         if (!abbrev)
1638                 return sha1_to_hex(sha1);
1639         abblen = strlen(abbrev);
1640         if (abblen < 37) {
1641                 static char hex[41];
1642                 if (len < abblen && abblen <= len + 2)
1643                         sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
1644                 else
1645                         sprintf(hex, "%s...", abbrev);
1646                 return hex;
1647         }
1648         return sha1_to_hex(sha1);
1651 static void diff_flush_raw(struct diff_filepair *p,
1652                            int line_termination,
1653                            int inter_name_termination,
1654                            struct diff_options *options,
1655                            int output_format)
1657         int two_paths;
1658         char status[10];
1659         int abbrev = options->abbrev;
1660         const char *path_one, *path_two;
1662         path_one = p->one->path;
1663         path_two = p->two->path;
1664         if (line_termination) {
1665                 path_one = quote_one(path_one);
1666                 path_two = quote_one(path_two);
1667         }
1669         if (p->score)
1670                 sprintf(status, "%c%03d", p->status,
1671                         (int)(0.5 + p->score * 100.0/MAX_SCORE));
1672         else {
1673                 status[0] = p->status;
1674                 status[1] = 0;
1675         }
1676         switch (p->status) {
1677         case DIFF_STATUS_COPIED:
1678         case DIFF_STATUS_RENAMED:
1679                 two_paths = 1;
1680                 break;
1681         case DIFF_STATUS_ADDED:
1682         case DIFF_STATUS_DELETED:
1683                 two_paths = 0;
1684                 break;
1685         default:
1686                 two_paths = 0;
1687                 break;
1688         }
1689         if (output_format != DIFF_FORMAT_NAME_STATUS) {
1690                 printf(":%06o %06o %s ",
1691                        p->one->mode, p->two->mode,
1692                        diff_unique_abbrev(p->one->sha1, abbrev));
1693                 printf("%s ",
1694                        diff_unique_abbrev(p->two->sha1, abbrev));
1695         }
1696         printf("%s%c%s", status, inter_name_termination, path_one);
1697         if (two_paths)
1698                 printf("%c%s", inter_name_termination, path_two);
1699         putchar(line_termination);
1700         if (path_one != p->one->path)
1701                 free((void*)path_one);
1702         if (path_two != p->two->path)
1703                 free((void*)path_two);
1706 static void diff_flush_name(struct diff_filepair *p,
1707                             int inter_name_termination,
1708                             int line_termination)
1710         char *path = p->two->path;
1712         if (line_termination)
1713                 path = quote_one(p->two->path);
1714         else
1715                 path = p->two->path;
1716         printf("%s%c", path, line_termination);
1717         if (p->two->path != path)
1718                 free(path);
1721 int diff_unmodified_pair(struct diff_filepair *p)
1723         /* This function is written stricter than necessary to support
1724          * the currently implemented transformers, but the idea is to
1725          * let transformers to produce diff_filepairs any way they want,
1726          * and filter and clean them up here before producing the output.
1727          */
1728         struct diff_filespec *one, *two;
1730         if (DIFF_PAIR_UNMERGED(p))
1731                 return 0; /* unmerged is interesting */
1733         one = p->one;
1734         two = p->two;
1736         /* deletion, addition, mode or type change
1737          * and rename are all interesting.
1738          */
1739         if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
1740             DIFF_PAIR_MODE_CHANGED(p) ||
1741             strcmp(one->path, two->path))
1742                 return 0;
1744         /* both are valid and point at the same path.  that is, we are
1745          * dealing with a change.
1746          */
1747         if (one->sha1_valid && two->sha1_valid &&
1748             !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
1749                 return 1; /* no change */
1750         if (!one->sha1_valid && !two->sha1_valid)
1751                 return 1; /* both look at the same file on the filesystem. */
1752         return 0;
1755 static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
1757         if (diff_unmodified_pair(p))
1758                 return;
1760         if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
1761             (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
1762                 return; /* no tree diffs in patch format */
1764         run_diff(p, o);
1767 static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
1768                             struct diffstat_t *diffstat)
1770         if (diff_unmodified_pair(p))
1771                 return;
1773         if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
1774             (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
1775                 return; /* no tree diffs in patch format */
1777         run_diffstat(p, o, diffstat);
1780 static void diff_flush_checkdiff(struct diff_filepair *p,
1781                 struct diff_options *o)
1783         if (diff_unmodified_pair(p))
1784                 return;
1786         if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
1787             (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
1788                 return; /* no tree diffs in patch format */
1790         run_checkdiff(p, o);
1793 int diff_queue_is_empty(void)
1795         struct diff_queue_struct *q = &diff_queued_diff;
1796         int i;
1797         for (i = 0; i < q->nr; i++)
1798                 if (!diff_unmodified_pair(q->queue[i]))
1799                         return 0;
1800         return 1;
1803 #if DIFF_DEBUG
1804 void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
1806         fprintf(stderr, "queue[%d] %s (%s) %s %06o %s\n",
1807                 x, one ? one : "",
1808                 s->path,
1809                 DIFF_FILE_VALID(s) ? "valid" : "invalid",
1810                 s->mode,
1811                 s->sha1_valid ? sha1_to_hex(s->sha1) : "");
1812         fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
1813                 x, one ? one : "",
1814                 s->size, s->xfrm_flags);
1817 void diff_debug_filepair(const struct diff_filepair *p, int i)
1819         diff_debug_filespec(p->one, i, "one");
1820         diff_debug_filespec(p->two, i, "two");
1821         fprintf(stderr, "score %d, status %c stays %d broken %d\n",
1822                 p->score, p->status ? p->status : '?',
1823                 p->source_stays, p->broken_pair);
1826 void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
1828         int i;
1829         if (msg)
1830                 fprintf(stderr, "%s\n", msg);
1831         fprintf(stderr, "q->nr = %d\n", q->nr);
1832         for (i = 0; i < q->nr; i++) {
1833                 struct diff_filepair *p = q->queue[i];
1834                 diff_debug_filepair(p, i);
1835         }
1837 #endif
1839 static void diff_resolve_rename_copy(void)
1841         int i, j;
1842         struct diff_filepair *p, *pp;
1843         struct diff_queue_struct *q = &diff_queued_diff;
1845         diff_debug_queue("resolve-rename-copy", q);
1847         for (i = 0; i < q->nr; i++) {
1848                 p = q->queue[i];
1849                 p->status = 0; /* undecided */
1850                 if (DIFF_PAIR_UNMERGED(p))
1851                         p->status = DIFF_STATUS_UNMERGED;
1852                 else if (!DIFF_FILE_VALID(p->one))
1853                         p->status = DIFF_STATUS_ADDED;
1854                 else if (!DIFF_FILE_VALID(p->two))
1855                         p->status = DIFF_STATUS_DELETED;
1856                 else if (DIFF_PAIR_TYPE_CHANGED(p))
1857                         p->status = DIFF_STATUS_TYPE_CHANGED;
1859                 /* from this point on, we are dealing with a pair
1860                  * whose both sides are valid and of the same type, i.e.
1861                  * either in-place edit or rename/copy edit.
1862                  */
1863                 else if (DIFF_PAIR_RENAME(p)) {
1864                         if (p->source_stays) {
1865                                 p->status = DIFF_STATUS_COPIED;
1866                                 continue;
1867                         }
1868                         /* See if there is some other filepair that
1869                          * copies from the same source as us.  If so
1870                          * we are a copy.  Otherwise we are either a
1871                          * copy if the path stays, or a rename if it
1872                          * does not, but we already handled "stays" case.
1873                          */
1874                         for (j = i + 1; j < q->nr; j++) {
1875                                 pp = q->queue[j];
1876                                 if (strcmp(pp->one->path, p->one->path))
1877                                         continue; /* not us */
1878                                 if (!DIFF_PAIR_RENAME(pp))
1879                                         continue; /* not a rename/copy */
1880                                 /* pp is a rename/copy from the same source */
1881                                 p->status = DIFF_STATUS_COPIED;
1882                                 break;
1883                         }
1884                         if (!p->status)
1885                                 p->status = DIFF_STATUS_RENAMED;
1886                 }
1887                 else if (memcmp(p->one->sha1, p->two->sha1, 20) ||
1888                          p->one->mode != p->two->mode)
1889                         p->status = DIFF_STATUS_MODIFIED;
1890                 else {
1891                         /* This is a "no-change" entry and should not
1892                          * happen anymore, but prepare for broken callers.
1893                          */
1894                         error("feeding unmodified %s to diffcore",
1895                               p->one->path);
1896                         p->status = DIFF_STATUS_UNKNOWN;
1897                 }
1898         }
1899         diff_debug_queue("resolve-rename-copy done", q);
1902 static void flush_one_pair(struct diff_filepair *p,
1903                            int diff_output_format,
1904                            struct diff_options *options,
1905                            struct diffstat_t *diffstat)
1907         int inter_name_termination = '\t';
1908         int line_termination = options->line_termination;
1909         if (!line_termination)
1910                 inter_name_termination = 0;
1912         switch (p->status) {
1913         case DIFF_STATUS_UNKNOWN:
1914                 break;
1915         case 0:
1916                 die("internal error in diff-resolve-rename-copy");
1917                 break;
1918         default:
1919                 switch (diff_output_format) {
1920                 case DIFF_FORMAT_DIFFSTAT:
1921                         diff_flush_stat(p, options, diffstat);
1922                         break;
1923                 case DIFF_FORMAT_CHECKDIFF:
1924                         diff_flush_checkdiff(p, options);
1925                         break;
1926                 case DIFF_FORMAT_PATCH:
1927                         diff_flush_patch(p, options);
1928                         break;
1929                 case DIFF_FORMAT_RAW:
1930                 case DIFF_FORMAT_NAME_STATUS:
1931                         diff_flush_raw(p, line_termination,
1932                                        inter_name_termination,
1933                                        options, diff_output_format);
1934                         break;
1935                 case DIFF_FORMAT_NAME:
1936                         diff_flush_name(p,
1937                                         inter_name_termination,
1938                                         line_termination);
1939                         break;
1940                 case DIFF_FORMAT_NO_OUTPUT:
1941                         break;
1942                 }
1943         }
1946 static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
1948         if (fs->mode)
1949                 printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path);
1950         else
1951                 printf(" %s %s\n", newdelete, fs->path);
1955 static void show_mode_change(struct diff_filepair *p, int show_name)
1957         if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
1958                 if (show_name)
1959                         printf(" mode change %06o => %06o %s\n",
1960                                p->one->mode, p->two->mode, p->two->path);
1961                 else
1962                         printf(" mode change %06o => %06o\n",
1963                                p->one->mode, p->two->mode);
1964         }
1967 static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
1969         const char *old, *new;
1971         /* Find common prefix */
1972         old = p->one->path;
1973         new = p->two->path;
1974         while (1) {
1975                 const char *slash_old, *slash_new;
1976                 slash_old = strchr(old, '/');
1977                 slash_new = strchr(new, '/');
1978                 if (!slash_old ||
1979                     !slash_new ||
1980                     slash_old - old != slash_new - new ||
1981                     memcmp(old, new, slash_new - new))
1982                         break;
1983                 old = slash_old + 1;
1984                 new = slash_new + 1;
1985         }
1986         /* p->one->path thru old is the common prefix, and old and new
1987          * through the end of names are renames
1988          */
1989         if (old != p->one->path)
1990                 printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
1991                        (int)(old - p->one->path), p->one->path,
1992                        old, new, (int)(0.5 + p->score * 100.0/MAX_SCORE));
1993         else
1994                 printf(" %s %s => %s (%d%%)\n", renamecopy,
1995                        p->one->path, p->two->path,
1996                        (int)(0.5 + p->score * 100.0/MAX_SCORE));
1997         show_mode_change(p, 0);
2000 static void diff_summary(struct diff_filepair *p)
2002         switch(p->status) {
2003         case DIFF_STATUS_DELETED:
2004                 show_file_mode_name("delete", p->one);
2005                 break;
2006         case DIFF_STATUS_ADDED:
2007                 show_file_mode_name("create", p->two);
2008                 break;
2009         case DIFF_STATUS_COPIED:
2010                 show_rename_copy("copy", p);
2011                 break;
2012         case DIFF_STATUS_RENAMED:
2013                 show_rename_copy("rename", p);
2014                 break;
2015         default:
2016                 if (p->score) {
2017                         printf(" rewrite %s (%d%%)\n", p->two->path,
2018                                 (int)(0.5 + p->score * 100.0/MAX_SCORE));
2019                         show_mode_change(p, 0);
2020                 } else  show_mode_change(p, 1);
2021                 break;
2022         }
2025 void diff_flush(struct diff_options *options)
2027         struct diff_queue_struct *q = &diff_queued_diff;
2028         int i;
2029         int diff_output_format = options->output_format;
2030         struct diffstat_t *diffstat = NULL;
2032         if (diff_output_format == DIFF_FORMAT_DIFFSTAT || options->with_stat) {
2033                 diffstat = xcalloc(sizeof (struct diffstat_t), 1);
2034                 diffstat->xm.consume = diffstat_consume;
2035         }
2037         if (options->with_raw) {
2038                 for (i = 0; i < q->nr; i++) {
2039                         struct diff_filepair *p = q->queue[i];
2040                         flush_one_pair(p, DIFF_FORMAT_RAW, options, NULL);
2041                 }
2042                 putchar(options->line_termination);
2043         }
2044         if (options->with_stat) {
2045                 for (i = 0; i < q->nr; i++) {
2046                         struct diff_filepair *p = q->queue[i];
2047                         flush_one_pair(p, DIFF_FORMAT_DIFFSTAT, options,
2048                                        diffstat);
2049                 }
2050                 show_stats(diffstat);
2051                 free(diffstat);
2052                 diffstat = NULL;
2053                 if (options->summary)
2054                         for (i = 0; i < q->nr; i++)
2055                                 diff_summary(q->queue[i]);
2056                 if (options->stat_sep)
2057                         fputs(options->stat_sep, stdout);
2058                 else
2059                         putchar(options->line_termination);
2060         }
2061         for (i = 0; i < q->nr; i++) {
2062                 struct diff_filepair *p = q->queue[i];
2063                 flush_one_pair(p, diff_output_format, options, diffstat);
2064         }
2066         if (diffstat) {
2067                 show_stats(diffstat);
2068                 free(diffstat);
2069         }
2071         for (i = 0; i < q->nr; i++) {
2072                 if (diffstat && options->summary)
2073                         diff_summary(q->queue[i]);
2074                 diff_free_filepair(q->queue[i]);
2075         }
2077         free(q->queue);
2078         q->queue = NULL;
2079         q->nr = q->alloc = 0;
2082 static void diffcore_apply_filter(const char *filter)
2084         int i;
2085         struct diff_queue_struct *q = &diff_queued_diff;
2086         struct diff_queue_struct outq;
2087         outq.queue = NULL;
2088         outq.nr = outq.alloc = 0;
2090         if (!filter)
2091                 return;
2093         if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
2094                 int found;
2095                 for (i = found = 0; !found && i < q->nr; i++) {
2096                         struct diff_filepair *p = q->queue[i];
2097                         if (((p->status == DIFF_STATUS_MODIFIED) &&
2098                              ((p->score &&
2099                                strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
2100                               (!p->score &&
2101                                strchr(filter, DIFF_STATUS_MODIFIED)))) ||
2102                             ((p->status != DIFF_STATUS_MODIFIED) &&
2103                              strchr(filter, p->status)))
2104                                 found++;
2105                 }
2106                 if (found)
2107                         return;
2109                 /* otherwise we will clear the whole queue
2110                  * by copying the empty outq at the end of this
2111                  * function, but first clear the current entries
2112                  * in the queue.
2113                  */
2114                 for (i = 0; i < q->nr; i++)
2115                         diff_free_filepair(q->queue[i]);
2116         }
2117         else {
2118                 /* Only the matching ones */
2119                 for (i = 0; i < q->nr; i++) {
2120                         struct diff_filepair *p = q->queue[i];
2122                         if (((p->status == DIFF_STATUS_MODIFIED) &&
2123                              ((p->score &&
2124                                strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
2125                               (!p->score &&
2126                                strchr(filter, DIFF_STATUS_MODIFIED)))) ||
2127                             ((p->status != DIFF_STATUS_MODIFIED) &&
2128                              strchr(filter, p->status)))
2129                                 diff_q(&outq, p);
2130                         else
2131                                 diff_free_filepair(p);
2132                 }
2133         }
2134         free(q->queue);
2135         *q = outq;
2138 void diffcore_std(struct diff_options *options)
2140         if (options->break_opt != -1)
2141                 diffcore_break(options->break_opt);
2142         if (options->detect_rename)
2143                 diffcore_rename(options);
2144         if (options->break_opt != -1)
2145                 diffcore_merge_broken();
2146         if (options->pickaxe)
2147                 diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
2148         if (options->orderfile)
2149                 diffcore_order(options->orderfile);
2150         diff_resolve_rename_copy();
2151         diffcore_apply_filter(options->filter);
2155 void diffcore_std_no_resolve(struct diff_options *options)
2157         if (options->pickaxe)
2158                 diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
2159         if (options->orderfile)
2160                 diffcore_order(options->orderfile);
2161         diffcore_apply_filter(options->filter);
2164 void diff_addremove(struct diff_options *options,
2165                     int addremove, unsigned mode,
2166                     const unsigned char *sha1,
2167                     const char *base, const char *path)
2169         char concatpath[PATH_MAX];
2170         struct diff_filespec *one, *two;
2172         /* This may look odd, but it is a preparation for
2173          * feeding "there are unchanged files which should
2174          * not produce diffs, but when you are doing copy
2175          * detection you would need them, so here they are"
2176          * entries to the diff-core.  They will be prefixed
2177          * with something like '=' or '*' (I haven't decided
2178          * which but should not make any difference).
2179          * Feeding the same new and old to diff_change() 
2180          * also has the same effect.
2181          * Before the final output happens, they are pruned after
2182          * merged into rename/copy pairs as appropriate.
2183          */
2184         if (options->reverse_diff)
2185                 addremove = (addremove == '+' ? '-' :
2186                              addremove == '-' ? '+' : addremove);
2188         if (!path) path = "";
2189         sprintf(concatpath, "%s%s", base, path);
2190         one = alloc_filespec(concatpath);
2191         two = alloc_filespec(concatpath);
2193         if (addremove != '+')
2194                 fill_filespec(one, sha1, mode);
2195         if (addremove != '-')
2196                 fill_filespec(two, sha1, mode);
2198         diff_queue(&diff_queued_diff, one, two);
2201 void diff_change(struct diff_options *options,
2202                  unsigned old_mode, unsigned new_mode,
2203                  const unsigned char *old_sha1,
2204                  const unsigned char *new_sha1,
2205                  const char *base, const char *path) 
2207         char concatpath[PATH_MAX];
2208         struct diff_filespec *one, *two;
2210         if (options->reverse_diff) {
2211                 unsigned tmp;
2212                 const unsigned char *tmp_c;
2213                 tmp = old_mode; old_mode = new_mode; new_mode = tmp;
2214                 tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
2215         }
2216         if (!path) path = "";
2217         sprintf(concatpath, "%s%s", base, path);
2218         one = alloc_filespec(concatpath);
2219         two = alloc_filespec(concatpath);
2220         fill_filespec(one, old_sha1, old_mode);
2221         fill_filespec(two, new_sha1, new_mode);
2223         diff_queue(&diff_queued_diff, one, two);
2226 void diff_unmerge(struct diff_options *options,
2227                   const char *path)
2229         struct diff_filespec *one, *two;
2230         one = alloc_filespec(path);
2231         two = alloc_filespec(path);
2232         diff_queue(&diff_queued_diff, one, two);