diff.c 24.8 KB
Newer Older
1 2 3 4 5
/*
 * Copyright (C) 2005 Junio C Hamano
 */
#include <sys/types.h>
#include <sys/wait.h>
6
#include <signal.h>
7 8
#include "cache.h"
#include "diff.h"
9
#include "diffcore.h"
10

J
Junio C Hamano 已提交
11
static const char *diff_opts = "-pu";
12
static unsigned char null_sha1[20] = { 0, };
13 14

static int reverse_diff;
15
static int use_size_cache;
16

17
static const char *external_diff(void)
18
{
J
Junio C Hamano 已提交
19
	static const char *external_diff_cmd = NULL;
20 21 22 23 24
	static int done_preparing = 0;

	if (done_preparing)
		return external_diff_cmd;

25 26 27 28 29 30 31 32
	/*
	 * Default values above are meant to match the
	 * Linux kernel development style.  Examples of
	 * alternative styles you can specify via environment
	 * variables are:
	 *
	 * GIT_DIFF_OPTS="-c";
	 */
J
Junio C Hamano 已提交
33 34
	if (gitenv("GIT_EXTERNAL_DIFF"))
		external_diff_cmd = gitenv("GIT_EXTERNAL_DIFF");
35 36

	/* In case external diff fails... */
J
Junio C Hamano 已提交
37
	diff_opts = gitenv("GIT_DIFF_OPTS") ? : diff_opts;
38 39 40

	done_preparing = 1;
	return external_diff_cmd;
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
}

/* Help to copy the thing properly quoted for the shell safety.
 * any single quote is replaced with '\'', and the caller is
 * expected to enclose the result within a single quote pair.
 *
 * E.g.
 *  original     sq_expand     result
 *  name     ==> name      ==> 'name'
 *  a b      ==> a b       ==> 'a b'
 *  a'b      ==> a'\''b    ==> 'a'\''b'
 */
static char *sq_expand(const char *src)
{
	static char *buf = NULL;
	int cnt, c;
	const char *cp;
	char *bp;

J
Junio C Hamano 已提交
60
	/* count bytes needed to store the quoted string. */
61 62 63 64
	for (cnt = 1, cp = src; *cp; cnt++, cp++)
		if (*cp == '\'')
			cnt += 3;

65
	buf = xmalloc(cnt);
66 67 68 69 70 71 72 73 74 75 76 77 78
	bp = buf;
	while ((c = *src++)) {
		if (c != '\'')
			*bp++ = c;
		else {
			bp = strcpy(bp, "'\\''");
			bp += 4;
		}
	}
	*bp = 0;
	return buf;
}

79
static struct diff_tempfile {
80
	const char *name; /* filename external diff should read from */
81 82 83 84 85
	char hex[41];
	char mode[10];
	char tmp_path[50];
} diff_temp[2];

J
Junio C Hamano 已提交
86 87
static void builtin_diff(const char *name_a,
			 const char *name_b,
J
Junio C Hamano 已提交
88
			 struct diff_tempfile *temp,
89
			 const char *xfrm_msg)
90
{
91
	int i, next_at, cmd_size;
92
	const char *diff_cmd = "diff -L'%s%s' -L'%s%s'";
93
	const char *diff_arg  = "'%s' '%s'||:"; /* "||:" is to return 0 */
94 95 96
	const char *input_name_sq[2];
	const char *path0[2];
	const char *path1[2];
J
Junio C Hamano 已提交
97
	const char *name_sq[2];
98
	char *cmd;
J
Junio C Hamano 已提交
99 100 101 102

	name_sq[0] = sq_expand(name_a);
	name_sq[1] = sq_expand(name_b);

103 104
	/* diff_cmd and diff_arg have 6 %s in total which makes
	 * the sum of these strings 12 bytes larger than required.
105
	 * we use 2 spaces around diff-opts, and we need to count
106
	 * terminating NUL, so we subtract 9 here.
107
	 */
108
	cmd_size = (strlen(diff_cmd) + strlen(diff_opts) +
109
			strlen(diff_arg) - 9);
110 111 112 113 114 115
	for (i = 0; i < 2; i++) {
		input_name_sq[i] = sq_expand(temp[i].name);
		if (!strcmp(temp[i].name, "/dev/null")) {
			path0[i] = "/dev/null";
			path1[i] = "";
		} else {
116
			path0[i] = i ? "b/" : "a/";
J
Junio C Hamano 已提交
117
			path1[i] = name_sq[i];
118 119
		}
		cmd_size += (strlen(path0[i]) + strlen(path1[i]) +
120
			     strlen(input_name_sq[i]));
121
	}
122

123 124 125
	cmd = xmalloc(cmd_size);

	next_at = 0;
126
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
127
			    diff_cmd,
128
			    path0[0], path1[0], path0[1], path1[1]);
