diff.c 29.2 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
#include "cache.h"
8
#include "quote.h"
9
#include "diff.h"
10
#include "diffcore.h"
11

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

static int reverse_diff;
16
static int use_size_cache;
17

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

	if (done_preparing)
		return external_diff_cmd;

27 28 29 30 31 32 33 34
	/*
	 * 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";
	 */
35
	external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
36 37

	/* In case external diff fails... */
38
	env_diff_opts = getenv("GIT_DIFF_OPTS");
J
Jason Riedy 已提交
39
	if (env_diff_opts) diff_opts = env_diff_opts;
40 41 42

	done_preparing = 1;
	return external_diff_cmd;
43 44
}

45 46
#define TEMPFILE_PATH_LEN		50

47
static struct diff_tempfile {
48
	const char *name; /* filename external diff should read from */
49 50
	char hex[41];
	char mode[10];
51
	char tmp_path[TEMPFILE_PATH_LEN];
52 53
} diff_temp[2];

J
Junio C Hamano 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static int count_lines(const char *filename)
{
	FILE *in;
	int count, ch, completely_empty = 1, nl_just_seen = 0;
	in = fopen(filename, "r");
	count = 0;
	while ((ch = fgetc(in)) != EOF)
		if (ch == '\n') {
			count++;
			nl_just_seen = 1;
			completely_empty = 0;
		}
		else {
			nl_just_seen = 0;
			completely_empty = 0;
		}
	fclose(in);
	if (completely_empty)
		return 0;
	if (!nl_just_seen)
		count++; /* no trailing newline */
	return count;
}

static void print_line_count(int count)
{
	switch (count) {
	case 0:
		printf("0,0");
		break;
	case 1:
		printf("1");
		break;
	default:
		printf("1,%d", count);
		break;
	}
}

static void copy_file(int prefix, const char *filename)
{
	FILE *in;
	int ch, nl_just_seen = 1;
	in = fopen(filename, "r");
	while ((ch = fgetc(in)) != EOF) {
		if (nl_just_seen)
			putchar(prefix);
		putchar(ch);
		if (ch == '\n')
			nl_just_seen = 1;
		else
			nl_just_seen = 0;
	}
	fclose(in);
	if (!nl_just_seen)
		printf("\n\\ No newline at end of file\n");
}

static void emit_rewrite_diff(const char *name_a,
			      const char *name_b,
			      struct diff_tempfile *temp)
{
	/* Use temp[i].name as input, name_a and name_b as labels */
	int lc_a, lc_b;
	lc_a = count_lines(temp[0].name);
	lc_b = count_lines(temp[1].name);
	printf("--- %s\n+++ %s\n@@ -", name_a, name_b);
	print_line_count(lc_a);
	printf(" +");
	print_line_count(lc_b);
	printf(" @@\n");
	if (lc_a)
		copy_file('-', temp[0].name);
	if (lc_b)
		copy_file('+', temp[1].name);
}

J
Junio C Hamano 已提交
131 132
static void builtin_diff(const char *name_a,
			 const char *name_b,
J
Junio C Hamano 已提交
133
			 struct diff_tempfile *temp,
J
Junio C Hamano 已提交
134 135
			 const char *xfrm_msg,
			 int complete_rewrite)
136
{
137
	int i, next_at, cmd_size;
138 139
	const char *const diff_cmd = "diff -L%s%s -L%s%s";
	const char *const diff_arg  = "%s %s||:"; /* "||:" is to return 0 */
140 141 142
	const char *input_name_sq[2];
	const char *path0[2];
	const char *path1[2];
J
Junio C Hamano 已提交
143
	const char *name_sq[2];
144
	char *cmd;
J
Junio C Hamano 已提交
145

146 147
	name_sq[0] = sq_quote(name_a);
	name_sq[1] = sq_quote(name_b);
J
Junio C Hamano 已提交
148

149 150
	/* diff_cmd and diff_arg have 6 %s in total which makes
	 * the sum of these strings 12 bytes larger than required.
151
	 * we use 2 spaces around diff-opts, and we need to count
152
	 * terminating NUL, so we subtract 9 here.
153
	 */
154
	cmd_size = (strlen(diff_cmd) + strlen(diff_opts) +
155
			strlen(diff_arg) - 9);
156
	for (i = 0; i < 2; i++) {
157
		input_name_sq[i] = sq_quote(temp[i].name);
158 159 160 161
		if (!strcmp(temp[i].name, "/dev/null")) {
			path0[i] = "/dev/null";
			path1[i] = "";
		} else {
162
			path0[i] = i ? "b/" : "a/";
J
Junio C Hamano 已提交
163
			path1[i] = name_sq[i];
164 165
		}
		cmd_size += (strlen(path0[i]) + strlen(path1[i]) +
166
			     strlen(input_name_sq[i]));
167
	}
168

169 170 171
	cmd = xmalloc(cmd_size);

	next_at = 0;
172
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
173
			    diff_cmd,
174
			    path0[0], path1[0], path0[1], path1[1]);
