Merge branch 'jc/diff' into next
[git] / combine-diff.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "diff.h"
4 #include "diffcore.h"
5 #include "quote.h"
6
7 static int uninteresting(struct diff_filepair *p)
8 {
9         if (diff_unmodified_pair(p))
10                 return 1;
11         return 0;
12 }
13
14 static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
15 {
16         struct diff_queue_struct *q = &diff_queued_diff;
17         struct combine_diff_path *p;
18         int i;
19
20         if (!n) {
21                 struct combine_diff_path *list = NULL, **tail = &list;
22                 for (i = 0; i < q->nr; i++) {
23                         int len;
24                         const char *path;
25                         if (uninteresting(q->queue[i]))
26                                 continue;
27                         path = q->queue[i]->two->path;
28                         len = strlen(path);
29                         p = xmalloc(combine_diff_path_size(num_parent, len));
30                         p->path = (char*) &(p->parent[num_parent]);
31                         memcpy(p->path, path, len);
32                         p->path[len] = 0;
33                         p->len = len;
34                         p->next = NULL;
35                         memset(p->parent, 0,
36                                sizeof(p->parent[0]) * num_parent);
37
38                         memcpy(p->sha1, q->queue[i]->two->sha1, 20);
39                         p->mode = q->queue[i]->two->mode;
40                         memcpy(p->parent[n].sha1, q->queue[i]->one->sha1, 20);
41                         p->parent[n].mode = q->queue[i]->one->mode;
42                         p->parent[n].status = q->queue[i]->status;
43                         *tail = p;
44                         tail = &p->next;
45                 }
46                 return list;
47         }
48
49         for (p = curr; p; p = p->next) {
50                 int found = 0;
51                 if (!p->len)
52                         continue;
53                 for (i = 0; i < q->nr; i++) {
54                         const char *path;
55                         int len;
56
57                         if (uninteresting(q->queue[i]))
58                                 continue;
59                         path = q->queue[i]->two->path;
60                         len = strlen(path);
61                         if (len == p->len && !memcmp(path, p->path, len)) {
62                                 found = 1;
63                                 memcpy(p->parent[n].sha1,
64                                        q->queue[i]->one->sha1, 20);
65                                 p->parent[n].mode = q->queue[i]->one->mode;
66                                 p->parent[n].status = q->queue[i]->status;
67                                 break;
68                         }
69                 }
70                 if (!found)
71                         p->len = 0;
72         }
73         return curr;
74 }
75
76 /* Lines lost from parent */
77 struct lline {
78         struct lline *next;
79         int len;
80         unsigned long parent_map;
81         char line[FLEX_ARRAY];
82 };
83
84 /* Lines surviving in the merge result */
85 struct sline {
86         struct lline *lost_head, **lost_tail;
87         char *bol;
88         int len;
89         /* bit 0 up to (N-1) are on if the parent has this line (i.e.
90          * we did not change it).
91          * bit N is used for "interesting" lines, including context.
92          */
93         unsigned long flag;
94         unsigned long *p_lno;
95 };
96
97 static char *grab_blob(const unsigned char *sha1, unsigned long *size)
98 {
99         char *blob;
100         char type[20];
101         if (!memcmp(sha1, null_sha1, 20)) {
102                 /* deleted blob */
103                 *size = 0;
104                 return xcalloc(1, 1);
105         }
106         blob = read_sha1_file(sha1, type, size);
107         if (strcmp(type, "blob"))
108                 die("object '%s' is not a blob!", sha1_to_hex(sha1));
109         return blob;
110 }
111
112 #define TMPPATHLEN 50
113 #define MAXLINELEN 10240
114
115 static void write_to_temp_file(char *tmpfile, void *blob, unsigned long size)
116 {
117         int fd = git_mkstemp(tmpfile, TMPPATHLEN, ".diff_XXXXXX");
118         if (fd < 0)
119                 die("unable to create temp-file");
120         if (write(fd, blob, size) != size)
121                 die("unable to write temp-file");
122         close(fd);
123 }
124
125 static void write_temp_blob(char *tmpfile, const unsigned char *sha1)
126 {
127         unsigned long size;
128         void *blob;
129         blob = grab_blob(sha1, &size);
130         write_to_temp_file(tmpfile, blob, size);
131         free(blob);
132 }
133
134 static int parse_num(char **cp_p, unsigned int *num_p)
135 {
136         char *cp = *cp_p;
137         unsigned int num = 0;
138         int read_some;
139
140         while ('0' <= *cp && *cp <= '9')
141                 num = num * 10 + *cp++ - '0';
142         if (!(read_some = cp - *cp_p))
143                 return -1;
144         *cp_p = cp;
145         *num_p = num;
146         return 0;
147 }
148
149 static int parse_hunk_header(char *line, int len,
150                              unsigned int *ob, unsigned int *on,
151                              unsigned int *nb, unsigned int *nn)
152 {
153         char *cp;
154         cp = line + 4;
155         if (parse_num(&cp, ob)) {
156         bad_line:
157                 return error("malformed diff output: %s", line);
158         }
159         if (*cp == ',') {
160                 cp++;
161                 if (parse_num(&cp, on))
162                         goto bad_line;
163         }
164         else
165                 *on = 1;
166         if (*cp++ != ' ' || *cp++ != '+')
167                 goto bad_line;
168         if (parse_num(&cp, nb))
169                 goto bad_line;
170         if (*cp == ',') {
171                 cp++;
172                 if (parse_num(&cp, nn))
173                         goto bad_line;
174         }
175         else
176                 *nn = 1;
177         return -!!memcmp(cp, " @@", 3);
178 }
179
180 static void append_lost(struct sline *sline, int n, const char *line)
181 {
182         struct lline *lline;
183         int len = strlen(line);
184         unsigned long this_mask = (1UL<<n);
185         if (line[len-1] == '\n')
186                 len--;
187
188         /* Check to see if we can squash things */
189         if (sline->lost_head) {
190                 struct lline *last_one = NULL;
191                 /* We cannot squash it with earlier one */
192                 for (lline = sline->lost_head;
193                      lline;
194                      lline = lline->next)
195                         if (lline->parent_map & this_mask)
196                                 last_one = lline;
197                 lline = last_one ? last_one->next : sline->lost_head;
198                 while (lline) {
199                         if (lline->len == len &&
200                             !memcmp(lline->line, line, len)) {
201                                 lline->parent_map |= this_mask;
202                                 return;
203                         }
204                         lline = lline->next;
205                 }
206         }
207
208         lline = xmalloc(sizeof(*lline) + len + 1);
209         lline->len = len;
210         lline->next = NULL;
211         lline->parent_map = this_mask;
212         memcpy(lline->line, line, len);
213         lline->line[len] = 0;
214         *sline->lost_tail = lline;
215         sline->lost_tail = &lline->next;
216 }
217
218 static void combine_diff(const unsigned char *parent, const char *ourtmp,
219                          struct sline *sline, int cnt, int n, int num_parent)
220 {
221         FILE *in;
222         char parent_tmp[TMPPATHLEN];
223         char cmd[TMPPATHLEN * 2 + 1024];
224         char line[MAXLINELEN];
225         unsigned int lno, ob, on, nb, nn, p_lno;
226         unsigned long nmask = (1UL << n);
227         struct sline *lost_bucket = NULL;
228
229         if (!cnt)
230                 return; /* result deleted */
231
232         write_temp_blob(parent_tmp, parent);
233         sprintf(cmd, "diff --unified=0 -La/x -Lb/x '%s' '%s'",
234                 parent_tmp, ourtmp);
235         in = popen(cmd, "r");
236         if (!in)
237                 die("cannot spawn %s", cmd);
238
239         lno = 1;
240         while (fgets(line, sizeof(line), in) != NULL) {
241                 int len = strlen(line);
242                 if (5 < len && !memcmp("@@ -", line, 4)) {
243                         if (parse_hunk_header(line, len,
244                                               &ob, &on, &nb, &nn))
245                                 break;
246                         lno = nb;
247                         if (!nb)
248                                 /* @@ -1,2 +0,0 @@ to remove the
249                                  * first two lines...
250                                  */
251                                 nb = 1;
252                         if (nn == 0)
253                                 /* @@ -X,Y +N,0 @@ removed Y lines
254                                  * that would have come *after* line N
255                                  * in the result.  Our lost buckets hang
256                                  * to the line after the removed lines,
257                                  */
258                                 lost_bucket = &sline[nb];
259                         else
260                                 lost_bucket = &sline[nb-1];
261                         if (!sline[nb-1].p_lno)
262                                 sline[nb-1].p_lno =
263                                         xcalloc(num_parent,
264                                                 sizeof(unsigned long));
265                         sline[nb-1].p_lno[n] = ob;
266                         continue;
267                 }
268                 if (!lost_bucket)
269                         continue; /* not in any hunk yet */
270                 switch (line[0]) {
271                 case '-':
272                         append_lost(lost_bucket, n, line+1);
273                         break;
274                 case '+':
275                         sline[lno-1].flag |= nmask;
276                         lno++;
277                         break;
278                 }
279         }
280         fclose(in);
281         unlink(parent_tmp);
282
283         /* Assign line numbers for this parent.
284          *
285          * sline[lno].p_lno[n] records the first line number
286          * (counting from 1) for parent N if the final hunk display
287          * started by showing sline[lno] (possibly showing the lost
288          * lines attached to it first).
289          */
290         for (lno = 0,  p_lno = 1; lno < cnt; lno++) {
291                 struct lline *ll;
292                 sline[lno].p_lno[n] = p_lno;
293
294                 /* How many lines would this sline advance the p_lno? */
295                 ll = sline[lno].lost_head;
296                 while (ll) {
297                         if (ll->parent_map & nmask)
298                                 p_lno++; /* '-' means parent had it */
299                         ll = ll->next;
300                 }
301                 if (!(sline[lno].flag & nmask))
302                         p_lno++; /* no '+' means parent had it */
303         }
304         sline[lno].p_lno[n] = p_lno; /* trailer */
305 }
306
307 static unsigned long context = 3;
308 static char combine_marker = '@';
309
310 static int interesting(struct sline *sline, unsigned long all_mask)
311 {
312         /* If some parents lost lines here, or if we have added to
313          * some parent, it is interesting.
314          */
315         return ((sline->flag & all_mask) || sline->lost_head);
316 }
317
318 static unsigned long adjust_hunk_tail(struct sline *sline,
319                                       unsigned long all_mask,
320                                       unsigned long hunk_begin,
321                                       unsigned long i)
322 {
323         /* i points at the first uninteresting line.  If the last line
324          * of the hunk was interesting only because it has some
325          * deletion, then it is not all that interesting for the
326          * purpose of giving trailing context lines.  This is because
327          * we output '-' line and then unmodified sline[i-1] itself in
328          * that case which gives us one extra context line.
329          */
330         if ((hunk_begin + 1 <= i) && !(sline[i-1].flag & all_mask))
331                 i--;
332         return i;
333 }
334
335 static unsigned long find_next(struct sline *sline,
336                                unsigned long mark,
337                                unsigned long i,
338                                unsigned long cnt,
339                                int uninteresting)
340 {
341         /* We have examined up to i-1 and are about to look at i.
342          * Find next interesting or uninteresting line.  Here,
343          * "interesting" does not mean interesting(), but marked by
344          * the give_context() function below (i.e. it includes context
345          * lines that are not interesting to interesting() function
346          * that are surrounded by interesting() ones.
347          */
348         while (i < cnt)
349                 if (uninteresting
350                     ? !(sline[i].flag & mark)
351                     : (sline[i].flag & mark))
352                         return i;
353                 else
354                         i++;
355         return cnt;
356 }
357
358 static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
359 {
360         unsigned long all_mask = (1UL<<num_parent) - 1;
361         unsigned long mark = (1UL<<num_parent);
362         unsigned long i;
363
364         /* Two groups of interesting lines may have a short gap of
365          * unintersting lines.  Connect such groups to give them a
366          * bit of context.
367          *
368          * We first start from what the interesting() function says,
369          * and mark them with "mark", and paint context lines with the
370          * mark.  So interesting() would still say false for such context
371          * lines but they are treated as "interesting" in the end.
372          */
373         i = find_next(sline, mark, 0, cnt, 0);
374         if (cnt <= i)
375                 return 0;
376
377         while (i < cnt) {
378                 unsigned long j = (context < i) ? (i - context) : 0;
379                 unsigned long k;
380
381                 /* Paint a few lines before the first interesting line. */
382                 while (j < i)
383                         sline[j++].flag |= mark;
384
385         again:
386                 /* we know up to i is to be included.  where does the
387                  * next uninteresting one start?
388                  */
389                 j = find_next(sline, mark, i, cnt, 1);
390                 if (cnt <= j)
391                         break; /* the rest are all interesting */
392
393                 /* lookahead context lines */
394                 k = find_next(sline, mark, j, cnt, 0);
395                 j = adjust_hunk_tail(sline, all_mask, i, j);
396
397                 if (k < j + context) {
398                         /* k is interesting and [j,k) are not, but
399                          * paint them interesting because the gap is small.
400                          */
401                         while (j < k)
402                                 sline[j++].flag |= mark;
403                         i = k;
404                         goto again;
405                 }
406
407                 /* j is the first uninteresting line and there is
408                  * no overlap beyond it within context lines.  Paint
409                  * the trailing edge a bit.
410                  */
411                 i = k;
412                 k = (j + context < cnt) ? j + context : cnt;
413                 while (j < k)
414                         sline[j++].flag |= mark;
415         }
416         return 1;
417 }
418
419 static int make_hunks(struct sline *sline, unsigned long cnt,
420                        int num_parent, int dense)
421 {
422         unsigned long all_mask = (1UL<<num_parent) - 1;
423         unsigned long mark = (1UL<<num_parent);
424         unsigned long i;
425         int has_interesting = 0;
426
427         for (i = 0; i < cnt; i++) {
428                 if (interesting(&sline[i], all_mask))
429                         sline[i].flag |= mark;
430                 else
431                         sline[i].flag &= ~mark;
432         }
433         if (!dense)
434                 return give_context(sline, cnt, num_parent);
435
436         /* Look at each hunk, and if we have changes from only one
437          * parent, or the changes are the same from all but one
438          * parent, mark that uninteresting.
439          */
440         i = 0;
441         while (i < cnt) {
442                 unsigned long j, hunk_begin, hunk_end;
443                 unsigned long same_diff;
444                 while (i < cnt && !(sline[i].flag & mark))
445                         i++;
446                 if (cnt <= i)
447                         break; /* No more interesting hunks */
448                 hunk_begin = i;
449                 for (j = i + 1; j < cnt; j++) {
450                         if (!(sline[j].flag & mark)) {
451                                 /* Look beyond the end to see if there
452                                  * is an interesting line after this
453                                  * hunk within context span.
454                                  */
455                                 unsigned long la; /* lookahead */
456                                 int contin = 0;
457                                 la = adjust_hunk_tail(sline, all_mask,
458                                                      hunk_begin, j);
459                                 la = (la + context < cnt) ?
460                                         (la + context) : cnt;
461                                 while (j <= --la) {
462                                         if (sline[la].flag & mark) {
463                                                 contin = 1;
464                                                 break;
465                                         }
466                                 }
467                                 if (!contin)
468                                         break;
469                                 j = la;
470                         }
471                 }
472                 hunk_end = j;
473
474                 /* [i..hunk_end) are interesting.  Now is it really
475                  * interesting?  We check if there are only two versions
476                  * and the result matches one of them.  That is, we look
477                  * at:
478                  *   (+) line, which records lines added to which parents;
479                  *       this line appears in the result.
480                  *   (-) line, which records from what parents the line
481                  *       was removed; this line does not appear in the result.
482                  * then check the set of parents the result has difference
483                  * from, from all lines.  If there are lines that has
484                  * different set of parents that the result has differences
485                  * from, that means we have more than two versions.
486                  *
487                  * Even when we have only two versions, if the result does
488                  * not match any of the parents, the it should be considered
489                  * interesting.  In such a case, we would have all '+' line.
490                  * After passing the above "two versions" test, that would
491                  * appear as "the same set of parents" to be "all parents".
492                  */
493                 same_diff = 0;
494                 has_interesting = 0;
495                 for (j = i; j < hunk_end && !has_interesting; j++) {
496                         unsigned long this_diff = sline[j].flag & all_mask;
497                         struct lline *ll = sline[j].lost_head;
498                         if (this_diff) {
499                                 /* This has some changes.  Is it the
500                                  * same as others?
501                                  */
502                                 if (!same_diff)
503                                         same_diff = this_diff;
504                                 else if (same_diff != this_diff) {
505                                         has_interesting = 1;
506                                         break;
507                                 }
508                         }
509                         while (ll && !has_interesting) {
510                                 /* Lost this line from these parents;
511                                  * who are they?  Are they the same?
512                                  */
513                                 this_diff = ll->parent_map;
514                                 if (!same_diff)
515                                         same_diff = this_diff;
516                                 else if (same_diff != this_diff) {
517                                         has_interesting = 1;
518                                 }
519                                 ll = ll->next;
520                         }
521                 }
522
523                 if (!has_interesting && same_diff != all_mask) {
524                         /* This hunk is not that interesting after all */
525                         for (j = hunk_begin; j < hunk_end; j++)
526                                 sline[j].flag &= ~mark;
527                 }
528                 i = hunk_end;
529         }
530
531         has_interesting = give_context(sline, cnt, num_parent);
532         return has_interesting;
533 }
534
535 static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, unsigned long cnt, int n)
536 {
537         l0 = sline[l0].p_lno[n];
538         l1 = sline[l1].p_lno[n];
539         printf(" -%lu,%lu", l0, l1-l0);
540 }
541
542 static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
543 {
544         unsigned long mark = (1UL<<num_parent);
545         int i;
546         unsigned long lno = 0;
547
548         if (!cnt)
549                 return; /* result deleted */
550
551         while (1) {
552                 struct sline *sl = &sline[lno];
553                 int hunk_end;
554                 while (lno < cnt && !(sline[lno].flag & mark))
555                         lno++;
556                 if (cnt <= lno)
557                         break;
558                 for (hunk_end = lno + 1; hunk_end < cnt; hunk_end++)
559                         if (!(sline[hunk_end].flag & mark))
560                                 break;
561                 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
562                 for (i = 0; i < num_parent; i++)
563                         show_parent_lno(sline, lno, hunk_end, cnt, i);
564                 printf(" +%lu,%lu ", lno+1, hunk_end-lno);
565                 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
566                 putchar('\n');
567                 while (lno < hunk_end) {
568                         struct lline *ll;
569                         int j;
570                         unsigned long p_mask;
571                         sl = &sline[lno++];
572                         ll = sl->lost_head;
573                         while (ll) {
574                                 for (j = 0; j < num_parent; j++) {
575                                         if (ll->parent_map & (1UL<<j))
576                                                 putchar('-');
577                                         else
578                                                 putchar(' ');
579                                 }
580                                 puts(ll->line);
581                                 ll = ll->next;
582                         }
583                         p_mask = 1;
584                         for (j = 0; j < num_parent; j++) {
585                                 if (p_mask & sl->flag)
586                                         putchar('+');
587                                 else
588                                         putchar(' ');
589                                 p_mask <<= 1;
590                         }
591                         printf("%.*s\n", sl->len, sl->bol);
592                 }
593         }
594 }
595
596 static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
597                                int i, int j)
598 {
599         /* We have already examined parent j and we know parent i
600          * and parent j are the same, so reuse the combined result
601          * of parent j for parent i.
602          */
603         unsigned long lno, imask, jmask;
604         imask = (1UL<<i);
605         jmask = (1UL<<j);
606
607         for (lno = 0; lno < cnt; lno++) {
608                 struct lline *ll = sline->lost_head;
609                 sline->p_lno[i] = sline->p_lno[j];
610                 while (ll) {
611                         if (ll->parent_map & jmask)
612                                 ll->parent_map |= imask;
613                         ll = ll->next;
614                 }
615                 if (sline->flag & jmask)
616                         sline->flag |= imask;
617                 sline++;
618         }
619         /* the overall size of the file (sline[cnt]) */
620         sline->p_lno[i] = sline->p_lno[j];
621 }
622
623 static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
624                            int dense, const char *header,
625                            struct diff_options *opt)
626 {
627         unsigned long size, cnt, lno;
628         char *result, *cp, *ep;
629         struct sline *sline; /* survived lines */
630         int mode_differs = 0;
631         int i, show_hunks, shown_header = 0;
632         char ourtmp_buf[TMPPATHLEN];
633         char *ourtmp = ourtmp_buf;
634         int working_tree_file = !memcmp(elem->sha1, null_sha1, 20);
635         int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
636
637         /* Read the result of merge first */
638         if (!working_tree_file) {
639                 result = grab_blob(elem->sha1, &size);
640                 write_to_temp_file(ourtmp, result, size);
641         }
642         else {
643                 /* Used by diff-tree to read from the working tree */
644                 struct stat st;
645                 int fd;
646                 ourtmp = elem->path;
647                 if (0 <= (fd = open(ourtmp, O_RDONLY)) &&
648                     !fstat(fd, &st)) {
649                         int len = st.st_size;
650                         int cnt = 0;
651
652                         elem->mode = DIFF_FILE_CANON_MODE(st.st_mode);
653                         size = len;
654                         result = xmalloc(len + 1);
655                         while (cnt < len) {
656                                 int done = xread(fd, result+cnt, len-cnt);
657                                 if (done == 0)
658                                         break;
659                                 if (done < 0)
660                                         die("read error '%s'", ourtmp);
661                                 cnt += done;
662                         }
663                         result[len] = 0;
664                 }
665                 else {
666                         /* deleted file */
667                         size = 0;
668                         elem->mode = 0;
669                         result = xmalloc(1);
670                         result[0] = 0;
671                         ourtmp = "/dev/null";
672                 }
673                 if (0 <= fd)
674                         close(fd);
675         }
676
677         for (cnt = 0, cp = result; cp - result < size; cp++) {
678                 if (*cp == '\n')
679                         cnt++;
680         }
681         if (size && result[size-1] != '\n')
682                 cnt++; /* incomplete line */
683
684         sline = xcalloc(cnt+1, sizeof(*sline));
685         ep = result;
686         sline[0].bol = result;
687         for (lno = 0; lno <= cnt; lno++) {
688                 sline[lno].lost_tail = &sline[lno].lost_head;
689                 sline[lno].flag = 0;
690         }
691         for (lno = 0, cp = result; cp - result < size; cp++) {
692                 if (*cp == '\n') {
693                         sline[lno].len = cp - sline[lno].bol;
694                         lno++;
695                         if (lno < cnt)
696                                 sline[lno].bol = cp + 1;
697                 }
698         }
699         if (size && result[size-1] != '\n')
700                 sline[cnt-1].len = size - (sline[cnt-1].bol - result);
701
702         sline[0].p_lno = xcalloc((cnt+1) * num_parent, sizeof(unsigned long));
703         for (lno = 0; lno < cnt; lno++)
704                 sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
705
706         for (i = 0; i < num_parent; i++) {
707                 int j;
708                 for (j = 0; j < i; j++) {
709                         if (!memcmp(elem->parent[i].sha1,
710                                     elem->parent[j].sha1, 20)) {
711                                 reuse_combine_diff(sline, cnt, i, j);
712                                 break;
713                         }
714                 }
715                 if (i <= j)
716                         combine_diff(elem->parent[i].sha1, ourtmp, sline,
717                                      cnt, i, num_parent);
718                 if (elem->parent[i].mode != elem->mode)
719                         mode_differs = 1;
720         }
721
722         show_hunks = make_hunks(sline, cnt, num_parent, dense);
723
724         if (show_hunks || mode_differs || working_tree_file) {
725                 const char *abb;
726
727                 if (header) {
728                         shown_header++;
729                         printf("%s%c", header, opt->line_termination);
730                 }
731                 printf("diff --%s ", dense ? "cc" : "combined");
732                 if (quote_c_style(elem->path, NULL, NULL, 0))
733                         quote_c_style(elem->path, NULL, stdout, 0);
734                 else
735                         printf("%s", elem->path);
736                 putchar('\n');
737                 printf("index ");
738                 for (i = 0; i < num_parent; i++) {
739                         abb = find_unique_abbrev(elem->parent[i].sha1,
740                                                  abbrev);
741                         printf("%s%s", i ? "," : "", abb);
742                 }
743                 abb = find_unique_abbrev(elem->sha1, abbrev);
744                 printf("..%s\n", abb);
745
746                 if (mode_differs) {
747                         int added = !!elem->mode;
748                         for (i = 0; added && i < num_parent; i++)
749                                 if (elem->parent[i].status !=
750                                     DIFF_STATUS_ADDED)
751                                         added = 0;
752                         if (added)
753                                 printf("new file mode %06o", elem->mode);
754                         else {
755                                 if (!elem->mode)
756                                         printf("deleted file ");
757                                 printf("mode ");
758                                 for (i = 0; i < num_parent; i++) {
759                                         printf("%s%06o", i ? "," : "",
760                                                elem->parent[i].mode);
761                                 }
762                                 if (elem->mode)
763                                         printf("..%06o", elem->mode);
764                         }
765                         putchar('\n');
766                 }
767                 dump_sline(sline, cnt, num_parent);
768         }
769         if (ourtmp == ourtmp_buf)
770                 unlink(ourtmp);
771         free(result);
772
773         for (i = 0; i < cnt; i++) {
774                 if (sline[i].lost_head) {
775                         struct lline *ll = sline[i].lost_head;
776                         while (ll) {
777                                 struct lline *tmp = ll;
778                                 ll = ll->next;
779                                 free(tmp);
780                         }
781                 }
782         }
783         free(sline[0].p_lno);
784         free(sline);
785         return shown_header;
786 }
787
788 #define COLONS "::::::::::::::::::::::::::::::::"
789
790 static void show_raw_diff(struct combine_diff_path *p, int num_parent, const char *header, struct diff_options *opt)
791 {
792         int i, offset, mod_type = 'A';
793         const char *prefix;
794         int line_termination, inter_name_termination;
795
796         line_termination = opt->line_termination;
797         inter_name_termination = '\t';
798         if (!line_termination)
799                 inter_name_termination = 0;
800
801         if (header)
802                 printf("%s%c", header, line_termination);
803
804         for (i = 0; i < num_parent; i++) {
805                 if (p->parent[i].mode)
806                         mod_type = 'M';
807         }
808         if (!p->mode)
809                 mod_type = 'D';
810
811         if (opt->output_format == DIFF_FORMAT_RAW) {
812                 offset = strlen(COLONS) - num_parent;
813                 if (offset < 0)
814                         offset = 0;
815                 prefix = COLONS + offset;
816
817                 /* Show the modes */
818                 for (i = 0; i < num_parent; i++) {
819                         printf("%s%06o", prefix, p->parent[i].mode);
820                         prefix = " ";
821                 }
822                 printf("%s%06o", prefix, p->mode);
823
824                 /* Show sha1's */
825                 for (i = 0; i < num_parent; i++)
826                         printf(" %s", diff_unique_abbrev(p->parent[i].sha1,
827                                                          opt->abbrev));
828                 printf(" %s ", diff_unique_abbrev(p->sha1, opt->abbrev));
829         }
830
831         if (opt->output_format == DIFF_FORMAT_RAW ||
832             opt->output_format == DIFF_FORMAT_NAME_STATUS) {
833                 for (i = 0; i < num_parent; i++)
834                         putchar(p->parent[i].status);
835                 putchar(inter_name_termination);
836         }
837
838         if (line_termination) {
839                 if (quote_c_style(p->path, NULL, NULL, 0))
840                         quote_c_style(p->path, NULL, stdout, 0);
841                 else
842                         printf("%s", p->path);
843                 putchar(line_termination);
844         }
845         else {
846                 printf("%s%c", p->path, line_termination);
847         }
848 }
849
850 int show_combined_diff(struct combine_diff_path *p,
851                        int num_parent,
852                        int dense,
853                        const char *header,
854                        struct diff_options *opt)
855 {
856         if (!p->len)
857                 return 0;
858         switch (opt->output_format) {
859         case DIFF_FORMAT_RAW:
860         case DIFF_FORMAT_NAME_STATUS:
861         case DIFF_FORMAT_NAME:
862                 show_raw_diff(p, num_parent, header, opt);
863                 return 1;
864
865         default:
866         case DIFF_FORMAT_PATCH:
867                 return show_patch_diff(p, num_parent, dense, header, opt);
868         }
869 }
870
871 const char *diff_tree_combined_merge(const unsigned char *sha1,
872                              const char *header, int dense,
873                              struct diff_options *opt)
874 {
875         struct commit *commit = lookup_commit(sha1);
876         struct diff_options diffopts;
877         struct commit_list *parents;
878         struct combine_diff_path *p, *paths = NULL;
879         int num_parent, i, num_paths;
880
881         diffopts = *opt;
882         diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
883         diffopts.recursive = 1;
884
885         /* count parents */
886         for (parents = commit->parents, num_parent = 0;
887              parents;
888              parents = parents->next, num_parent++)
889                 ; /* nothing */
890
891         /* find set of paths that everybody touches */
892         for (parents = commit->parents, i = 0;
893              parents;
894              parents = parents->next, i++) {
895                 struct commit *parent = parents->item;
896                 diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
897                                &diffopts);
898                 diffcore_std(&diffopts);
899                 paths = intersect_paths(paths, i, num_parent);
900                 diff_flush(&diffopts);
901         }
902
903         /* find out surviving paths */
904         for (num_paths = 0, p = paths; p; p = p->next) {
905                 if (p->len)
906                         num_paths++;
907         }
908         if (num_paths) {
909                 for (p = paths; p; p = p->next) {
910                         if (show_combined_diff(p, num_parent, dense,
911                                                header, opt))
912                                 header = NULL;
913                 }
914         }
915
916         /* Clean things up */
917         while (paths) {
918                 struct combine_diff_path *tmp = paths;
919                 paths = paths->next;
920                 free(tmp);
921         }
922         return header;
923 }