129 130 131
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
			    " %s ", diff_opts);
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
132 133
			    diff_arg, input_name_sq[0], input_name_sq[1]);

J
Junio C Hamano 已提交
134
	printf("diff --git a/%s b/%s\n", name_a, name_b);
135
	if (!path1[0][0])
136
		printf("new file mode %s\n", temp[1].mode);
137
	else if (!path1[1][0])
138
		printf("deleted file mode %s\n", temp[0].mode);
139
	else {
140 141 142 143
		if (strcmp(temp[0].mode, temp[1].mode)) {
			printf("old mode %s\n", temp[0].mode);
			printf("new mode %s\n", temp[1].mode);
		}
144
		if (xfrm_msg && xfrm_msg[0])
145
			puts(xfrm_msg);
146

147 148 149 150
		if (strncmp(temp[0].mode, temp[1].mode, 3))
			/* we do not run diff between different kind
			 * of objects.
			 */
151 152
			exit(0);
	}
153
	fflush(NULL);
154
	execlp("/bin/sh","sh", "-c", cmd, NULL);
155 156
}

157 158 159 160 161 162
struct diff_filespec *alloc_filespec(const char *path)
{
	int namelen = strlen(path);
	struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
	spec->path = (char *)(spec + 1);
	strcpy(spec->path, path);
163
	spec->should_free = spec->should_munmap = 0;
164 165
	spec->xfrm_flags = 0;
	spec->size = 0;
L
Linus Torvalds 已提交
166
	spec->data = NULL;
167 168
	spec->mode = 0;
	memset(spec->sha1, 0, 20);
169 170 171 172 173 174
	return spec;
}

void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
		   unsigned short mode)
{
175 176
	if (mode) {
		spec->mode = DIFF_FILE_CANON_MODE(mode);
177 178 179
		memcpy(spec->sha1, sha1, 20);
		spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
	}
180 181
}

J
Junio C Hamano 已提交
182 183 184 185 186 187 188 189 190 191
/*
 * Given a name and sha1 pair, if the dircache tells us the file in
 * the work tree has that object contents, return true, so that
 * prepare_temp_file() does not have to inflate and extract.
 */