175 176 177
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
			    " %s ", diff_opts);
	next_at += snprintf(cmd+next_at, cmd_size-next_at,
178 179
			    diff_arg, input_name_sq[0], input_name_sq[1]);

J
Junio C Hamano 已提交
180
	printf("diff --git a/%s b/%s\n", name_a, name_b);
181
	if (!path1[0][0]) {
182
		printf("new file mode %s\n", temp[1].mode);
183 184 185 186
		if (xfrm_msg && xfrm_msg[0])
			puts(xfrm_msg);
	}
	else if (!path1[1][0]) {
187
		printf("deleted file mode %s\n", temp[0].mode);
188 189 190
		if (xfrm_msg && xfrm_msg[0])
			puts(xfrm_msg);
	}
191
	else {
192 193 194 195
		if (strcmp(temp[0].mode, temp[1].mode)) {
			printf("old mode %s\n", temp[0].mode);
			printf("new mode %s\n", temp[1].mode);
		}
196
		if (xfrm_msg && xfrm_msg[0])
197
			puts(xfrm_msg);
198 199 200 201
		if (strncmp(temp[0].mode, temp[1].mode, 3))
			/* we do not run diff between different kind
			 * of objects.
			 */
202
			exit(0);
J
Junio C Hamano 已提交
203 204 205 206 207
		if (complete_rewrite) {
			fflush(NULL);
			emit_rewrite_diff(name_a, name_b, temp);
			exit(0);
		}
208
	}
209
	fflush(NULL);
210
	execlp("/bin/sh","sh", "-c", cmd, NULL);
211 212
}

213 214 215 216 217 218
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);
219
	spec->should_free = spec->should_munmap = 0;
220 221
	spec->xfrm_flags = 0;
	spec->size = 0;
L
Linus Torvalds 已提交
222
	spec->data = NULL;
223 224
	spec->mode = 0;
	memset(spec->sha1, 0, 20);
225 226 227 228 229 230
	return spec;
}

void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
		   unsigned short mode)
{
231 232
	if (mode) {
		spec->mode = DIFF_FILE_CANON_MODE(mode);
233 234 235
		memcpy(spec->sha1, sha1, 20);
		spec->sha1_valid = !!memcmp(sha1, null_sha1, 20);
	}
236 237
}

J
Junio C Hamano 已提交
238 239 240 241 242 243 244 245 246 247
/*
 * 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;
248

J
Junio C Hamano 已提交
249 250 251 252
	/* 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 已提交
253
	 * tree.  This is because most diff-tree comparisons deal with
J
Junio C Hamano 已提交
254 255 256 257 258 259
	 * 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 已提交
260
	 */
J
Junio C Hamano 已提交
261 262 263 264 265 266 267 268
	if (!active_cache)
		return 0;

	len = strlen(name);
	pos = cache_name_pos(name, len);
	if (pos < 0)
		return 0;
	ce = active_cache[pos];
269
	if ((lstat(name, &st) < 0) ||
270
	    !S_ISREG(st.st_mode) || /* careful! */
271
	    ce_match_stat(ce, &st) ||
J
Junio C Hamano 已提交
272 273
	    memcmp(sha1, ce->sha1, 20))
		return 0;
