Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
3
4 #include "git-compat-util.h"
5 #include "odb.h"
6 #include "commit.h"
7 #include "convert.h"
8 #include "diff.h"
9 #include "diffcore.h"
10 #include "environment.h"
11 #include "hex.h"
12 #include "object-name.h"
13 #include "quote.h"
14 #include "xdiff-interface.h"
15 #include "xdiff/xmacros.h"
16 #include "log-tree.h"
17 #include "refs.h"
18 #include "tree.h"
19 #include "userdiff.h"
20 #include "oid-array.h"
21 #include "revision.h"
22
23 static int compare_paths(const struct combine_diff_path *one,
24 const struct diff_filespec *two)
25 {
26 if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
27 return strcmp(one->path, two->path);
28
29 return base_name_compare(one->path, strlen(one->path), one->mode,
30 two->path, strlen(two->path), two->mode);
31 }
32
33 static int filename_changed(char status)
34 {
35 return status == 'R' || status == 'C';
36 }
37
38 static struct combine_diff_path *intersect_paths(
39 struct combine_diff_path *curr,
40 int n,
41 int num_parent,
42 int combined_all_paths)
43 {
44 struct diff_queue_struct *q = &diff_queued_diff;
45 struct combine_diff_path *p, **tail = &curr;
46 int i, j, cmp;
47
48 if (!n) {
49 for (i = 0; i < q->nr; i++) {
50 if (diff_unmodified_pair(q->queue[i]))
51 continue;
52 p = combine_diff_path_new(q->queue[i]->two->path,
53 strlen(q->queue[i]->two->path),
54 q->queue[i]->two->mode,
55 &q->queue[i]->two->oid,
56 num_parent);
57 oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
58 p->parent[n].mode = q->queue[i]->one->mode;
59 p->parent[n].status = q->queue[i]->status;
60
61 if (combined_all_paths &&
62 filename_changed(p->parent[n].status)) {
63 p->parent[n].path = xstrdup(q->queue[i]->one->path);
64 }
65 *tail = p;
66 tail = &p->next;
67 }
68 return curr;
69 }
70
71 /*
72 * paths in curr (linked list) and q->queue[] (array) are
73 * both sorted in the tree order.
74 */
75 i = 0;
76 while ((p = *tail) != NULL) {
77 cmp = ((i >= q->nr)
78 ? -1 : compare_paths(p, q->queue[i]->two));
79
80 if (cmp < 0) {
81 /* p->path not in q->queue[]; drop it */
82 *tail = p->next;
83 for (j = 0; j < num_parent; j++)
84 free(p->parent[j].path);
85 free(p);
86 continue;
87 }
88
89 if (cmp > 0) {
90 /* q->queue[i] not in p->path; skip it */
91 i++;
92 continue;
93 }
94
95 oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
96 p->parent[n].mode = q->queue[i]->one->mode;
97 p->parent[n].status = q->queue[i]->status;
98 if (combined_all_paths &&
99 filename_changed(p->parent[n].status))
100 p->parent[n].path = xstrdup(q->queue[i]->one->path);
101
102 tail = &p->next;
103 i++;
104 }
105 return curr;
106 }
107
108 /* Lines lost from parent */
109 struct lline {
110 struct lline *next, *prev;
111 int len;
112 unsigned long parent_map;
113 char line[FLEX_ARRAY];
114 };
115
116 /* Lines lost from current parent (before coalescing) */
117 struct plost {
118 struct lline *lost_head, *lost_tail;
119 int len;
120 };
121
122 /* Lines surviving in the merge result */
123 struct sline {
124 /* Accumulated and coalesced lost lines */
125 struct lline *lost;
126 int lenlost;
127 struct plost plost;
128 char *bol;
129 int len;
130 /* bit 0 up to (N-1) are on if the parent has this line (i.e.
131 * we did not change it).
132 * bit N is used for "interesting" lines, including context.
133 * bit (N+1) is used for "do not show deletion before this".
134 */
135 unsigned long flag;
136 unsigned long *p_lno;
137 };
138
139 static int match_string_spaces(const char *line1, int len1,
140 const char *line2, int len2,
141 long flags)
142 {
143 if (flags & XDF_WHITESPACE_FLAGS) {
144 for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
145 for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
146 }
147
148 if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
149 return (len1 == len2 && !memcmp(line1, line2, len1));
150
151 while (len1 > 0 && len2 > 0) {
152 len1--;
153 len2--;
154 if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
155 if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
156 (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
157 return 0;
158
159 for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
160 for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
161 }
162 if (line1[len1] != line2[len2])
163 return 0;
164 }
165
166 if (flags & XDF_IGNORE_WHITESPACE) {
167 /* Consume remaining spaces */
168 for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
169 for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
170 }
171
172 /* We matched full line1 and line2 */
173 if (!len1 && !len2)
174 return 1;
175
176 return 0;
177 }
178
179 enum coalesce_direction { MATCH, BASE, NEW };
180
181 /* Coalesce new lines into base by finding LCS */
182 static struct lline *coalesce_lines(struct lline *base, int *lenbase,
183 struct lline *newline, int lennew,
184 unsigned long parent, long flags)
185 {
186 int **lcs;
187 enum coalesce_direction **directions;
188 struct lline *baseend, *newend = NULL;
189 int i, j, origbaselen = *lenbase;
190
191 if (!newline)
192 return base;
193
194 if (!base) {
195 *lenbase = lennew;
196 return newline;
197 }
198
199 /*
200 * Coalesce new lines into base by finding the LCS
201 * - Create the table to run dynamic programming
202 * - Compute the LCS
203 * - Then reverse read the direction structure:
204 * - If we have MATCH, assign parent to base flag, and consume
205 * both baseend and newend
206 * - Else if we have BASE, consume baseend
207 * - Else if we have NEW, insert newend lline into base and
208 * consume newend
209 */
210 CALLOC_ARRAY(lcs, st_add(origbaselen, 1));
211 CALLOC_ARRAY(directions, st_add(origbaselen, 1));
212 for (i = 0; i < origbaselen + 1; i++) {
213 CALLOC_ARRAY(lcs[i], st_add(lennew, 1));
214 CALLOC_ARRAY(directions[i], st_add(lennew, 1));
215 directions[i][0] = BASE;
216 }
217 for (j = 1; j < lennew + 1; j++)
218 directions[0][j] = NEW;
219
220 for (i = 1, baseend = base; i < origbaselen + 1; i++) {
221 for (j = 1, newend = newline; j < lennew + 1; j++) {
222 if (match_string_spaces(baseend->line, baseend->len,
223 newend->line, newend->len, flags)) {
224 lcs[i][j] = lcs[i - 1][j - 1] + 1;
225 directions[i][j] = MATCH;
226 } else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
227 lcs[i][j] = lcs[i][j - 1];
228 directions[i][j] = NEW;
229 } else {
230 lcs[i][j] = lcs[i - 1][j];
231 directions[i][j] = BASE;
232 }
233 if (newend->next)
234 newend = newend->next;
235 }
236 if (baseend->next)
237 baseend = baseend->next;
238 }
239
240 for (i = 0; i < origbaselen + 1; i++)
241 free(lcs[i]);
242 free(lcs);
243
244 /* At this point, baseend and newend point to the end of each lists */
245 i--;
246 j--;
247 while (i != 0 || j != 0) {
248 if (directions[i][j] == MATCH) {
249 baseend->parent_map |= 1<<parent;
250 baseend = baseend->prev;
251 newend = newend->prev;
252 i--;
253 j--;
254 } else if (directions[i][j] == NEW) {
255 struct lline *lline;
256
257 lline = newend;
258 /* Remove lline from new list and update newend */
259 if (lline->prev)
260 lline->prev->next = lline->next;
261 else
262 newline = lline->next;
263 if (lline->next)
264 lline->next->prev = lline->prev;
265
266 newend = lline->prev;
267 j--;
268
269 /* Add lline to base list */
270 if (baseend) {
271 lline->next = baseend->next;
272 lline->prev = baseend;
273 if (lline->prev)
274 lline->prev->next = lline;
275 }
276 else {
277 lline->next = base;
278 base = lline;
279 }
280 (*lenbase)++;
281
282 if (lline->next)
283 lline->next->prev = lline;
284
285 } else {
286 baseend = baseend->prev;
287 i--;
288 }
289 }
290
291 newend = newline;
292 while (newend) {
293 struct lline *lline = newend;
294 newend = newend->next;
295 free(lline);
296 }
297
298 for (i = 0; i < origbaselen + 1; i++)
299 free(directions[i]);
300 free(directions);
301
302 return base;
303 }
304
305 static char *grab_blob(struct repository *r,
306 const struct object_id *oid, unsigned int mode,
307 unsigned long *size, struct userdiff_driver *textconv,
308 const char *path)
309 {
310 char *blob;
311 enum object_type type;
312
313 if (S_ISGITLINK(mode)) {
314 struct strbuf buf = STRBUF_INIT;
315 strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid));
316 *size = buf.len;
317 blob = strbuf_detach(&buf, NULL);
318 } else if (is_null_oid(oid)) {
319 /* deleted blob */
320 *size = 0;
321 return xcalloc(1, 1);
322 } else if (textconv) {
323 struct diff_filespec *df = alloc_filespec(path);
324 fill_filespec(df, oid, 1, mode);
325 *size = fill_textconv(r, textconv, df, &blob);
326 free_filespec(df);
327 } else {
328 size_t size_st = 0;
329 blob = odb_read_object(r->objects, oid, &type, &size_st);
330 *size = cast_size_t_to_ulong(size_st);
331 if (!blob)
332 die(_("unable to read %s"), oid_to_hex(oid));
333 if (type != OBJ_BLOB)
334 die("object '%s' is not a blob!", oid_to_hex(oid));
335 }
336 return blob;
337 }
338
339 static void append_lost(struct sline *sline, int n, const char *line, int len)
340 {
341 struct lline *lline;
342 unsigned long this_mask = (1UL<<n);
343 if (line[len-1] == '\n')
344 len--;
345
346 FLEX_ALLOC_MEM(lline, line, line, len);
347 lline->len = len;
348 lline->next = NULL;
349 lline->prev = sline->plost.lost_tail;
350 if (lline->prev)
351 lline->prev->next = lline;
352 else
353 sline->plost.lost_head = lline;
354 sline->plost.lost_tail = lline;
355 sline->plost.len++;
356 lline->parent_map = this_mask;
357 }
358
359 struct combine_diff_state {
360 unsigned int lno;
361 int ob, on, nb, nn;
362 unsigned long nmask;
363 int num_parent;
364 int n;
365 struct sline *sline;
366 struct sline *lost_bucket;
367 };
368
369 static void consume_hunk(void *state_,
370 long ob, long on,
371 long nb, long nn,
372 const char *func UNUSED, long funclen UNUSED)
373 {
374 struct combine_diff_state *state = state_;
375
376 state->ob = ob;
377 state->on = on;
378 state->nb = nb;
379 state->nn = nn;
380 state->lno = state->nb;
381 if (state->nn == 0) {
382 /* @@ -X,Y +N,0 @@ removed Y lines
383 * that would have come *after* line N
384 * in the result. Our lost buckets hang
385 * to the line after the removed lines,
386 *
387 * Note that this is correct even when N == 0,
388 * in which case the hunk removes the first
389 * line in the file.
390 */
391 state->lost_bucket = &state->sline[state->nb];
392 if (!state->nb)
393 state->nb = 1;
394 } else {
395 state->lost_bucket = &state->sline[state->nb-1];
396 }
397 if (!state->sline[state->nb-1].p_lno)
398 CALLOC_ARRAY(state->sline[state->nb - 1].p_lno,
399 state->num_parent);
400 state->sline[state->nb-1].p_lno[state->n] = state->ob;
401 }
402
403 static int consume_line(void *state_, char *line, unsigned long len)
404 {
405 struct combine_diff_state *state = state_;
406 if (!state->lost_bucket)
407 return 0; /* not in any hunk yet */
408 switch (line[0]) {
409 case '-':
410 append_lost(state->lost_bucket, state->n, line+1, len-1);
411 break;
412 case '+':
413 state->sline[state->lno-1].flag |= state->nmask;
414 state->lno++;
415 break;
416 }
417 return 0;
418 }
419
420 static void combine_diff(struct repository *r,
421 const struct object_id *parent, unsigned int mode,
422 mmfile_t *result_file,
423 struct sline *sline, unsigned int cnt, int n,
424 int num_parent, int result_deleted,
425 struct userdiff_driver *textconv,
426 const char *path, long flags)
427 {
428 unsigned int p_lno, lno;
429 unsigned long nmask = (1UL << n);
430 xpparam_t xpp;
431 xdemitconf_t xecfg;
432 mmfile_t parent_file;
433 struct combine_diff_state state;
434 unsigned long sz;
435
436 if (result_deleted)
437 return; /* result deleted */
438
439 parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path);
440 parent_file.size = sz;
441 memset(&xpp, 0, sizeof(xpp));
442 xpp.flags = flags;
443 memset(&xecfg, 0, sizeof(xecfg));
444 memset(&state, 0, sizeof(state));
445 state.nmask = nmask;
446 state.sline = sline;
447 state.lno = 1;
448 state.num_parent = num_parent;
449 state.n = n;
450
451 if (xdi_diff_outf(&parent_file, result_file, consume_hunk,
452 consume_line, &state, &xpp, &xecfg))
453 die("unable to generate combined diff for %s",
454 oid_to_hex(parent));
455 free(parent_file.ptr);
456
457 /* Assign line numbers for this parent.
458 *
459 * sline[lno].p_lno[n] records the first line number
460 * (counting from 1) for parent N if the final hunk display
461 * started by showing sline[lno] (possibly showing the lost
462 * lines attached to it first).
463 */
464 for (lno = 0, p_lno = 1; lno <= cnt; lno++) {
465 struct lline *ll;
466 sline[lno].p_lno[n] = p_lno;
467
468 /* Coalesce new lines */
469 if (sline[lno].plost.lost_head) {
470 struct sline *sl = &sline[lno];
471 sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
472 sl->plost.lost_head,
473 sl->plost.len, n, flags);
474 sl->plost.lost_head = sl->plost.lost_tail = NULL;
475 sl->plost.len = 0;
476 }
477
478 /* How many lines would this sline advance the p_lno? */
479 ll = sline[lno].lost;
480 while (ll) {
481 if (ll->parent_map & nmask)
482 p_lno++; /* '-' means parent had it */
483 ll = ll->next;
484 }
485 if (lno < cnt && !(sline[lno].flag & nmask))
486 p_lno++; /* no '+' means parent had it */
487 }
488 sline[lno].p_lno[n] = p_lno; /* trailer */
489 }
490
491 static unsigned long context = 3;
492 static char combine_marker = '@';
493
494 static int interesting(struct sline *sline, unsigned long all_mask)
495 {
496 /* If some parents lost lines here, or if we have added to
497 * some parent, it is interesting.
498 */
499 return ((sline->flag & all_mask) || sline->lost);
500 }
501
502 static unsigned long adjust_hunk_tail(struct sline *sline,
503 unsigned long all_mask,
504 unsigned long hunk_begin,
505 unsigned long i)
506 {
507 /* i points at the first uninteresting line. If the last line
508 * of the hunk was interesting only because it has some
509 * deletion, then it is not all that interesting for the
510 * purpose of giving trailing context lines. This is because
511 * we output '-' line and then unmodified sline[i-1] itself in
512 * that case which gives us one extra context line.
513 */
514 if ((hunk_begin + 1 <= i) && !(sline[i-1].flag & all_mask))
515 i--;
516 return i;
517 }
518
519 static unsigned long find_next(struct sline *sline,
520 unsigned long mark,
521 unsigned long i,
522 unsigned long cnt,
523 int look_for_uninteresting)
524 {
525 /* We have examined up to i-1 and are about to look at i.
526 * Find next interesting or uninteresting line. Here,
527 * "interesting" does not mean interesting(), but marked by
528 * the give_context() function below (i.e. it includes context
529 * lines that are not interesting to interesting() function
530 * that are surrounded by interesting() ones.
531 */
532 while (i <= cnt)
533 if (look_for_uninteresting
534 ? !(sline[i].flag & mark)
535 : (sline[i].flag & mark))
536 return i;
537 else
538 i++;
539 return i;
540 }
541
542 static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
543 {
544 unsigned long all_mask = (1UL<<num_parent) - 1;
545 unsigned long mark = (1UL<<num_parent);
546 unsigned long no_pre_delete = (2UL<<num_parent);
547 unsigned long i;
548
549 /* Two groups of interesting lines may have a short gap of
550 * uninteresting lines. Connect such groups to give them a
551 * bit of context.
552 *
553 * We first start from what the interesting() function says,
554 * and mark them with "mark", and paint context lines with the
555 * mark. So interesting() would still say false for such context
556 * lines but they are treated as "interesting" in the end.
557 */
558 i = find_next(sline, mark, 0, cnt, 0);
559 if (cnt < i)
560 return 0;
561
562 while (i <= cnt) {
563 unsigned long j = (context < i) ? (i - context) : 0;
564 unsigned long k;
565
566 /* Paint a few lines before the first interesting line. */
567 while (j < i) {
568 if (!(sline[j].flag & mark))
569 sline[j].flag |= no_pre_delete;
570 sline[j++].flag |= mark;
571 }
572
573 again:
574 /* we know up to i is to be included. where does the
575 * next uninteresting one start?
576 */
577 j = find_next(sline, mark, i, cnt, 1);
578 if (cnt < j)
579 break; /* the rest are all interesting */
580
581 /* lookahead context lines */
582 k = find_next(sline, mark, j, cnt, 0);
583 j = adjust_hunk_tail(sline, all_mask, i, j);
584
585 if (k < j + context) {
586 /* k is interesting and [j,k) are not, but
587 * paint them interesting because the gap is small.
588 */
589 while (j < k)
590 sline[j++].flag |= mark;
591 i = k;
592 goto again;
593 }
594
595 /* j is the first uninteresting line and there is
596 * no overlap beyond it within context lines. Paint
597 * the trailing edge a bit.
598 */
599 i = k;
600 k = (j + context < cnt+1) ? j + context : cnt+1;
601 while (j < k)
602 sline[j++].flag |= mark;
603 }
604 return 1;
605 }
606
607 static int make_hunks(struct sline *sline, unsigned long cnt,
608 int num_parent, int dense)
609 {
610 unsigned long all_mask = (1UL<<num_parent) - 1;
611 unsigned long mark = (1UL<<num_parent);
612 unsigned long i;
613 int has_interesting = 0;
614
615 for (i = 0; i <= cnt; i++) {
616 if (interesting(&sline[i], all_mask))
617 sline[i].flag |= mark;
618 else
619 sline[i].flag &= ~mark;
620 }
621 if (!dense)
622 return give_context(sline, cnt, num_parent);
623
624 /* Look at each hunk, and if we have changes from only one
625 * parent, or the changes are the same from all but one
626 * parent, mark that uninteresting.
627 */
628 i = 0;
629 while (i <= cnt) {
630 unsigned long j, hunk_begin, hunk_end;
631 unsigned long same_diff;
632 while (i <= cnt && !(sline[i].flag & mark))
633 i++;
634 if (cnt < i)
635 break; /* No more interesting hunks */
636 hunk_begin = i;
637 for (j = i + 1; j <= cnt; j++) {
638 if (!(sline[j].flag & mark)) {
639 /* Look beyond the end to see if there
640 * is an interesting line after this
641 * hunk within context span.
642 */
643 unsigned long la; /* lookahead */
644 int contin = 0;
645 la = adjust_hunk_tail(sline, all_mask,
646 hunk_begin, j);
647 la = (la + context < cnt + 1) ?
648 (la + context) : cnt + 1;
649 while (la && j <= --la) {
650 if (sline[la].flag & mark) {
651 contin = 1;
652 break;
653 }
654 }
655 if (!contin)
656 break;
657 j = la;
658 }
659 }
660 hunk_end = j;
661
662 /* [i..hunk_end) are interesting. Now is it really
663 * interesting? We check if there are only two versions
664 * and the result matches one of them. That is, we look
665 * at:
666 * (+) line, which records lines added to which parents;
667 * this line appears in the result.
668 * (-) line, which records from what parents the line
669 * was removed; this line does not appear in the result.
670 * then check the set of parents the result has difference
671 * from, from all lines. If there are lines that have
672 * different set of parents that the result has differences
673 * from, that means we have more than two versions.
674 *
675 * Even when we have only two versions, if the result does
676 * not match any of the parents, the it should be considered
677 * interesting. In such a case, we would have all '+' line.
678 * After passing the above "two versions" test, that would
679 * appear as "the same set of parents" to be "all parents".
680 */
681 same_diff = 0;
682 has_interesting = 0;
683 for (j = i; j < hunk_end && !has_interesting; j++) {
684 unsigned long this_diff = sline[j].flag & all_mask;
685 struct lline *ll = sline[j].lost;
686 if (this_diff) {
687 /* This has some changes. Is it the
688 * same as others?
689 */
690 if (!same_diff)
691 same_diff = this_diff;
692 else if (same_diff != this_diff) {
693 has_interesting = 1;
694 break;
695 }
696 }
697 while (ll && !has_interesting) {
698 /* Lost this line from these parents;
699 * who are they? Are they the same?
700 */
701 this_diff = ll->parent_map;
702 if (!same_diff)
703 same_diff = this_diff;
704 else if (same_diff != this_diff) {
705 has_interesting = 1;
706 }
707 ll = ll->next;
708 }
709 }
710
711 if (!has_interesting && same_diff != all_mask) {
712 /* This hunk is not that interesting after all */
713 for (j = hunk_begin; j < hunk_end; j++)
714 sline[j].flag &= ~mark;
715 }
716 i = hunk_end;
717 }
718
719 has_interesting = give_context(sline, cnt, num_parent);
720 return has_interesting;
721 }
722
723 static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, int n, unsigned long null_context)
724 {
725 l0 = sline[l0].p_lno[n];
726 l1 = sline[l1].p_lno[n];
727 printf(" -%lu,%lu", l0, l1-l0-null_context);
728 }
729
730 static int hunk_comment_line(const char *bol)
731 {
732 int ch;
733
734 if (!bol)
735 return 0;
736 ch = *bol & 0xff;
737 return (isalpha(ch) || ch == '_' || ch == '$');
738 }
739
740 static void show_line_to_eol(const char *line, int len, const char *reset)
741 {
742 int saw_cr_at_eol = 0;
743 if (len < 0)
744 len = strlen(line);
745 saw_cr_at_eol = (len && line[len-1] == '\r');
746
747 printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
748 reset,
749 saw_cr_at_eol ? "\r" : "");
750 }
751
752 static void dump_sline(struct sline *sline, const char *line_prefix,
753 unsigned long cnt, int num_parent,
754 enum git_colorbool use_color, int result_deleted)
755 {
756 unsigned long mark = (1UL<<num_parent);
757 unsigned long no_pre_delete = (2UL<<num_parent);
758 int i;
759 unsigned long lno = 0;
760 const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
761 const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO);
762 const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW);
763 const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD);
764 const char *c_context = diff_get_color(use_color, DIFF_CONTEXT);
765 const char *c_reset = diff_get_color(use_color, DIFF_RESET);
766
767 if (result_deleted)
768 return; /* result deleted */
769
770 while (1) {
771 unsigned long hunk_end;
772 unsigned long rlines;
773 const char *hunk_comment = NULL;
774 unsigned long null_context = 0;
775
776 while (lno <= cnt && !(sline[lno].flag & mark)) {
777 if (hunk_comment_line(sline[lno].bol))
778 hunk_comment = sline[lno].bol;
779 lno++;
780 }
781 if (cnt < lno)
782 break;
783 else {
784 for (hunk_end = lno + 1; hunk_end <= cnt; hunk_end++)
785 if (!(sline[hunk_end].flag & mark))
786 break;
787 }
788 rlines = hunk_end - lno;
789 if (cnt < hunk_end)
790 rlines--; /* pointing at the last delete hunk */
791
792 if (!context) {
793 /*
794 * Even when running with --unified=0, all
795 * lines in the hunk needs to be processed in
796 * the loop below in order to show the
797 * deletion recorded in lost_head. However,
798 * we do not want to show the resulting line
799 * with all blank context markers in such a
800 * case. Compensate.
801 */
802 unsigned long j;
803 for (j = lno; j < hunk_end; j++)
804 if (!(sline[j].flag & (mark-1)))
805 null_context++;
806 rlines -= null_context;
807 }
808
809 printf("%s%s", line_prefix, c_frag);
810 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
811 for (i = 0; i < num_parent; i++)
812 show_parent_lno(sline, lno, hunk_end, i, null_context);
813 printf(" +%lu,%lu ", lno+1, rlines);
814 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
815
816 if (hunk_comment) {
817 int comment_end = 0;
818 for (i = 0; i < 40; i++) {
819 int ch = hunk_comment[i] & 0xff;
820 if (!ch || ch == '\n')
821 break;
822 if (!isspace(ch))
823 comment_end = i;
824 }
825 if (comment_end)
826 printf("%s%s %s%s", c_reset,
827 c_context, c_reset,
828 c_func);
829 for (i = 0; i < comment_end; i++)
830 putchar(hunk_comment[i]);
831 }
832
833 printf("%s\n", c_reset);
834 while (lno < hunk_end) {
835 struct lline *ll;
836 int j;
837 unsigned long p_mask;
838 struct sline *sl = &sline[lno++];
839 ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
840 while (ll) {
841 printf("%s%s", line_prefix, c_old);
842 for (j = 0; j < num_parent; j++) {
843 if (ll->parent_map & (1UL<<j))
844 putchar('-');
845 else
846 putchar(' ');
847 }
848 show_line_to_eol(ll->line, -1, c_reset);
849 ll = ll->next;
850 }
851 if (cnt < lno)
852 break;
853 p_mask = 1;
854 fputs(line_prefix, stdout);
855 if (!(sl->flag & (mark-1))) {
856 /*
857 * This sline was here to hang the
858 * lost lines in front of it.
859 */
860 if (!context)
861 continue;
862 fputs(c_context, stdout);
863 }
864 else
865 fputs(c_new, stdout);
866 for (j = 0; j < num_parent; j++) {
867 if (p_mask & sl->flag)
868 putchar('+');
869 else
870 putchar(' ');
871 p_mask <<= 1;
872 }
873 show_line_to_eol(sl->bol, sl->len, c_reset);
874 }
875 }
876 }
877
878 static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
879 int i, int j)
880 {
881 /* We have already examined parent j and we know parent i
882 * and parent j are the same, so reuse the combined result
883 * of parent j for parent i.
884 */
885 unsigned long lno, imask, jmask;
886 imask = (1UL<<i);
887 jmask = (1UL<<j);
888
889 for (lno = 0; lno <= cnt; lno++) {
890 struct lline *ll = sline->lost;
891 sline->p_lno[i] = sline->p_lno[j];
892 while (ll) {
893 if (ll->parent_map & jmask)
894 ll->parent_map |= imask;
895 ll = ll->next;
896 }
897 if (sline->flag & jmask)
898 sline->flag |= imask;
899 sline++;
900 }
901 /* the overall size of the file (sline[cnt]) */
902 sline->p_lno[i] = sline->p_lno[j];
903 }
904
905 static void dump_quoted_path(const char *head,
906 const char *prefix,
907 const char *path,
908 const char *line_prefix,
909 const char *c_meta, const char *c_reset)
910 {
911 static struct strbuf buf = STRBUF_INIT;
912
913 strbuf_reset(&buf);
914 strbuf_addstr(&buf, line_prefix);
915 strbuf_addstr(&buf, c_meta);
916 strbuf_addstr(&buf, head);
917 quote_two_c_style(&buf, prefix, path, 0);
918 strbuf_addstr(&buf, c_reset);
919 puts(buf.buf);
920 }
921
922 static void show_combined_header(struct combine_diff_path *elem,
923 int num_parent,
924 struct rev_info *rev,
925 const char *line_prefix,
926 int mode_differs,
927 int show_file_header)
928 {
929 struct diff_options *opt = &rev->diffopt;
930 int abbrev = opt->flags.full_index ? the_hash_algo->hexsz : DEFAULT_ABBREV;
931 const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
932 const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
933 const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
934 const char *c_reset = diff_get_color_opt(opt, DIFF_RESET);
935 const char *abb;
936 int added = 0;
937 int deleted = 0;
938 int i;
939 int dense = rev->dense_combined_merges;
940
941 if (rev->loginfo && !rev->no_commit_id)
942 show_log(rev);
943
944 dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
945 "", elem->path, line_prefix, c_meta, c_reset);
946 printf("%s%sindex ", line_prefix, c_meta);
947 for (i = 0; i < num_parent; i++) {
948 abb = repo_find_unique_abbrev(the_repository,
949 &elem->parent[i].oid, abbrev);
950 printf("%s%s", i ? "," : "", abb);
951 }
952 abb = repo_find_unique_abbrev(the_repository, &elem->oid, abbrev);
953 printf("..%s%s\n", abb, c_reset);
954
955 if (mode_differs) {
956 deleted = !elem->mode;
957
958 /* We say it was added if nobody had it */
959 added = !deleted;
960 for (i = 0; added && i < num_parent; i++)
961 if (elem->parent[i].status !=
962 DIFF_STATUS_ADDED)
963 added = 0;
964 if (added)
965 printf("%s%snew file mode %06o",
966 line_prefix, c_meta, elem->mode);
967 else {
968 if (deleted)
969 printf("%s%sdeleted file ",
970 line_prefix, c_meta);
971 printf("mode ");
972 for (i = 0; i < num_parent; i++) {
973 printf("%s%06o", i ? "," : "",
974 elem->parent[i].mode);
975 }
976 if (elem->mode)
977 printf("..%06o", elem->mode);
978 }
979 printf("%s\n", c_reset);
980 }
981
982 if (!show_file_header)
983 return;
984
985 if (rev->combined_all_paths) {
986 for (i = 0; i < num_parent; i++) {
987 const char *path = elem->parent[i].path ?
988 elem->parent[i].path :
989 elem->path;
990 if (elem->parent[i].status == DIFF_STATUS_ADDED)
991 dump_quoted_path("--- ", "", "/dev/null",
992 line_prefix, c_meta, c_reset);
993 else
994 dump_quoted_path("--- ", a_prefix, path,
995 line_prefix, c_meta, c_reset);
996 }
997 } else {
998 if (added)
999 dump_quoted_path("--- ", "", "/dev/null",
1000 line_prefix, c_meta, c_reset);
1001 else
1002 dump_quoted_path("--- ", a_prefix, elem->path,
1003 line_prefix, c_meta, c_reset);
1004 }
1005 if (deleted)
1006 dump_quoted_path("+++ ", "", "/dev/null",
1007 line_prefix, c_meta, c_reset);
1008 else
1009 dump_quoted_path("+++ ", b_prefix, elem->path,
1010 line_prefix, c_meta, c_reset);
1011 }
1012
1013 static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
1014 int working_tree_file,
1015 struct rev_info *rev)
1016 {
1017 struct diff_options *opt = &rev->diffopt;
1018 unsigned long result_size, cnt, lno;
1019 int result_deleted = 0;
1020 char *result, *cp;
1021 struct sline *sline; /* survived lines */
1022 int mode_differs = 0;
1023 int i, show_hunks;
1024 mmfile_t result_file;
1025 struct userdiff_driver *userdiff;
1026 struct userdiff_driver *textconv = NULL;
1027 int is_binary;
1028 const char *line_prefix = diff_line_prefix(opt);
1029
1030 context = opt->context;
1031 userdiff = userdiff_find_by_path(opt->repo->index, elem->path);
1032 if (!userdiff)
1033 userdiff = userdiff_find_by_name("default");
1034 if (opt->flags.allow_textconv)
1035 textconv = userdiff_get_textconv(opt->repo, userdiff);
1036
1037 /* Read the result of merge first */
1038 if (!working_tree_file)
1039 result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size,
1040 textconv, elem->path);
1041 else {
1042 /* Used by diff-tree to read from the working tree */
1043 struct stat st;
1044 int fd = -1;
1045
1046 if (lstat(elem->path, &st) < 0)
1047 goto deleted_file;
1048
1049 if (S_ISLNK(st.st_mode)) {
1050 struct strbuf buf = STRBUF_INIT;
1051
1052 if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
1053 error_errno("readlink(%s)", elem->path);
1054 return;
1055 }
1056 result_size = buf.len;
1057 result = strbuf_detach(&buf, NULL);
1058 elem->mode = canon_mode(st.st_mode);
1059 } else if (S_ISDIR(st.st_mode)) {
1060 struct object_id oid;
1061 if (repo_resolve_gitlink_ref(the_repository, elem->path,
1062 "HEAD", &oid) < 0)
1063 result = grab_blob(opt->repo, &elem->oid,
1064 elem->mode, &result_size,
1065 NULL, NULL);
1066 else
1067 result = grab_blob(opt->repo, &oid, elem->mode,
1068 &result_size, NULL, NULL);
1069 } else if (textconv) {
1070 struct diff_filespec *df = alloc_filespec(elem->path);
1071 fill_filespec(df, null_oid(the_hash_algo), 0, st.st_mode);
1072 result_size = fill_textconv(opt->repo, textconv, df, &result);
1073 free_filespec(df);
1074 } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
1075 size_t len = xsize_t(st.st_size);
1076 ssize_t done;
1077 int is_file, i;
1078
1079 elem->mode = canon_mode(st.st_mode);
1080 /* if symlinks don't work, assume symlink if all parents
1081 * are symlinks
1082 */
1083 is_file = repo_has_symlinks(rev->repo);
1084 for (i = 0; !is_file && i < num_parent; i++)
1085 is_file = !S_ISLNK(elem->parent[i].mode);
1086 if (!is_file)
1087 elem->mode = canon_mode(S_IFLNK);
1088
1089 result_size = len;
1090 result = xmallocz(len);
1091
1092 done = read_in_full(fd, result, len);
1093 if (done < 0)
1094 die_errno("read error '%s'", elem->path);
1095 else if (done < len)
1096 die("early EOF '%s'", elem->path);
1097
1098 /* If not a fake symlink, apply filters, e.g. autocrlf */
1099 if (is_file) {
1100 struct strbuf buf = STRBUF_INIT;
1101
1102 if (convert_to_git(rev->diffopt.repo->index,
1103 elem->path, result, len, &buf, global_conv_flags_eol)) {
1104 free(result);
1105 result = strbuf_detach(&buf, &len);
1106 result_size = len;
1107 }
1108 }
1109 }
1110 else {
1111 deleted_file:
1112 result_deleted = 1;
1113 result_size = 0;
1114 elem->mode = 0;
1115 result = xcalloc(1, 1);
1116 }
1117
1118 if (0 <= fd)
1119 close(fd);
1120 }
1121
1122 for (i = 0; i < num_parent; i++) {
1123 if (elem->parent[i].mode != elem->mode) {
1124 mode_differs = 1;
1125 break;
1126 }
1127 }
1128
1129 if (textconv)
1130 is_binary = 0;
1131 else if (userdiff->binary != -1)
1132 is_binary = userdiff->binary;
1133 else {
1134 is_binary = buffer_is_binary(result, result_size);
1135 for (i = 0; !is_binary && i < num_parent; i++) {
1136 char *buf;
1137 unsigned long size;
1138 buf = grab_blob(opt->repo,
1139 &elem->parent[i].oid,
1140 elem->parent[i].mode,
1141 &size, NULL, NULL);
1142 if (buffer_is_binary(buf, size))
1143 is_binary = 1;
1144 free(buf);
1145 }
1146 }
1147 if (is_binary) {
1148 show_combined_header(elem, num_parent, rev,
1149 line_prefix, mode_differs, 0);
1150 printf("Binary files differ\n");
1151 free(result);
1152 return;
1153 }
1154
1155 for (cnt = 0, cp = result; cp < result + result_size; cp++) {
1156 if (*cp == '\n')
1157 cnt++;
1158 }
1159 if (result_size && result[result_size-1] != '\n')
1160 cnt++; /* incomplete line */
1161
1162 CALLOC_ARRAY(sline, st_add(cnt, 2));
1163 sline[0].bol = result;
1164 for (lno = 0, cp = result; cp < result + result_size; cp++) {
1165 if (*cp == '\n') {
1166 sline[lno].len = cp - sline[lno].bol;
1167 lno++;
1168 if (lno < cnt)
1169 sline[lno].bol = cp + 1;
1170 }
1171 }
1172 if (result_size && result[result_size-1] != '\n')
1173 sline[cnt-1].len = result_size - (sline[cnt-1].bol - result);
1174
1175 result_file.ptr = result;
1176 result_file.size = result_size;
1177
1178 /*
1179 * Even p_lno[cnt+1] is valid -- that is for the end line number
1180 * for deletion hunk at the end.
1181 */
1182 CALLOC_ARRAY(sline[0].p_lno, st_mult(st_add(cnt, 2), num_parent));
1183 for (lno = 0; lno <= cnt; lno++)
1184 sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
1185
1186 for (i = 0; i < num_parent; i++) {
1187 int j;
1188 for (j = 0; j < i; j++) {
1189 if (oideq(&elem->parent[i].oid,
1190 &elem->parent[j].oid)) {
1191 reuse_combine_diff(sline, cnt, i, j);
1192 break;
1193 }
1194 }
1195 if (i <= j)
1196 combine_diff(opt->repo,
1197 &elem->parent[i].oid,
1198 elem->parent[i].mode,
1199 &result_file, sline,
1200 cnt, i, num_parent, result_deleted,
1201 textconv, elem->path, opt->xdl_opts);
1202 }
1203
1204 show_hunks = make_hunks(sline, cnt, num_parent, rev->dense_combined_merges);
1205
1206 if (show_hunks || mode_differs || working_tree_file) {
1207 show_combined_header(elem, num_parent, rev,
1208 line_prefix, mode_differs, 1);
1209 dump_sline(sline, line_prefix, cnt, num_parent,
1210 opt->use_color, result_deleted);
1211 }
1212 free(result);
1213
1214 for (lno = 0; lno < cnt + 2; lno++) {
1215 if (sline[lno].lost) {
1216 struct lline *ll = sline[lno].lost;
1217 while (ll) {
1218 struct lline *tmp = ll;
1219 ll = ll->next;
1220 free(tmp);
1221 }
1222 }
1223 }
1224 free(sline[0].p_lno);
1225 free(sline);
1226 }
1227
1228 static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
1229 {
1230 struct diff_options *opt = &rev->diffopt;
1231 int line_termination, inter_name_termination, i;
1232 const char *line_prefix = diff_line_prefix(opt);
1233
1234 line_termination = opt->line_termination;
1235 inter_name_termination = '\t';
1236 if (!line_termination)
1237 inter_name_termination = 0;
1238
1239 if (rev->loginfo && !rev->no_commit_id)
1240 show_log(rev);
1241
1242
1243 if (opt->output_format & DIFF_FORMAT_RAW) {
1244 printf("%s", line_prefix);
1245
1246 /* As many colons as there are parents */
1247 for (i = 0; i < num_parent; i++)
1248 putchar(':');
1249
1250 /* Show the modes */
1251 for (i = 0; i < num_parent; i++)
1252 printf("%06o ", p->parent[i].mode);
1253 printf("%06o", p->mode);
1254
1255 /* Show sha1's */
1256 for (i = 0; i < num_parent; i++)
1257 printf(" %s", diff_aligned_abbrev(&p->parent[i].oid,
1258 opt->abbrev));
1259 printf(" %s ", diff_aligned_abbrev(&p->oid, opt->abbrev));
1260 }
1261
1262 if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) {
1263 for (i = 0; i < num_parent; i++)
1264 putchar(p->parent[i].status);
1265 putchar(inter_name_termination);
1266 }
1267
1268 for (i = 0; i < num_parent; i++)
1269 if (rev->combined_all_paths) {
1270 const char *path = p->parent[i].path ?
1271 p->parent[i].path :
1272 p->path;
1273 write_name_quoted(path, stdout, inter_name_termination);
1274 }
1275 write_name_quoted(p->path, stdout, line_termination);
1276 }
1277
1278 /*
1279 * The result (p->elem) is from the working tree and their
1280 * parents are typically from multiple stages during a merge
1281 * (i.e. diff-files) or the state in HEAD and in the index
1282 * (i.e. diff-index).
1283 */
1284 void show_combined_diff(struct combine_diff_path *p,
1285 int num_parent,
1286 struct rev_info *rev)
1287 {
1288 struct diff_options *opt = &rev->diffopt;
1289
1290 if (opt->output_format & (DIFF_FORMAT_RAW |
1291 DIFF_FORMAT_NAME |
1292 DIFF_FORMAT_NAME_STATUS))
1293 show_raw_diff(p, num_parent, rev);
1294 else if (opt->output_format & DIFF_FORMAT_PATCH)
1295 show_patch_diff(p, num_parent, 1, rev);
1296 }
1297
1298 static void free_combined_pair(struct diff_filepair *pair)
1299 {
1300 free(pair->two);
1301 free(pair);
1302 }
1303
1304 /*
1305 * A combine_diff_path expresses N parents on the LHS against 1 merge
1306 * result. Synthesize a diff_filepair that has N entries on the "one"
1307 * side and 1 entry on the "two" side.
1308 *
1309 * In the future, we might want to add more data to combine_diff_path
1310 * so that we can fill fields we are ignoring (most notably, size) here,
1311 * but currently nobody uses it, so this should suffice for now.
1312 */
1313 static struct diff_filepair *combined_pair(struct combine_diff_path *p,
1314 int num_parent)
1315 {
1316 int i;
1317 struct diff_filepair *pair;
1318 struct diff_filespec *pool;
1319
1320 CALLOC_ARRAY(pair, 1);
1321 CALLOC_ARRAY(pool, st_add(num_parent, 1));
1322 pair->one = pool + 1;
1323 pair->two = pool;
1324
1325 for (i = 0; i < num_parent; i++) {
1326 pair->one[i].path = p->path;
1327 pair->one[i].mode = p->parent[i].mode;
1328 oidcpy(&pair->one[i].oid, &p->parent[i].oid);
1329 pair->one[i].oid_valid = !is_null_oid(&p->parent[i].oid);
1330 pair->one[i].has_more_entries = 1;
1331 }
1332 pair->one[num_parent - 1].has_more_entries = 0;
1333
1334 pair->two->path = p->path;
1335 pair->two->mode = p->mode;
1336 oidcpy(&pair->two->oid, &p->oid);
1337 pair->two->oid_valid = !is_null_oid(&p->oid);
1338 return pair;
1339 }
1340
1341 static void handle_combined_callback(struct diff_options *opt,
1342 struct combine_diff_path *paths,
1343 int num_parent,
1344 int num_paths)
1345 {
1346 struct combine_diff_path *p;
1347 struct diff_queue_struct q;
1348 int i;
1349
1350 CALLOC_ARRAY(q.queue, num_paths);
1351 q.alloc = num_paths;
1352 q.nr = num_paths;
1353 for (i = 0, p = paths; p; p = p->next)
1354 q.queue[i++] = combined_pair(p, num_parent);
1355 opt->format_callback(&q, opt, opt->format_callback_data);
1356 for (i = 0; i < num_paths; i++)
1357 free_combined_pair(q.queue[i]);
1358 free(q.queue);
1359 }
1360
1361 static const char *path_path(void *obj)
1362 {
1363 struct combine_diff_path *path = (struct combine_diff_path *)obj;
1364
1365 return path->path;
1366 }
1367
1368 /*
1369 * Diff stat formats which we always compute solely against the first parent.
1370 */
1371 #define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \
1372 | DIFF_FORMAT_SHORTSTAT \
1373 | DIFF_FORMAT_SUMMARY \
1374 | DIFF_FORMAT_DIRSTAT \
1375 | DIFF_FORMAT_DIFFSTAT)
1376
1377 /* find set of paths that every parent touches */
1378 static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
1379 const struct oid_array *parents,
1380 struct diff_options *opt,
1381 int combined_all_paths)
1382 {
1383 struct combine_diff_path *paths = NULL;
1384 int i, num_parent = parents->nr;
1385 int output_format = opt->output_format;
1386 char *orderfile = opt->orderfile;
1387
1388 opt->output_format = DIFF_FORMAT_NO_OUTPUT;
1389 /* tell diff_tree to emit paths in sorted (=tree) order */
1390 opt->orderfile = NULL;
1391
1392 /* D(A,P1...Pn) = D(A,P1) ^ ... ^ D(A,Pn) (wrt paths) */
1393 for (i = 0; i < num_parent; i++) {
1394 /*
1395 * show stat against the first parent even when doing
1396 * combined diff.
1397 */
1398 int stat_opt = output_format & STAT_FORMAT_MASK;
1399 if (i == 0 && stat_opt)
1400 opt->output_format = stat_opt;
1401 else
1402 opt->output_format = DIFF_FORMAT_NO_OUTPUT;
1403 diff_tree_oid(&parents->oid[i], oid, "", opt);
1404 diffcore_std(opt);
1405 paths = intersect_paths(paths, i, num_parent,
1406 combined_all_paths);
1407
1408 /* if showing diff, show it in requested order */
1409 if (opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
1410 orderfile) {
1411 diffcore_order(orderfile);
1412 }
1413
1414 diff_flush(opt);
1415 }
1416
1417 opt->output_format = output_format;
1418 opt->orderfile = orderfile;
1419 return paths;
1420 }
1421
1422
1423 /*
1424 * find set of paths that everybody touches, assuming diff is run without
1425 * rename/copy detection, etc, comparing all trees simultaneously (= faster).
1426 */
1427 static struct combine_diff_path *find_paths_multitree(
1428 const struct object_id *oid, const struct oid_array *parents,
1429 struct diff_options *opt)
1430 {
1431 int i, nparent = parents->nr;
1432 const struct object_id **parents_oid;
1433 struct combine_diff_path *paths;
1434 struct strbuf base;
1435
1436 ALLOC_ARRAY(parents_oid, nparent);
1437 for (i = 0; i < nparent; i++)
1438 parents_oid[i] = &parents->oid[i];
1439
1440 strbuf_init(&base, PATH_MAX);
1441 paths = diff_tree_paths(oid, parents_oid, nparent, &base, opt);
1442
1443 strbuf_release(&base);
1444 free(parents_oid);
1445 return paths;
1446 }
1447
1448 static int match_objfind(struct combine_diff_path *path,
1449 int num_parent,
1450 const struct oidset *set)
1451 {
1452 int i;
1453 if (oidset_contains(set, &path->oid))
1454 return 1;
1455 for (i = 0; i < num_parent; i++) {
1456 if (oidset_contains(set, &path->parent[i].oid))
1457 return 1;
1458 }
1459 return 0;
1460 }
1461
1462 static struct combine_diff_path *combined_objfind(struct diff_options *opt,
1463 struct combine_diff_path *paths,
1464 int num_parent)
1465 {
1466 struct combine_diff_path *ret = NULL, **tail = &ret;
1467 struct combine_diff_path *p = paths;
1468
1469 while (p) {
1470 struct combine_diff_path *next = p->next;
1471
1472 if (match_objfind(p, num_parent, opt->objfind)) {
1473 p->next = NULL;
1474 *tail = p;
1475 tail = &p->next;
1476 } else {
1477 free(p);
1478 }
1479 p = next;
1480 }
1481
1482 return ret;
1483 }
1484
1485 void diff_tree_combined(const struct object_id *oid,
1486 const struct oid_array *parents,
1487 struct rev_info *rev)
1488 {
1489 struct diff_options *opt = &rev->diffopt;
1490 struct diff_options diffopts;
1491 struct combine_diff_path *p, *paths;
1492 int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
1493 int need_generic_pathscan;
1494
1495 if (opt->ignore_regex_nr)
1496 die("combined diff and '%s' cannot be used together",
1497 "--ignore-matching-lines");
1498 if (opt->close_file)
1499 die("combined diff and '%s' cannot be used together",
1500 "--output");
1501
1502 /* nothing to do, if no parents */
1503 if (!num_parent)
1504 return;
1505
1506 show_log_first = !!rev->loginfo && !rev->no_commit_id;
1507 needsep = 0;
1508 if (show_log_first) {
1509 show_log(rev);
1510
1511 if (rev->verbose_header && opt->output_format &&
1512 opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
1513 !commit_format_is_empty(rev->commit_format))
1514 printf("%s%c", diff_line_prefix(opt),
1515 opt->line_termination);
1516 }
1517
1518 diffopts = *opt;
1519 copy_pathspec(&diffopts.pathspec, &opt->pathspec);
1520 diffopts.flags.allow_external = 0;
1521 if (!opt->flags.no_recursive_diff_tree_combined)
1522 diffopts.flags.recursive = 1;
1523
1524 /* find set of paths that everybody touches
1525 *
1526 * NOTE
1527 *
1528 * Diffcore transformations are bound to diff_filespec and logic
1529 * comparing two entries - i.e. they do not apply directly to combine
1530 * diff.
1531 *
1532 * If some of such transformations is requested - we launch generic
1533 * path scanning, which works significantly slower compared to
1534 * simultaneous all-trees-in-one-go scan in find_paths_multitree().
1535 *
1536 * TODO some of the filters could be ported to work on
1537 * combine_diff_paths - i.e. all functionality that skips paths, so in
1538 * theory, we could end up having only multitree path scanning.
1539 *
1540 * NOTE please keep this semantically in sync with diffcore_std()
1541 */
1542 need_generic_pathscan = opt->skip_stat_unmatch ||
1543 opt->flags.follow_renames ||
1544 opt->break_opt != -1 ||
1545 opt->detect_rename ||
1546 (opt->pickaxe_opts &
1547 (DIFF_PICKAXE_KINDS_MASK & ~DIFF_PICKAXE_KIND_OBJFIND)) ||
1548 opt->filter;
1549
1550 if (need_generic_pathscan) {
1551 /*
1552 * NOTE generic case also handles --stat, as it computes
1553 * diff(sha1,parent_i) for all i to do the job, specifically
1554 * for parent0.
1555 */
1556 paths = find_paths_generic(oid, parents, &diffopts,
1557 rev->combined_all_paths);
1558 }
1559 else {
1560 int stat_opt;
1561 paths = find_paths_multitree(oid, parents, &diffopts);
1562
1563 if (opt->pickaxe_opts & DIFF_PICKAXE_KIND_OBJFIND)
1564 paths = combined_objfind(opt, paths, num_parent);
1565
1566 /*
1567 * show stat against the first parent even
1568 * when doing combined diff.
1569 */
1570 stat_opt = opt->output_format & STAT_FORMAT_MASK;
1571 if (stat_opt) {
1572 diffopts.output_format = stat_opt;
1573
1574 diff_tree_oid(&parents->oid[0], oid, "", &diffopts);
1575 diffcore_std(&diffopts);
1576 if (opt->orderfile)
1577 diffcore_order(opt->orderfile);
1578 diff_flush(&diffopts);
1579 }
1580 }
1581
1582 /* find out number of surviving paths */
1583 for (num_paths = 0, p = paths; p; p = p->next)
1584 num_paths++;
1585
1586 /* order paths according to diffcore_order */
1587 if (opt->orderfile && num_paths) {
1588 struct obj_order *o;
1589
1590 ALLOC_ARRAY(o, num_paths);
1591 for (i = 0, p = paths; p; p = p->next, i++)
1592 o[i].obj = p;
1593 order_objects(opt->orderfile, path_path, o, num_paths);
1594 for (i = 0; i < num_paths - 1; i++) {
1595 p = o[i].obj;
1596 p->next = o[i+1].obj;
1597 }
1598
1599 p = o[num_paths-1].obj;
1600 p->next = NULL;
1601 paths = o[0].obj;
1602 free(o);
1603 }
1604
1605
1606 if (num_paths) {
1607 if (opt->output_format & (DIFF_FORMAT_RAW |
1608 DIFF_FORMAT_NAME |
1609 DIFF_FORMAT_NAME_STATUS)) {
1610 for (p = paths; p; p = p->next)
1611 show_raw_diff(p, num_parent, rev);
1612 needsep = 1;
1613 }
1614 else if (opt->output_format & STAT_FORMAT_MASK)
1615 needsep = 1;
1616 else if (opt->output_format & DIFF_FORMAT_CALLBACK)
1617 handle_combined_callback(opt, paths, num_parent, num_paths);
1618
1619 if (opt->output_format & DIFF_FORMAT_PATCH) {
1620 if (needsep)
1621 printf("%s%c", diff_line_prefix(opt),
1622 opt->line_termination);
1623 for (p = paths; p; p = p->next)
1624 show_patch_diff(p, num_parent, 0, rev);
1625 }
1626 }
1627
1628 /* Clean things up */
1629 while (paths) {
1630 struct combine_diff_path *tmp = paths;
1631 paths = paths->next;
1632 for (i = 0; i < num_parent; i++)
1633 free(tmp->parent[i].path);
1634 free(tmp);
1635 }
1636
1637 clear_pathspec(&diffopts.pathspec);
1638 }
1639
1640 void diff_tree_combined_merge(const struct commit *commit,
1641 struct rev_info *rev)
1642 {
1643 struct commit_list *parent = get_saved_parents(rev, commit);
1644 struct oid_array parents = OID_ARRAY_INIT;
1645
1646 while (parent) {
1647 oid_array_append(&parents, &parent->item->object.oid);
1648 parent = parent->next;
1649 }
1650 diff_tree_combined(&commit->object.oid, &parents, rev);
1651 oid_array_clear(&parents);
1652 }
1653
1654 struct combine_diff_path *combine_diff_path_new(const char *path,
1655 size_t path_len,
1656 unsigned int mode,
1657 const struct object_id *oid,
1658 size_t num_parents)
1659 {
1660 struct combine_diff_path *p;
1661 size_t parent_len = st_mult(sizeof(p->parent[0]), num_parents);
1662
1663 p = xmalloc(st_add4(sizeof(*p), path_len, 1, parent_len));
1664 p->path = (char *)&(p->parent[num_parents]);
1665 memcpy(p->path, path, path_len);
1666 p->path[path_len] = 0;
1667 p->next = NULL;
1668 p->mode = mode;
1669 oidcpy(&p->oid, oid);
1670
1671 memset(p->parent, 0, parent_len);
1672
1673 return p;
1674 }