static int work_tree_matches(const char *name, const unsigned char *sha1)
{
	struct cache_entry *ce;
	struct stat st;
	int pos, len;
192

J
Junio C Hamano 已提交
193 194 195 196
	/* We do not read the cache ourselves here, because the
	 * benchmark with my previous version that always reads cache
	 * shows that it makes things worse for diff-tree comparing
	 * two linux-2.6 kernel trees in an already checked out work
J
Junio C Hamano 已提交
197
	 * tree.  This is because most diff-tree comparisons deal with
J
Junio C Hamano 已提交
198 199 200 201 202 203
	 * only a small number of files, while reading the cache is
	 * expensive for a large project, and its cost outweighs the
	 * savings we get by not inflating the object to a temporary
	 * file.  Practically, this code only helps when we are used
	 * by diff-cache --cached, which does read the cache before
	 * calling us.
J
Junio C Hamano 已提交
204
	 */
J
Junio C Hamano 已提交
205 206 207 208 209 210 211 212
	if (!active_cache)
		return 0;

	len = strlen(name);
	pos = cache_name_pos(name, len);
	if (pos < 0)
		return 0;
	ce = active_cache[pos];
213
	if ((lstat(name, &st) < 0) ||
214
	    !S_ISREG(st.st_mode) || /* careful! */
215
	    ce_match_stat(ce, &st) ||
J
Junio C Hamano 已提交
216 217
	    memcmp(sha1, ce->sha1, 20))
		return 0;
218 219 220 221 222
	/* we return 1 only when we can stat, it is a regular file,
	 * stat information matches, and sha1 recorded in the cache
	 * matches.  I.e. we know the file in the work tree really is
	 * the same as the <name, sha1> pair.
	 */
J
Junio C Hamano 已提交
223 224 225
	return 1;
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
static struct sha1_size_cache {
	unsigned char sha1[20];
	unsigned long size;
} **sha1_size_cache;
static int sha1_size_cache_nr, sha1_size_cache_alloc;

static struct sha1_size_cache *locate_size_cache(unsigned char *sha1,
						 unsigned long size)
{
	int first, last;
	struct sha1_size_cache *e;

	first = 0;
	last = sha1_size_cache_nr;
	while (last > first) {
		int next = (last + first) >> 1;
		e = sha1_size_cache[next];
		int cmp = memcmp(e->sha1, sha1, 20);
		if (!cmp)
			return e;
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
	/* not found */
	if (size == UINT_MAX)
		return NULL;
	/* insert to make it at "first" */
	if (sha1_size_cache_alloc <= sha1_size_cache_nr) {
		sha1_size_cache_alloc = alloc_nr(sha1_size_cache_alloc);
		sha1_size_cache = xrealloc(sha1_size_cache,
					   sha1_size_cache_alloc *
					   sizeof(*sha1_size_cache));
	}
	sha1_size_cache_nr++;
	if (first < sha1_size_cache_nr)
		memmove(sha1_size_cache + first + 1, sha1_size_cache + first,
			(sha1_size_cache_nr - first - 1) *
			sizeof(*sha1_size_cache));
	e = xmalloc(sizeof(struct sha1_size_cache));
	sha1_size_cache[first] = e;
	memcpy(e->sha1, sha1, 20);
	e->size = size;
	return e;
}

274 275 276 277 278
/*
 * While doing rename detection and pickaxe operation, we may need to
 * grab the data for the blob (or file) for our own in-core comparison.
 * diff_filespec has data and size fields for this purpose.
 */
279
int diff_populate_filespec(struct diff_filespec *s, int size_only)
280 281
{
	int err = 0;
282
	if (!DIFF_FILE_VALID(s))
283 284 285 286
		die("internal error: asking to populate invalid file.");
	if (S_ISDIR(s->mode))
		return -1;

287 288 289
	if (!use_size_cache)
		size_only = 0;

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	if (s->data)
		return err;
	if (!s->sha1_valid ||
	    work_tree_matches(s->path, s->sha1)) {
		struct stat st;
		int fd;
		if (lstat(s->path, &st) < 0) {
			if (errno == ENOENT) {
			err_empty:
				err = -1;
			empty:
				s->data = "";
				s->size = 0;
				return err;
			}
		}
		s->size = st.st_size;
		if (!s->size)
			goto empty;
309 310
		if (size_only)
			return 0;
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		if (S_ISLNK(st.st_mode)) {
			int ret;
			s->data = xmalloc(s->size);
			s->should_free = 1;
			ret = readlink(s->path, s->data, s->size);
			if (ret < 0) {
				free(s->data);
				goto err_empty;
			}
			return 0;
		}
		fd = open(s->path, O_RDONLY);
		if (fd < 0)
			goto err_empty;
		s->data = mmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
		s->should_munmap = 1;
		close(fd);
	}
	else {
330
		/* We cannot do size only for SHA1 blobs */
331
		char type[20];
332 333 334 335 336 337 338 339 340
		struct sha1_size_cache *e;

		if (size_only) {
			e = locate_size_cache(s->sha1, UINT_MAX);
			if (e) {
				s->size = e->size;
				return 0;
			}
		}
341 342
		s->data = read_sha1_file(s->sha1, type, &s->size);
		s->should_free = 1;
343 344
		if (s->data && size_only)
			locate_size_cache(s->sha1, s->size);
345 346 347 348 349 350 351 352 353 354 355
	}
	return 0;
}

void diff_free_filespec_data(struct diff_filespec *s)
{
	if (s->should_free)
		free(s->data);
	else if (s->should_munmap)
		munmap(s->data, s->size);
	s->should_free = s->should_munmap = 0;
L
Linus Torvalds 已提交
356
	s->data = NULL;
357 358
}

359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
static void prep_temp_blob(struct diff_tempfile *temp,
			   void *blob,
			   unsigned long size,
			   unsigned char *sha1,
			   int mode)
{
	int fd;

	strcpy(temp->tmp_path, ".diff_XXXXXX");
	fd = mkstemp(temp->tmp_path);
	if (fd < 0)
		die("unable to create temp-file");
	if (write(fd, blob, size) != size)
		die("unable to write temp-file");
	close(fd);
	temp->name = temp->tmp_path;
	strcpy(temp->hex, sha1_to_hex(sha1));
	temp->hex[40] = 0;
	sprintf(temp->mode, "%06o", mode);
}

380 381
static void prepare_temp_file(const char *name,
			      struct diff_tempfile *temp,
382
			      struct diff_filespec *one)
383
{
384
	if (!DIFF_FILE_VALID(one)) {
385
	not_a_valid_file:
386 387 388
		/* A '-' entry produces this for file-2, and
		 * a '+' entry produces this for file-1.
		 */
389 390 391
		temp->name = "/dev/null";
		strcpy(temp->hex, ".");
		strcpy(temp->mode, ".");
392 393
		return;
	}
394

395
	if (!one->sha1_valid ||
396
	    work_tree_matches(name, one->sha1)) {
397
		struct stat st;
398
		if (lstat(name, &st) < 0) {
399 400
			if (errno == ENOENT)
				goto not_a_valid_file;
401
			die("stat(%s): %s", name, strerror(errno));
402
		}
403 404 405 406 407 408 409 410 411 412
		if (S_ISLNK(st.st_mode)) {
			int ret;
			char *buf, buf_[1024];
			buf = ((sizeof(buf_) < st.st_size) ?
			       xmalloc(st.st_size) : buf_);
			ret = readlink(name, buf, st.st_size);
			if (ret < 0)
				die("readlink(%s)", name);
			prep_temp_blob(temp, buf, st.st_size,
				       (one->sha1_valid ?
413
					one->sha1 : null_sha1),
414 415 416 417
				       (one->sha1_valid ?
					one->mode : S_IFLNK));
		}
		else {
418 419
			/* we can borrow from the file in the work tree */
			temp->name = name;
420 421 422
			if (!one->sha1_valid)
				strcpy(temp->hex, sha1_to_hex(null_sha1));
			else
423
				strcpy(temp->hex, sha1_to_hex(one->sha1));
J
Junio C Hamano 已提交
424 425 426 427 428 429 430
			/* Even though we may sometimes borrow the
			 * contents from the work tree, we always want
			 * one->mode.  mode is trustworthy even when
			 * !(one->sha1_valid), as long as
			 * DIFF_FILE_VALID(one).
			 */
			sprintf(temp->mode, "%06o", one->mode);
431 432
		}
		return;
433 434
	}
	else {
435
		if (diff_populate_filespec(one, 0))
436 437 438
			die("cannot read data blob for %s", one->path);
		prep_temp_blob(temp, one->data, one->size,
			       one->sha1, one->mode);
439 440 441 442 443 444 445 446 447 448 449 450 451 452
	}
}

static void remove_tempfile(void)
{
	int i;

	for (i = 0; i < 2; i++)
		if (diff_temp[i].name == diff_temp[i].tmp_path) {
			unlink(diff_temp[i].name);
			diff_temp[i].name = NULL;
		}
}

453 454 455 456 457
static void remove_tempfile_on_signal(int signo)
{
	remove_tempfile();
}

458 459 460
/* An external diff command takes:
 *
 * diff-cmd name infile1 infile1-sha1 infile1-mode \
461
 *               infile2 infile2-sha1 infile2-mode [ rename-to ]
462 463
 *
 */
464 465
static void run_external_diff(const char *pgm,
			      const char *name,
466
			      const char *other,
467 468 469
			      struct diff_filespec *one,
			      struct diff_filespec *two,
			      const char *xfrm_msg)
470 471
{
	struct diff_tempfile *temp = diff_temp;
472 473
	pid_t pid;
	int status;
474 475
	static int atexit_asked = 0;

476 477
	if (one && two) {
		prepare_temp_file(name, &temp[0], one);
J
Junio C Hamano 已提交
478
		prepare_temp_file(other ? : name, &temp[1], two);
479 480 481 482 483 484
		if (! atexit_asked &&
		    (temp[0].name == temp[0].tmp_path ||
		     temp[1].name == temp[1].tmp_path)) {
			atexit_asked = 1;
			atexit(remove_tempfile);
		}
485
		signal(SIGINT, remove_tempfile_on_signal);
486 487 488 489 490 491 492
	}

	fflush(NULL);
	pid = fork();
	if (pid < 0)
		die("unable to fork");
	if (!pid) {
493 494
		if (pgm) {
			if (one && two) {
495
				const char *exec_arg[10];
496 497 498 499 500 501 502 503 504
				const char **arg = &exec_arg[0];
				*arg++ = pgm;
				*arg++ = name;
				*arg++ = temp[0].name;
				*arg++ = temp[0].hex;
				*arg++ = temp[0].mode;
				*arg++ = temp[1].name;
				*arg++ = temp[1].hex;
				*arg++ = temp[1].mode;
505
				if (other) {
506
					*arg++ = other;
507 508
					*arg++ = xfrm_msg;
				}
L
Linus Torvalds 已提交
509
				*arg = NULL;
510 511
				execvp(pgm, (char *const*) exec_arg);
			}
512 513 514
			else
				execlp(pgm, pgm, name, NULL);
		}
515 516 517
		/*
		 * otherwise we use the built-in one.
		 */
518
		if (one && two)
519
			builtin_diff(name, other ? : name, temp, xfrm_msg);
520 521
		else
			printf("* Unmerged path %s\n", name);
522 523
		exit(0);
	}
524 525 526
	if (waitpid(pid, &status, 0) < 0 ||
	    !WIFEXITED(status) || WEXITSTATUS(status)) {
		/* Earlier we did not check the exit status because
527
		 * diff exits non-zero if files are different, and
528 529 530 531 532 533
		 * we are not interested in knowing that.  It was a
		 * mistake which made it harder to quit a diff-*
		 * session that uses the git-apply-patch-script as
		 * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
		 * should also exit non-zero only when it wants to
		 * abort the entire diff-* session.
534 535
		 */
		remove_tempfile();
536 537
		fprintf(stderr, "external diff died, stopping at %s.\n", name);
		exit(1);
538
	}
539 540 541
	remove_tempfile();
}

542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
static void run_diff(const char *name,
		     const char *other,
		     struct diff_filespec *one,
		     struct diff_filespec *two,
		     const char *xfrm_msg)
{
	const char *pgm = external_diff();
	if (!pgm &&
	    DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
	    (S_IFMT & one->mode) != (S_IFMT & two->mode)) {
		/* a filepair that changes between file and symlink
		 * needs to be split into deletion and creation.
		 */
		struct diff_filespec *null = alloc_filespec(two->path);
		run_external_diff(NULL, name, other, one, null, xfrm_msg);
		free(null);
		null = alloc_filespec(one->path);
		run_external_diff(NULL, name, other, null, two, xfrm_msg);
		free(null);
	}
	else
		run_external_diff(pgm, name, other, one, two, xfrm_msg);
}

566
void diff_setup(int flags)
567
{
568 569
	if (flags & DIFF_SETUP_REVERSE)
		reverse_diff = 1;
570 571 572 573 574 575 576 577 578 579 580 581 582
	if (flags & DIFF_SETUP_USE_CACHE) {
		if (!active_cache)
			/* read-cache does not die even when it fails
			 * so it is safe for us to do this here.  Also
			 * it does not smudge active_cache or active_nr
			 * when it fails, so we do not have to worry about
			 * cleaning it up oufselves either.
			 */
			read_cache();
	}
	if (flags & DIFF_SETUP_USE_SIZE_CACHE)
		use_size_cache = 1;
	
583 584
}

J
Junio C Hamano 已提交
585 586 587
struct diff_queue_struct diff_queued_diff;

void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
588
{
J
Junio C Hamano 已提交
589 590 591 592
	if (queue->alloc <= queue->nr) {
		queue->alloc = alloc_nr(queue->alloc);
		queue->queue = xrealloc(queue->queue,
					sizeof(dp) * queue->alloc);
593
	}
J
Junio C Hamano 已提交
594
	queue->queue[queue->nr++] = dp;
595 596
}

597
struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
J
Junio C Hamano 已提交
598 599
				 struct diff_filespec *one,
				 struct diff_filespec *two)
600
{
601
	struct diff_filepair *dp = xmalloc(sizeof(*dp));
602 603
	dp->one = one;
	dp->two = two;
604
	dp->score = 0;
605
	dp->source_stays = 0;
606
	dp->broken_pair = 0;
J
Junio C Hamano 已提交
607
	diff_q(queue, dp);
608
	return dp;
609 610
}

611 612 613 614 615 616 617
void diff_free_filepair(struct diff_filepair *p)
{
	diff_free_filespec_data(p->one);
	diff_free_filespec_data(p->two);
	free(p);
}

618 619 620
static void diff_flush_raw(struct diff_filepair *p,
			   int line_termination,
			   int inter_name_termination)
621
{
622 623
	int two_paths;
	char status[10];
624 625 626 627 628 629 630 631 632 633 634

	if (line_termination) {
		const char *err = "path %s cannot be expressed without -z";
		if (strchr(p->one->path, line_termination) ||
		    strchr(p->one->path, inter_name_termination))
			die(err, p->one->path);
		if (strchr(p->two->path, line_termination) ||
		    strchr(p->two->path, inter_name_termination))
			die(err, p->two->path);
	}

635 636 637
	switch (p->status) {
	case 'C': case 'R':
		two_paths = 1;
638 639
		sprintf(status, "%c%03d", p->status,
			(int)(0.5 + p->score * 100.0/MAX_SCORE));
640
		break;
641 642 643 644 645 646 647 648 649 650
	case 'N': case 'D':
		two_paths = 0;
		if (p->score)
			sprintf(status, "%c%03d", p->status,
				(int)(0.5 + p->score * 100.0/MAX_SCORE));
		else {
			status[0] = p->status;
			status[1] = 0;
		}
		break;
651 652 653 654 655
	default:
		two_paths = 0;
		status[0] = p->status;
		status[1] = 0;
		break;
J
Junio C Hamano 已提交
656
	}
657 658
	printf(":%06o %06o %s ",
	       p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
659 660 661 662 663 664 665 666
	printf("%s %s%c%s",
	       sha1_to_hex(p->two->sha1),
	       status,
	       inter_name_termination,
	       p->one->path);
	if (two_paths)
		printf("%c%s", inter_name_termination, p->two->path);
	putchar(line_termination);
667 668
}

669
int diff_unmodified_pair(struct diff_filepair *p)
670
{
671 672
	/* This function is written stricter than necessary to support
	 * the currently implemented transformers, but the idea is to
673
	 * let transformers to produce diff_filepairs any way they want,
674
	 * and filter and clean them up here before producing the output.
675
	 */
J
Junio C Hamano 已提交
676 677 678 679
	struct diff_filespec *one, *two;

	if (DIFF_PAIR_UNMERGED(p))
		return 0; /* unmerged is interesting */
680

J
Junio C Hamano 已提交
681 682
	one = p->one;
	two = p->two;
683

684 685 686
	/* deletion, addition, mode or type change
	 * and rename are all interesting.
	 */
687
	if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
688
	    DIFF_PAIR_MODE_CHANGED(p) ||
689 690
	    strcmp(one->path, two->path))
		return 0;
J
Junio C Hamano 已提交
691

692 693
	/* both are valid and point at the same path.  that is, we are
	 * dealing with a change.
J
Junio C Hamano 已提交
694
	 */
695 696 697 698 699 700
	if (one->sha1_valid && two->sha1_valid &&
	    !memcmp(one->sha1, two->sha1, sizeof(one->sha1)))
		return 1; /* no change */
	if (!one->sha1_valid && !two->sha1_valid)
		return 1; /* both look at the same file on the filesystem. */
	return 0;
J
Junio C Hamano 已提交
701 702
}

703
static void diff_flush_patch(struct diff_filepair *p)
704 705
{
	const char *name, *other;
706
	char msg_[PATH_MAX*2+200], *msg;
707 708 709 710 711 712 713 714 715 716

	if (diff_unmodified_pair(p))
		return;

	name = p->one->path;
	other = (strcmp(name, p->two->path) ? p->two->path : NULL);
	if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
	    (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
		return; /* no tree diffs in patch format */ 

717 718 719 720 721
	switch (p->status) {
	case 'C':
		sprintf(msg_,
			"similarity index %d%%\n"
			"copy from %s\n"
722
			"copy to %s",
723
			(int)(0.5 + p->score * 100.0/MAX_SCORE),
724 725 726 727 728 729 730
			p->one->path, p->two->path);
		msg = msg_;
		break;
	case 'R':
		sprintf(msg_,
			"similarity index %d%%\n"
			"rename old %s\n"
731
			"rename new %s",
732
			(int)(0.5 + p->score * 100.0/MAX_SCORE),
733 734 735 736 737 738 739
			p->one->path, p->two->path);
		msg = msg_;
		break;
	default:
		msg = NULL;
	}

740
	if (DIFF_PAIR_UNMERGED(p))
741
		run_diff(name, NULL, NULL, NULL, NULL);
742
	else
743
		run_diff(name, other, p->one, p->two, msg);
744 745
}

746
int diff_queue_is_empty(void)
747
{
748
	struct diff_queue_struct *q = &diff_queued_diff;
749 750 751 752 753
	int i;
	for (i = 0; i < q->nr; i++)
		if (!diff_unmodified_pair(q->queue[i]))
			return 0;
	return 1;
754 755
}

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
#if DIFF_DEBUG
void diff_debug_filespec(struct diff_filespec *s, int x, const char *one)
{
	fprintf(stderr, "queue[%d] %s (%s) %s %06o %s\n",
		x, one ? : "",
		s->path,
		DIFF_FILE_VALID(s) ? "valid" : "invalid",
		s->mode,
		s->sha1_valid ? sha1_to_hex(s->sha1) : "");
	fprintf(stderr, "queue[%d] %s size %lu flags %d\n",
		x, one ? : "",
		s->size, s->xfrm_flags);
}

void diff_debug_filepair(const struct diff_filepair *p, int i)
{
	diff_debug_filespec(p->one, i, "one");
	diff_debug_filespec(p->two, i, "two");
774 775 776
	fprintf(stderr, "score %d, status %c stays %d broken %d\n",
		p->score, p->status ? : '?',
		p->source_stays, p->broken_pair);
777 778 779
}

void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
J
Junio C Hamano 已提交
780 781
{
	int i;
782 783 784
	if (msg)
		fprintf(stderr, "%s\n", msg);
	fprintf(stderr, "q->nr = %d\n", q->nr);
J
Junio C Hamano 已提交
785 786
	for (i = 0; i < q->nr; i++) {
		struct diff_filepair *p = q->queue[i];
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
		diff_debug_filepair(p, i);
	}
}
#endif

static void diff_resolve_rename_copy(void)
{
	int i, j;
	struct diff_filepair *p, *pp;
	struct diff_queue_struct *q = &diff_queued_diff;

	diff_debug_queue("resolve-rename-copy", q);

	for (i = 0; i < q->nr; i++) {
		p = q->queue[i];
802
		p->status = 0; /* undecided */
803 804
		if (DIFF_PAIR_UNMERGED(p))
			p->status = 'U';
805
		else if (!DIFF_FILE_VALID(p->one))
806
			p->status = 'N';
807 808
		else if (!DIFF_FILE_VALID(p->two))
			p->status = 'D';
809 810 811 812 813 814 815
		else if (DIFF_PAIR_TYPE_CHANGED(p))
			p->status = 'T';

		/* from this point on, we are dealing with a pair
		 * whose both sides are valid and of the same type, i.e.
		 * either in-place edit or rename/copy edit.
		 */
816
		else if (DIFF_PAIR_RENAME(p)) {
817 818 819 820 821 822 823
			if (p->source_stays) {
				p->status = 'C';
				continue;
			}
			/* See if there is some other filepair that
			 * copies from the same source as us.  If so
			 * we are a copy.  Otherwise we are a rename.
824
			 */
825
			for (j = i + 1; j < q->nr; j++) {
826 827
				pp = q->queue[j];
				if (strcmp(pp->one->path, p->one->path))
828
					continue; /* not us */
829
				if (!DIFF_PAIR_RENAME(pp))
830 831 832 833
					continue; /* not a rename/copy */
				/* pp is a rename/copy from the same source */
				p->status = 'C';
				break;
834 835
			}
			if (!p->status)
836 837
				p->status = 'R';
		}
838 839
		else if (memcmp(p->one->sha1, p->two->sha1, 20) ||
			 p->one->mode != p->two->mode)
840
			p->status = 'M';
841
		else
842 843 844 845 846
			/* this is a "no-change" entry.
			 * should not happen anymore.
			 * p->status = 'X';
			 */
			die("internal error in diffcore: unmodified entry remains");
J
Junio C Hamano 已提交
847
	}
848
	diff_debug_queue("resolve-rename-copy done", q);
849 850
}

851
void diff_flush(int diff_output_style, int resolve_rename_copy)
852 853 854
{
	struct diff_queue_struct *q = &diff_queued_diff;
	int i;
855 856
	int line_termination = '\n';
	int inter_name_termination = '\t';
857

858
	if (diff_output_style == DIFF_FORMAT_MACHINE)
J
Junio C Hamano 已提交
859
		line_termination = inter_name_termination = 0;
860 861 862
	if (resolve_rename_copy)
		diff_resolve_rename_copy();

863 864
	for (i = 0; i < q->nr; i++) {
		struct diff_filepair *p = q->queue[i];
865 866
		if ((diff_output_style == DIFF_FORMAT_NO_OUTPUT) ||
		    (p->status == 'X'))
867
			continue;
868
		if (p->status == 0)
869
			die("internal error in diff-resolve-rename-copy");
870 871
		switch (diff_output_style) {
		case DIFF_FORMAT_PATCH:
872
			diff_flush_patch(p);
873 874 875 876 877 878 879
			break;
		case DIFF_FORMAT_HUMAN:
		case DIFF_FORMAT_MACHINE:
			diff_flush_raw(p, line_termination,
				       inter_name_termination);
			break;
		}
880
	}
881 882
	for (i = 0; i < q->nr; i++)
		diff_free_filepair(q->queue[i]);
883 884 885
	free(q->queue);
	q->queue = NULL;
	q->nr = q->alloc = 0;
886 887
}

888 889
void diffcore_std(const char **paths,
		  int detect_rename, int rename_score,
890
		  const char *pickaxe, int pickaxe_opts,
891 892
		  int break_opt,
		  const char *orderfile)
893 894 895
{
	if (paths && paths[0])
		diffcore_pathspec(paths);
896 897
	if (0 <= break_opt)
		diffcore_break(break_opt);
898 899 900 901
	if (detect_rename)
		diffcore_rename(detect_rename, rename_score);
	if (pickaxe)
		diffcore_pickaxe(pickaxe, pickaxe_opts);
902 903
	if (orderfile)
		diffcore_order(orderfile);
904 905
}

906 907 908
void diff_addremove(int addremove, unsigned mode,
		    const unsigned char *sha1,
		    const char *base, const char *path)
909
{
910
	char concatpath[PATH_MAX];
911 912 913 914 915 916 917 918 919
	struct diff_filespec *one, *two;

	/* This may look odd, but it is a preparation for
	 * feeding "there are unchanged files which should
	 * not produce diffs, but when you are doing copy
	 * detection you would need them, so here they are"
	 * entries to the diff-core.  They will be prefixed
	 * with something like '=' or '*' (I haven't decided
	 * which but should not make any difference).
920
	 * Feeding the same new and old to diff_change() 
921 922 923
	 * also has the same effect.
	 * Before the final output happens, they are pruned after
	 * merged into rename/copy pairs as appropriate.
924
	 */
925
	if (reverse_diff)
926 927
		addremove = (addremove == '+' ? '-' :
			     addremove == '-' ? '+' : addremove);
928

929 930 931 932
	if (!path) path = "";
	sprintf(concatpath, "%s%s", base, path);
	one = alloc_filespec(concatpath);
	two = alloc_filespec(concatpath);
933

934 935 936 937
	if (addremove != '+')
		fill_filespec(one, sha1, mode);
	if (addremove != '-')
		fill_filespec(two, sha1, mode);
938

939
	diff_queue(&diff_queued_diff, one, two);
940 941
}

942 943 944 945 946 947 948 949
void diff_helper_input(unsigned old_mode,
		       unsigned new_mode,
		       const unsigned char *old_sha1,
		       const unsigned char *new_sha1,
		       const char *old_path,
		       int status,
		       int score,
		       const char *new_path)
950 951
{
	struct diff_filespec *one, *two;
952
	struct diff_filepair *dp;
953 954 955 956 957 958 959

	one = alloc_filespec(old_path);
	two = alloc_filespec(new_path);
	if (old_mode)
		fill_filespec(one, old_sha1, old_mode);
	if (new_mode)
		fill_filespec(two, new_sha1, new_mode);
960
	dp = diff_queue(&diff_queued_diff, one, two);
961
	dp->score = score * MAX_SCORE / 100;
962
	dp->status = status;
963 964
}

965 966 967
void diff_change(unsigned old_mode, unsigned new_mode,
		 const unsigned char *old_sha1,
		 const unsigned char *new_sha1,
968 969
		 const char *base, const char *path) 
{
970
	char concatpath[PATH_MAX];
971
	struct diff_filespec *one, *two;
972

973 974 975 976 977 978
	if (reverse_diff) {
		unsigned tmp;
		const unsigned char *tmp_c;
		tmp = old_mode; old_mode = new_mode; new_mode = tmp;
		tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
	}
979 980 981 982 983 984 985
	if (!path) path = "";
	sprintf(concatpath, "%s%s", base, path);
	one = alloc_filespec(concatpath);
	two = alloc_filespec(concatpath);
	fill_filespec(one, old_sha1, old_mode);
	fill_filespec(two, new_sha1, new_mode);

986
	diff_queue(&diff_queued_diff, one, two);
987
}
988

989 990
void diff_unmerge(const char *path)
{
J
Junio C Hamano 已提交
991 992 993 994
	struct diff_filespec *one, *two;
	one = alloc_filespec(path);
	two = alloc_filespec(path);
	diff_queue(&diff_queued_diff, one, two);
995
}