274 275 276 277 278
	/* 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 已提交
279 280 281
	return 1;
}

282 283 284 285 286 287 288
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,
289
						 int find_only,
290 291 292 293 294 295 296 297
						 unsigned long size)
{
	int first, last;
	struct sha1_size_cache *e;

	first = 0;
	last = sha1_size_cache_nr;
	while (last > first) {
298
		int cmp, next = (last + first) >> 1;
299
		e = sha1_size_cache[next];
300
		cmp = memcmp(e->sha1, sha1, 20);
301 302 303 304 305 306 307 308 309
		if (!cmp)
			return e;
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
	/* not found */
310
	if (find_only)
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
		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;
}

331 332 333 334 335
/*
 * 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.
 */
336
int diff_populate_filespec(struct diff_filespec *s, int size_only)
337 338
{
	int err = 0;
339
	if (!DIFF_FILE_VALID(s))
340 341 342 343
		die("internal error: asking to populate invalid file.");
	if (S_ISDIR(s->mode))
		return -1;

344 345 346
	if (!use_size_cache)
		size_only = 0;

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	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;
366 367
		if (size_only)
			return 0;
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
		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);
		close(fd);
P
Pavel Roskin 已提交
384 385 386
		if (s->data == MAP_FAILED)
			goto err_empty;
		s->should_munmap = 1;
387 388 389
	}
	else {
		char type[20];
390 391 392
		struct sha1_size_cache *e;

		if (size_only) {
393
			e = locate_size_cache(s->sha1, 1, 0);
394 395 396 397
			if (e) {
				s->size = e->size;
				return 0;
			}
398
			if (!sha1_object_info(s->sha1, type, &s->size))
399
				locate_size_cache(s->sha1, 0, s->size);
400 401 402 403
		}
		else {
			s->data = read_sha1_file(s->sha1, type, &s->size);
			s->should_free = 1;
404
		}
405 406 407 408
	}
	return 0;
}

409
void diff_free_filespec(struct diff_filespec *s)
410 411 412 413 414
{
	if (s->should_free)
		free(s->data);
	else if (s->should_munmap)
		munmap(s->data, s->size);
415
	free(s);
416 417
}

418 419 420 421 422 423 424 425
static void prep_temp_blob(struct diff_tempfile *temp,
			   void *blob,
			   unsigned long size,
			   unsigned char *sha1,
			   int mode)
{
	int fd;

426
	fd = git_mkstemp(temp->tmp_path, TEMPFILE_PATH_LEN, ".diff_XXXXXX");
427 428 429 430 431 432 433 434 435 436 437
	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);
}

438 439
static void prepare_temp_file(const char *name,
			      struct diff_tempfile *temp,
440
			      struct diff_filespec *one)
