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 22 23 24 25
	static int done_preparing = 0;

	if (done_preparing)
		return external_diff_cmd;

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

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

	done_preparing = 1;
	return external_diff_cmd;
42 43
}

44 45
#define TEMPFILE_PATH_LEN		50

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

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

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

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

168 169 170
	cmd = xmalloc(cmd_size);

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

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

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

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

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

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

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

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

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

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

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

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

		if (size_only) {
392
			e = locate_size_cache(s->sha1, 1, 0);
393 394 395 396
			if (e) {
				s->size = e->size;
				return 0;
			}
397
			if (!sha1_object_info(s->sha1, type, &s->size))
398
				locate_size_cache(s->sha1, 0, s->size);
399 400 401 402
		}
		else {
			s->data = read_sha1_file(s->sha1, type, &s->size);
			s->should_free = 1;
403
		}
404 405 406 407 408 409 410 411 412 413 414
	}
	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 已提交
415
	s->data = NULL;
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 534
	static int atexit_asked = 0;

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

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

J
Junio C Hamano 已提交
602
static void run_diff(struct diff_filepair *p)
603 604
{
	const char *pgm = external_diff();
J
Junio C Hamano 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
	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) {
623
	case DIFF_STATUS_COPIED:
J
Junio C Hamano 已提交
624 625 626 627 628 629 630 631
		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;
632
	case DIFF_STATUS_RENAMED:
J
Junio C Hamano 已提交
633 634 635 636 637 638 639 640
		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;
641
	case DIFF_STATUS_MODIFIED:
J
Junio C Hamano 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654
		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;
	}

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

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

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
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';
		}
		*cp++;
	}
	*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)
{
717
	int opt1, opt2, cmd;
718 719 720 721 722 723 724 725

	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);
726 727 728 729 730 731 732 733 734 735 736 737
	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);
		}
	}
738 739
	if (*opt != 0)
		return -1;
740
	return opt1 | (opt2 << 16);
741 742
}

J
Junio C Hamano 已提交
743 744 745
struct diff_queue_struct diff_queued_diff;

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

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

770 771 772 773 774 775 776
void diff_free_filepair(struct diff_filepair *p)
{
	diff_free_filespec_data(p->one);
	diff_free_filespec_data(p->two);
	free(p);
}

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

	if (line_termination) {
785 786
		const char *const err =
			"path %s cannot be expressed without -z";
787 788 789 790 791 792 793 794
		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 已提交
795 796 797 798 799 800 801
	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;
	}
802
	switch (p->status) {
803 804
	case DIFF_STATUS_COPIED:
	case DIFF_STATUS_RENAMED:
805 806
		two_paths = 1;
		break;
807 808
	case DIFF_STATUS_ADDED:
	case DIFF_STATUS_DELETED:
809 810
		two_paths = 0;
		break;
811 812 813
	default:
		two_paths = 0;
		break;
J
Junio C Hamano 已提交
814
	}
815 816
	printf(":%06o %06o %s ",
	       p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
817 818 819 820 821 822 823 824
	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);
825 826
}

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

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

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

J
Junio C Hamano 已提交
845 846
	one = p->one;
	two = p->two;
847

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

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

867
static void diff_flush_patch(struct diff_filepair *p)
868 869 870 871 872 873 874 875
{
	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 已提交
876
	run_diff(p);
877 878
}

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

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

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

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

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

992 993
	if (!line_termination)
		inter_name_termination = 0;
994

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

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
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;

1033
	if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
1034 1035 1036
		int found;
		for (i = found = 0; !found && i < q->nr; i++) {
			struct diff_filepair *p = q->queue[i];
1037 1038 1039 1040 1041 1042 1043
			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)))
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
				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];
1061 1062 1063 1064 1065 1066 1067 1068

			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)))
1069 1070 1071 1072 1073 1074 1075 1076 1077
				diff_q(&outq, p);
			else
				diff_free_filepair(p);
		}
	}
	free(q->queue);
	*q = outq;
}

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

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

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

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

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

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

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

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

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

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

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