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