441
{
442
	if (!DIFF_FILE_VALID(one)) {
443
	not_a_valid_file:
444 445 446
		/* A '-' entry produces this for file-2, and
		 * a '+' entry produces this for file-1.
		 */
447 448 449
		temp->name = "/dev/null";
		strcpy(temp->hex, ".");
		strcpy(temp->mode, ".");
450 451
		return;
	}
452

453
	if (!one->sha1_valid ||
454
	    work_tree_matches(name, one->sha1)) {
455
		struct stat st;
456
		if (lstat(name, &st) < 0) {
457 458
			if (errno == ENOENT)
				goto not_a_valid_file;
459
			die("stat(%s): %s", name, strerror(errno));
460
		}
461 462 463 464 465 466 467 468 469 470
		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 ?
471
					one->sha1 : null_sha1),
472 473 474 475
				       (one->sha1_valid ?
					one->mode : S_IFLNK));
		}
		else {
476 477
			/* we can borrow from the file in the work tree */
			temp->name = name;
478 479 480
			if (!one->sha1_valid)
				strcpy(temp->hex, sha1_to_hex(null_sha1));
			else
481
				strcpy(temp->hex, sha1_to_hex(one->sha1));
J
Junio C Hamano 已提交
482 483 484 485 486 487 488
			/* 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);
489 490
		}
		return;
491 492
	}
	else {
493
		if (diff_populate_filespec(one, 0))
494 495 496
			die("cannot read data blob for %s", one->path);
		prep_temp_blob(temp, one->data, one->size,
			       one->sha1, one->mode);
497 498 499 500 501 502 503 504 505 506 507 508 509 510
	}
}

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;
		}
}

511 512 513 514 515
static void remove_tempfile_on_signal(int signo)
{
	remove_tempfile();
}

516 517 518
/* An external diff command takes:
 *
 * diff-cmd name infile1 infile1-sha1 infile1-mode \
519
 *               infile2 infile2-sha1 infile2-mode [ rename-to ]
520 521
 *
 */
522 523
static void run_external_diff(const char *pgm,
			      const char *name,
524
			      const char *other,
525 526
			      struct diff_filespec *one,
			      struct diff_filespec *two,
J
Junio C Hamano 已提交
527 528
			      const char *xfrm_msg,
			      int complete_rewrite)
529 530
{
	struct diff_tempfile *temp = diff_temp;
531 532
	pid_t pid;
	int status;
533
	static int atexit_asked = 0;
J
Jason Riedy 已提交
534
	const char *othername;
535

J
Jason Riedy 已提交
536
	othername = (other? other : name);
537 538
	if (one && two) {
		prepare_temp_file(name, &temp[0], one);
J
Jason Riedy 已提交
539
		prepare_temp_file(othername, &temp[1], two);
540 541 542 543 544 545
		if (! atexit_asked &&
		    (temp[0].name == temp[0].tmp_path ||
		     temp[1].name == temp[1].tmp_path)) {
			atexit_asked = 1;
			atexit(remove_tempfile);
		}
546
		signal(SIGINT, remove_tempfile_on_signal);
547 548 549 550 551 552 553
	}

	fflush(NULL);
	pid = fork();
	if (pid < 0)
		die("unable to fork");
	if (!pid) {
554 555
		if (pgm) {
			if (one && two) {
556
				const char *exec_arg[10];
557 558 559 560 561 562 563 564 565
				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;
566
				if (other) {
567
					*arg++ = other;
568 569
					*arg++ = xfrm_msg;
				}
L
Linus Torvalds 已提交
570
				*arg = NULL;
571 572
				execvp(pgm, (char *const*) exec_arg);
			}
573 574 575
			else
				execlp(pgm, pgm, name, NULL);
		}
576 577 578
		/*
		 * otherwise we use the built-in one.
		 */
579
		if (one && two)
J
Jason Riedy 已提交
580
			builtin_diff(name, othername, temp, xfrm_msg,
J
Junio C Hamano 已提交
581
				     complete_rewrite);
582 583
		else
			printf("* Unmerged path %s\n", name);
584 585
		exit(0);
	}
586 587 588
	if (waitpid(pid, &status, 0) < 0 ||
	    !WIFEXITED(status) || WEXITSTATUS(status)) {
		/* Earlier we did not check the exit status because
589
		 * diff exits non-zero if files are different, and
590 591 592 593 594 595
		 * 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.
596 597
		 */
		remove_tempfile();
598 599
		fprintf(stderr, "external diff died, stopping at %s.\n", name);
		exit(1);
600
	}
601 602 603
	remove_tempfile();
}

J
Junio C Hamano 已提交
604
static void run_diff(struct diff_filepair *p)
605 606
{
	const char *pgm = external_diff();
J
Junio C Hamano 已提交
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
	char msg_[PATH_MAX*2+200], *xfrm_msg;
	struct diff_filespec *one;
	struct diff_filespec *two;
	const char *name;
	const char *other;
	int complete_rewrite = 0;

	if (DIFF_PAIR_UNMERGED(p)) {
		/* unmerged */
		run_external_diff(pgm, p->one->path, NULL, NULL, NULL, NULL,
				  0);
		return;
	}

	name = p->one->path;
	other = (strcmp(name, p->two->path) ? p->two->path : NULL);
	one = p->one; two = p->two;
	switch (p->status) {
625
	case DIFF_STATUS_COPIED:
J
Junio C Hamano 已提交
626 627 628 629 630 631 632 633
		sprintf(msg_,
			"similarity index %d%%\n"
			"copy from %s\n"
			"copy to %s",
			(int)(0.5 + p->score * 100.0/MAX_SCORE),
			name, other);
		xfrm_msg = msg_;
		break;
634
	case DIFF_STATUS_RENAMED:
J
Junio C Hamano 已提交
635 636 637 638 639 640 641 642
		sprintf(msg_,
			"similarity index %d%%\n"
			"rename from %s\n"
			"rename to %s",
			(int)(0.5 + p->score * 100.0/MAX_SCORE),
			name, other);
		xfrm_msg = msg_;
		break;
643
	case DIFF_STATUS_MODIFIED:
J
Junio C Hamano 已提交
644 645 646 647 648 649 650 651 652 653 654 655 656
		if (p->score) {
			sprintf(msg_,
				"dissimilarity index %d%%",
				(int)(0.5 + p->score * 100.0/MAX_SCORE));
			xfrm_msg = msg_;
			complete_rewrite = 1;
			break;
		}
		/* fallthru */
	default:
		xfrm_msg = NULL;
	}

657 658 659 660 661 662 663
	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);
J
Junio C Hamano 已提交
664
		run_external_diff(NULL, name, other, one, null, xfrm_msg, 0);
665 666
		free(null);
		null = alloc_filespec(one->path);
J
Junio C Hamano 已提交
667
		run_external_diff(NULL, name, other, null, two, xfrm_msg, 0);
668 669 670
		free(null);
	}
	else
J
Junio C Hamano 已提交
671 672
		run_external_diff(pgm, name, other, one, two, xfrm_msg,
				  complete_rewrite);
673 674
}

675
void diff_setup(int flags)
676
{
677 678
	if (flags & DIFF_SETUP_REVERSE)
		reverse_diff = 1;
679 680 681 682 683 684 685 686 687 688 689 690 691
	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;
	
692 693
}

694 695 696 697 698 699 700 701 702 703 704 705 706
static int parse_num(const char **cp_p)
{
	int num, scale, ch, cnt;
	const char *cp = *cp_p;

	cnt = num = 0;
	scale = 1;
	while ('0' <= (ch = *cp) && ch <= '9') {
		if (cnt++ < 5) {
			/* We simply ignore more than 5 digits precision. */
			scale *= 10;
			num = num * 10 + ch - '0';
		}
J
Junio C Hamano 已提交
707
		cp++;
708 709 710 711 712 713 714 715 716 717 718
	}
	*cp_p = cp;

	/* user says num divided by scale and we say internally that
	 * is MAX_SCORE * num / scale.
	 */
	return (MAX_SCORE * num / scale);
}

int diff_scoreopt_parse(const char *opt)
{
719
	int opt1, opt2, cmd;
720 721 722 723 724 725 726 727

	if (*opt++ != '-')
		return -1;
	cmd = *opt++;
	if (cmd != 'M' && cmd != 'C' && cmd != 'B')
		return -1; /* that is not a -M, -C nor -B option */

	opt1 = parse_num(&opt);
728 729 730 731 732 733 734 735 736 737 738 739
	if (cmd != 'B')
		opt2 = 0;
	else {
		if (*opt == 0)
			opt2 = 0;
		else if (*opt != '/')
			return -1; /* we expect -B80/99 or -B80 */
		else {
			opt++;
			opt2 = parse_num(&opt);
		}
	}
740 741
	if (*opt != 0)
		return -1;
742
	return opt1 | (opt2 << 16);
743 744
}

J
Junio C Hamano 已提交
745 746 747
struct diff_queue_struct diff_queued_diff;

void diff_q(struct diff_queue_struct *queue, struct diff_filepair *dp)
748
{
J
Junio C Hamano 已提交
749 750 751 752
	if (queue->alloc <= queue->nr) {
		queue->alloc = alloc_nr(queue->alloc);
		queue->queue = xrealloc(queue->queue,
					sizeof(dp) * queue->alloc);
753
	}
J
Junio C Hamano 已提交
754
	queue->queue[queue->nr++] = dp;
755 756
}

757
struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
J
Junio C Hamano 已提交
758 759
				 struct diff_filespec *one,
				 struct diff_filespec *two)
760
{
761
	struct diff_filepair *dp = xmalloc(sizeof(*dp));
762 763
	dp->one = one;
	dp->two = two;
764
	dp->score = 0;
765
	dp->status = 0;
766
	dp->source_stays = 0;
767
	dp->broken_pair = 0;
J
Junio C Hamano 已提交
768
	diff_q(queue, dp);
769
	return dp;
770 771
}

772 773
void diff_free_filepair(struct diff_filepair *p)
{
774 775
	diff_free_filespec(p->one);
	diff_free_filespec(p->two);
776 777 778
	free(p);
}

779 780 781
static void diff_flush_raw(struct diff_filepair *p,
			   int line_termination,
			   int inter_name_termination)
782
{
783 784
	int two_paths;
	char status[10];
785 786

	if (line_termination) {
787 788
		const char *const err =
			"path %s cannot be expressed without -z";
789 790 791 792 793 794 795 796
		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);
	}

J
Junio C Hamano 已提交
797 798 799 800 801 802 803
	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;
	}
804
	switch (p->status) {
805 806
	case DIFF_STATUS_COPIED:
	case DIFF_STATUS_RENAMED:
807 808
		two_paths = 1;
		break;
809 810
	case DIFF_STATUS_ADDED:
	case DIFF_STATUS_DELETED:
811 812
		two_paths = 0;
		break;
813 814 815
	default:
		two_paths = 0;
		break;
J
Junio C Hamano 已提交
816
	}
817 818
	printf(":%06o %06o %s ",
	       p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
819 820 821 822 823 824 825 826
	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);
827 828
}

829 830 831 832 833 834
static void diff_flush_name(struct diff_filepair *p,
			    int line_termination)
{
	printf("%s%c", p->two->path, line_termination);
}

835
int diff_unmodified_pair(struct diff_filepair *p)
836
{
837 838
	/* This function is written stricter than necessary to support
	 * the currently implemented transformers, but the idea is to
839
	 * let transformers to produce diff_filepairs any way they want,
840
	 * and filter and clean them up here before producing the output.
841
	 */
J
Junio C Hamano 已提交
842 843 844 845
	struct diff_filespec *one, *two;

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

J
Junio C Hamano 已提交
847 848
	one = p->one;
	two = p->two;
849

850 851 852
	/* deletion, addition, mode or type change
	 * and rename are all interesting.
	 */
853
	if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
854
	    DIFF_PAIR_MODE_CHANGED(p) ||
855 856
	    strcmp(one->path, two->path))
		return 0;
J
Junio C Hamano 已提交
857

858 859
	/* both are valid and point at the same path.  that is, we are
	 * dealing with a change.
J
Junio C Hamano 已提交
860
	 */
861 862 863 864 865 866
	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 已提交
867 868
}

869
static void diff_flush_patch(struct diff_filepair *p)
870 871 872 873 874 875 876 877
{
	if (diff_unmodified_pair(p))
		return;

	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 */ 

J
Junio C Hamano 已提交
878
	run_diff(p);
879 880
}

881
int diff_queue_is_empty(void)
882
{
883
	struct diff_queue_struct *q = &diff_queued_diff;
884 885 886 887 888
	int i;
	for (i = 0; i < q->nr; i++)
		if (!diff_unmodified_pair(q->queue[i]))
			return 0;
	return 1;
889 890
}

891 892 893 894
#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",
J
Jason Riedy 已提交
895
		x, one ? one : "",
896 897 898 899 900
		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",
J
Jason Riedy 已提交
901
		x, one ? one : "",
902 903 904 905 906 907 908
		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");
909
	fprintf(stderr, "score %d, status %c stays %d broken %d\n",
J
Jason Riedy 已提交
910
		p->score, p->status ? p->status : '?',
911
		p->source_stays, p->broken_pair);
912 913 914
}

void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
J
Junio C Hamano 已提交
915 916
{
	int i;
917 918 919
	if (msg)
		fprintf(stderr, "%s\n", msg);
	fprintf(stderr, "q->nr = %d\n", q->nr);
J
Junio C Hamano 已提交
920 921
	for (i = 0; i < q->nr; i++) {
		struct diff_filepair *p = q->queue[i];
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
		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];
937
		p->status = 0; /* undecided */
938
		if (DIFF_PAIR_UNMERGED(p))
939
			p->status = DIFF_STATUS_UNMERGED;
940
		else if (!DIFF_FILE_VALID(p->one))
941
			p->status = DIFF_STATUS_ADDED;
942
		else if (!DIFF_FILE_VALID(p->two))
943
			p->status = DIFF_STATUS_DELETED;
944
		else if (DIFF_PAIR_TYPE_CHANGED(p))
945
			p->status = DIFF_STATUS_TYPE_CHANGED;
946 947 948 949 950

		/* 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.
		 */
951
		else if (DIFF_PAIR_RENAME(p)) {
952
			if (p->source_stays) {
953
				p->status = DIFF_STATUS_COPIED;
954 955 956 957 958
				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.
959
			 */
960
			for (j = i + 1; j < q->nr; j++) {
961 962
				pp = q->queue[j];
				if (strcmp(pp->one->path, p->one->path))
963
					continue; /* not us */
964
				if (!DIFF_PAIR_RENAME(pp))
965 966
					continue; /* not a rename/copy */
				/* pp is a rename/copy from the same source */
967
				p->status = DIFF_STATUS_COPIED;
968
				break;
969 970
			}
			if (!p->status)
971
				p->status = DIFF_STATUS_RENAMED;
972
		}
973 974
		else if (memcmp(p->one->sha1, p->two->sha1, 20) ||
			 p->one->mode != p->two->mode)
975
			p->status = DIFF_STATUS_MODIFIED;
J
Junio C Hamano 已提交
976 977 978
		else {
			/* This is a "no-change" entry and should not
			 * happen anymore, but prepare for broken callers.
979
			 */
J
Junio C Hamano 已提交
980 981
			error("feeding unmodified %s to diffcore",
			      p->one->path);
982
			p->status = DIFF_STATUS_UNKNOWN;
J
Junio C Hamano 已提交
983
		}
J
Junio C Hamano 已提交
984
	}
985
	diff_debug_queue("resolve-rename-copy done", q);
986 987
}

988
void diff_flush(int diff_output_style, int line_termination)
989 990 991
{
	struct diff_queue_struct *q = &diff_queued_diff;
	int i;
992
	int inter_name_termination = '\t';
993

994 995
	if (!line_termination)
		inter_name_termination = 0;
996

997 998
	for (i = 0; i < q->nr; i++) {
		struct diff_filepair *p = q->queue[i];
999
		if ((diff_output_style == DIFF_FORMAT_NO_OUTPUT) ||
1000
		    (p->status == DIFF_STATUS_UNKNOWN))
1001
			continue;
1002
		if (p->status == 0)
1003
			die("internal error in diff-resolve-rename-copy");
1004 1005
		switch (diff_output_style) {
		case DIFF_FORMAT_PATCH:
1006
			diff_flush_patch(p);
1007
			break;
1008
		case DIFF_FORMAT_RAW:
1009 1010 1011
			diff_flush_raw(p, line_termination,
				       inter_name_termination);
			break;
1012 1013 1014
		case DIFF_FORMAT_NAME:
			diff_flush_name(p, line_termination);
			break;
1015
		}
1016
		diff_free_filepair(q->queue[i]);
1017
	}
1018 1019 1020
	free(q->queue);
	q->queue = NULL;
	q->nr = q->alloc = 0;
1021 1022
}

1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
static void diffcore_apply_filter(const char *filter)
{
	int i;
	struct diff_queue_struct *q = &diff_queued_diff;
	struct diff_queue_struct outq;
	outq.queue = NULL;
	outq.nr = outq.alloc = 0;

	if (!filter)
		return;

1034
	if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
1035 1036 1037
		int found;
		for (i = found = 0; !found && i < q->nr; i++) {
			struct diff_filepair *p = q->queue[i];
1038 1039 1040 1041 1042 1043 1044
			if (((p->status == DIFF_STATUS_MODIFIED) &&
			     ((p->score &&
			       strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
			      (!p->score &&
			       strchr(filter, DIFF_STATUS_MODIFIED)))) ||
			    ((p->status != DIFF_STATUS_MODIFIED) &&
			     strchr(filter, p->status)))
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
				found++;
		}
		if (found)
			return;

		/* otherwise we will clear the whole queue
		 * by copying the empty outq at the end of this
		 * function, but first clear the current entries
		 * in the queue.
		 */
		for (i = 0; i < q->nr; i++)
			diff_free_filepair(q->queue[i]);
	}
	else {
		/* Only the matching ones */
		for (i = 0; i < q->nr; i++) {
			struct diff_filepair *p = q->queue[i];
1062 1063 1064 1065 1066 1067 1068 1069

			if (((p->status == DIFF_STATUS_MODIFIED) &&
			     ((p->score &&
			       strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
			      (!p->score &&
			       strchr(filter, DIFF_STATUS_MODIFIED)))) ||
			    ((p->status != DIFF_STATUS_MODIFIED) &&
			     strchr(filter, p->status)))
1070 1071 1072 1073 1074 1075 1076 1077 1078
				diff_q(&outq, p);
			else
				diff_free_filepair(p);
		}
	}
	free(q->queue);
	*q = outq;
}

1079 1080
void diffcore_std(const char **paths,
		  int detect_rename, int rename_score,
1081
		  const char *pickaxe, int pickaxe_opts,
1082
		  int break_opt,
1083 1084
		  const char *orderfile,
		  const char *filter)
1085 1086 1087
{
	if (paths && paths[0])
		diffcore_pathspec(paths);
1088
	if (break_opt != -1)
1089
		diffcore_break(break_opt);
1090 1091
	if (detect_rename)
		diffcore_rename(detect_rename, rename_score);
1092
	if (break_opt != -1)
1093
		diffcore_merge_broken();
1094 1095
	if (pickaxe)
		diffcore_pickaxe(pickaxe, pickaxe_opts);
1096 1097
	if (orderfile)
		diffcore_order(orderfile);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
	diff_resolve_rename_copy();
	diffcore_apply_filter(filter);
}


void diffcore_std_no_resolve(const char **paths,
			     const char *pickaxe, int pickaxe_opts,
			     const char *orderfile,
			     const char *filter)
{
	if (paths && paths[0])
		diffcore_pathspec(paths);
	if (pickaxe)
		diffcore_pickaxe(pickaxe, pickaxe_opts);
	if (orderfile)
		diffcore_order(orderfile);
	diffcore_apply_filter(filter);
1115 1116
}

1117 1118 1119
void diff_addremove(int addremove, unsigned mode,
		    const unsigned char *sha1,
		    const char *base, const char *path)
1120
{
1121
	char concatpath[PATH_MAX];
1122 1123 1124 1125 1126 1127 1128 1129 1130
	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).
1131
	 * Feeding the same new and old to diff_change() 
1132 1133 1134
	 * also has the same effect.
	 * Before the final output happens, they are pruned after
	 * merged into rename/copy pairs as appropriate.
1135
	 */
1136
	if (reverse_diff)
1137 1138
		addremove = (addremove == '+' ? '-' :
			     addremove == '-' ? '+' : addremove);
1139

1140 1141 1142 1143
	if (!path) path = "";
	sprintf(concatpath, "%s%s", base, path);
	one = alloc_filespec(concatpath);
	two = alloc_filespec(concatpath);
1144

1145 1146 1147 1148
	if (addremove != '+')
		fill_filespec(one, sha1, mode);
	if (addremove != '-')
		fill_filespec(two, sha1, mode);
1149

1150
	diff_queue(&diff_queued_diff, one, two);
1151 1152
}

1153 1154 1155 1156 1157 1158 1159 1160
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)
1161 1162
{
	struct diff_filespec *one, *two;
1163
	struct diff_filepair *dp;
1164 1165 1166 1167 1168 1169 1170

	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);
1171
	dp = diff_queue(&diff_queued_diff, one, two);
1172
	dp->score = score * MAX_SCORE / 100;
1173
	dp->status = status;
1174 1175
}

1176 1177 1178
void diff_change(unsigned old_mode, unsigned new_mode,
		 const unsigned char *old_sha1,
		 const unsigned char *new_sha1,
1179 1180
		 const char *base, const char *path) 
{
1181
	char concatpath[PATH_MAX];
1182
	struct diff_filespec *one, *two;
1183

1184 1185 1186 1187 1188 1189
	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;
	}
1190 1191 1192 1193 1194 1195 1196
	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);

1197
	diff_queue(&diff_queued_diff, one, two);
1198
}
1199

1200 1201
void diff_unmerge(const char *path)
{
J
Junio C Hamano 已提交
1202 1203 1204 1205
	struct diff_filespec *one, *two;
	one = alloc_filespec(path);
	two = alloc_filespec(path);
	diff_queue(&diff_queued_diff, one, two);
1206
}