convert.c 19.0 KB
Newer Older
L
Linus Torvalds 已提交
1
#include "cache.h"
J
Junio C Hamano 已提交
2
#include "attr.h"
J
Junio C Hamano 已提交
3
#include "run-command.h"
4
#include "quote.h"
J
Junio C Hamano 已提交
5

L
Linus Torvalds 已提交
6 7 8 9 10 11
/*
 * convert.c - convert a file when checking it out and checking it in.
 *
 * This should use the pathname to decide on whether it wants to do some
 * more interesting conversions (automatic gzip/unzip, general format
 * conversions etc etc), but by default it just does automatic CRLF<->LF
12
 * translation when the "text" attribute or "auto_crlf" option is set.
L
Linus Torvalds 已提交
13 14
 */

15 16 17 18 19 20 21 22
enum action {
	CRLF_GUESS = -1,
	CRLF_BINARY = 0,
	CRLF_TEXT,
	CRLF_INPUT,
	CRLF_CRLF,
	CRLF_AUTO,
};
23

L
Linus Torvalds 已提交
24
struct text_stat {
25 26
	/* NUL, CR, LF and CRLF counts */
	unsigned nul, cr, lf, crlf;
L
Linus Torvalds 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

	/* These are just approximations! */
	unsigned printable, nonprintable;
};

static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
{
	unsigned long i;

	memset(stats, 0, sizeof(*stats));

	for (i = 0; i < size; i++) {
		unsigned char c = buf[i];
		if (c == '\r') {
			stats->cr++;
			if (i+1 < size && buf[i+1] == '\n')
				stats->crlf++;
			continue;
		}
		if (c == '\n') {
			stats->lf++;
			continue;
		}
		if (c == 127)
			/* DEL */
			stats->nonprintable++;
		else if (c < 32) {
			switch (c) {
				/* BS, HT, ESC and FF */
			case '\b': case '\t': case '\033': case '\014':
				stats->printable++;
				break;
59 60 61
			case 0:
				stats->nul++;
				/* fall through */
L
Linus Torvalds 已提交
62 63 64 65 66 67 68
			default:
				stats->nonprintable++;
			}
		}
		else
			stats->printable++;
	}
69 70 71 72

	/* If file ends with EOF then don't count this EOF as non-printable. */
	if (size >= 1 && buf[size-1] == '\032')
		stats->nonprintable--;
L
Linus Torvalds 已提交
73 74 75 76 77 78 79 80
}

/*
 * The same heuristics as diff.c::mmfile_is_binary()
 */
static int is_binary(unsigned long size, struct text_stat *stats)
{

81 82
	if (stats->nul)
		return 1;
L
Linus Torvalds 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96
	if ((stats->printable >> 7) < stats->nonprintable)
		return 1;
	/*
	 * Other heuristics? Average line length might be relevant,
	 * as might LF vs CR vs CRLF counts..
	 *
	 * NOTE! It might be normal to have a low ratio of CRLF to LF
	 * (somebody starts with a LF-only file and edits it with an editor
	 * that adds CRLF only to lines that are added..). But do  we
	 * want to support CR-only? Probably not.
	 */
	return 0;
}

97 98
static enum eol determine_output_conversion(enum action action)
{
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	switch (action) {
	case CRLF_BINARY:
		return EOL_UNSET;
	case CRLF_CRLF:
		return EOL_CRLF;
	case CRLF_INPUT:
		return EOL_LF;
	case CRLF_GUESS:
		if (!auto_crlf)
			return EOL_UNSET;
		/* fall through */
	case CRLF_TEXT:
	case CRLF_AUTO:
		if (auto_crlf == AUTO_CRLF_TRUE)
			return EOL_CRLF;
		else if (auto_crlf == AUTO_CRLF_INPUT)
			return EOL_LF;
		else if (eol == EOL_UNSET)
			return EOL_NATIVE;
	}
	return eol;
}

122
static void check_safe_crlf(const char *path, enum action action,
123 124 125 126 127
                            struct text_stat *stats, enum safe_crlf checksafe)
{
	if (!checksafe)
		return;

128
	if (determine_output_conversion(action) == EOL_LF) {
129 130 131 132 133 134
		/*
		 * CRLFs would not be restored by checkout:
		 * check if we'd remove CRLFs
		 */
		if (stats->crlf) {
			if (checksafe == SAFE_CRLF_WARN)
135
				warning("CRLF will be replaced by LF in %s.\nThe file will have its original line endings in your working directory.", path);
136 137 138
			else /* i.e. SAFE_CRLF_FAIL */
				die("CRLF would be replaced by LF in %s.", path);
		}
139
	} else if (determine_output_conversion(action) == EOL_CRLF) {
140 141 142 143 144 145
		/*
		 * CRLFs would be added by checkout:
		 * check if we have "naked" LFs
		 */
		if (stats->lf != stats->crlf) {
			if (checksafe == SAFE_CRLF_WARN)
146
				warning("LF will be replaced by CRLF in %s.\nThe file will have its original line endings in your working directory.", path);
147 148 149 150 151 152
			else /* i.e. SAFE_CRLF_FAIL */
				die("LF would be replaced by CRLF in %s", path);
		}
	}
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static int has_cr_in_index(const char *path)
{
	int pos, len;
	unsigned long sz;
	enum object_type type;
	void *data;
	int has_cr;
	struct index_state *istate = &the_index;

	len = strlen(path);
	pos = index_name_pos(istate, path, len);
	if (pos < 0) {
		/*
		 * We might be in the middle of a merge, in which
		 * case we would read stage #2 (ours).
		 */
		int i;
		for (i = -pos - 1;
		     (pos < 0 && i < istate->cache_nr &&
		      !strcmp(istate->cache[i]->name, path));
		     i++)
			if (ce_stage(istate->cache[i]) == 2)
				pos = i;
	}
	if (pos < 0)
		return 0;
	data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
	if (!data || type != OBJ_BLOB) {
		free(data);
		return 0;
	}

	has_cr = memchr(data, '\r', sz) != NULL;
	free(data);
	return has_cr;
}

190
static int crlf_to_git(const char *path, const char *src, size_t len,
191
		       struct strbuf *buf, enum action action, enum safe_crlf checksafe)
L
Linus Torvalds 已提交
192 193
{
	struct text_stat stats;
194
	char *dst;
L
Linus Torvalds 已提交
195

196 197
	if (action == CRLF_BINARY ||
	    (action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len)
198
		return 0;
L
Linus Torvalds 已提交
199

200
	gather_stats(src, len, &stats);
L
Linus Torvalds 已提交
201

202
	if (action == CRLF_AUTO || action == CRLF_GUESS) {
J
Junio C Hamano 已提交
203 204 205 206 207 208
		/*
		 * We're currently not going to even try to convert stuff
		 * that has bare CR characters. Does anybody do that crazy
		 * stuff?
		 */
		if (stats.cr != stats.crlf)
209
			return 0;
J
Junio C Hamano 已提交
210 211 212 213

		/*
		 * And add some heuristics for binary vs text, of course...
		 */
214 215
		if (is_binary(len, &stats))
			return 0;
216

217 218 219 220 221 222 223 224
		if (action == CRLF_GUESS) {
			/*
			 * If the file in the index has any CR in it, do not convert.
			 * This is the new safer autocrlf handling.
			 */
			if (has_cr_in_index(path))
				return 0;
		}
J
Junio C Hamano 已提交
225
	}
L
Linus Torvalds 已提交
226

227 228 229 230 231 232
	check_safe_crlf(path, action, &stats, checksafe);

	/* Optimization: No CR? Nothing to convert, regardless. */
	if (!stats.cr)
		return 0;

233 234 235
	/* only grow if not in place */
	if (strbuf_avail(buf) + buf->len < len)
		strbuf_grow(buf, len - buf->len);
236
	dst = buf->buf;
237
	if (action == CRLF_AUTO || action == CRLF_GUESS) {
238 239 240 241 242
		/*
		 * If we guessed, we already know we rejected a file with
		 * lone CR, and we can strip a CR without looking at what
		 * follow it.
		 */
J
Junio C Hamano 已提交
243
		do {
244
			unsigned char c = *src++;
J
Junio C Hamano 已提交
245
			if (c != '\r')
246
				*dst++ = c;
247
		} while (--len);
J
Junio C Hamano 已提交
248 249
	} else {
		do {
250
			unsigned char c = *src++;
251
			if (! (c == '\r' && (1 < len && *src == '\n')))
252
				*dst++ = c;
253
		} while (--len);
J
Junio C Hamano 已提交
254
	}
255 256
	strbuf_setlen(buf, dst - buf->buf);
	return 1;
L
Linus Torvalds 已提交
257 258
}

259
static int crlf_to_worktree(const char *path, const char *src, size_t len,
260
			    struct strbuf *buf, enum action action)
L
Linus Torvalds 已提交
261
{
262
	char *to_free = NULL;
L
Linus Torvalds 已提交
263 264
	struct text_stat stats;

265
	if (!len || determine_output_conversion(action) != EOL_CRLF)
266
		return 0;
L
Linus Torvalds 已提交
267

268
	gather_stats(src, len, &stats);
L
Linus Torvalds 已提交
269 270 271

	/* No LF? Nothing to convert, regardless. */
	if (!stats.lf)
272
		return 0;
L
Linus Torvalds 已提交
273 274 275

	/* Was it already in CRLF format? */
	if (stats.lf == stats.crlf)
276
		return 0;
L
Linus Torvalds 已提交
277

278 279 280 281 282 283 284
	if (action == CRLF_AUTO || action == CRLF_GUESS) {
		if (action == CRLF_GUESS) {
			/* If we have any CR or CRLF line endings, we do not touch it */
			/* This is the new safer autocrlf-handling */
			if (stats.cr > 0 || stats.crlf > 0)
				return 0;
		}
285

J
Junio C Hamano 已提交
286 287
		/* If we have any bare CR characters, we're not going to touch it */
		if (stats.cr != stats.crlf)
288
			return 0;
L
Linus Torvalds 已提交
289

290 291
		if (is_binary(len, &stats))
			return 0;
J
Junio C Hamano 已提交
292
	}
L
Linus Torvalds 已提交
293

294 295
	/* are we "faking" in place editing ? */
	if (src == buf->buf)
296
		to_free = strbuf_detach(buf, NULL);
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

	strbuf_grow(buf, len + stats.lf - stats.crlf);
	for (;;) {
		const char *nl = memchr(src, '\n', len);
		if (!nl)
			break;
		if (nl > src && nl[-1] == '\r') {
			strbuf_add(buf, src, nl + 1 - src);
		} else {
			strbuf_add(buf, src, nl - src);
			strbuf_addstr(buf, "\r\n");
		}
		len -= nl + 1 - src;
		src  = nl + 1;
	}
	strbuf_add(buf, src, len);

	free(to_free);
	return 1;
L
Linus Torvalds 已提交
316
}
J
Junio C Hamano 已提交
317

318 319 320 321
struct filter_params {
	const char *src;
	unsigned long size;
	const char *cmd;
322
	const char *path;
323 324
};

325
static int filter_buffer(int in, int out, void *data)
326 327 328 329 330
{
	/*
	 * Spawn cmd and feed the buffer contents through its stdin.
	 */
	struct child_process child_process;
331
	struct filter_params *params = (struct filter_params *)data;
332
	int write_err, status;
333 334
	const char *argv[] = { NULL, NULL };

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	/* apply % substitution to cmd */
	struct strbuf cmd = STRBUF_INIT;
	struct strbuf path = STRBUF_INIT;
	struct strbuf_expand_dict_entry dict[] = {
		{ "f", NULL, },
		{ NULL, NULL, },
	};

	/* quote the path to preserve spaces, etc. */
	sq_quote_buf(&path, params->path);
	dict[0].value = path.buf;

	/* expand all %f with the quoted path */
	strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
	strbuf_release(&path);

	argv[0] = cmd.buf;
352 353

	memset(&child_process, 0, sizeof(child_process));
354
	child_process.argv = argv;
355
	child_process.use_shell = 1;
356
	child_process.in = -1;
357
	child_process.out = out;
358

359
	if (start_command(&child_process))
360
		return error("cannot fork to run external filter %s", params->cmd);
361

362
	write_err = (write_in_full(child_process.in, params->src, params->size) < 0);
363
	if (close(child_process.in))
364 365
		write_err = 1;
	if (write_err)
366
		error("cannot feed the input to external filter %s", params->cmd);
367 368 369

	status = finish_command(&child_process);
	if (status)
370
		error("external filter %s failed %d", params->cmd, status);
371 372

	strbuf_release(&cmd);
373 374 375
	return (write_err || status);
}

376 377
static int apply_filter(const char *path, const char *src, size_t len,
                        struct strbuf *dst, const char *cmd)
378 379 380 381 382 383 384
{
	/*
	 * Create a pipeline to have the command filter the buffer's
	 * contents.
	 *
	 * (child --> cmd) --> us
	 */
385
	int ret = 1;
386
	struct strbuf nbuf = STRBUF_INIT;
387 388
	struct async async;
	struct filter_params params;
389 390

	if (!cmd)
391
		return 0;
392

393 394 395
	memset(&async, 0, sizeof(async));
	async.proc = filter_buffer;
	async.data = &params;
396
	async.out = -1;
397 398 399
	params.src = src;
	params.size = len;
	params.cmd = cmd;
400
	params.path = path;
401 402

	fflush(NULL);
403 404
	if (start_async(&async))
		return 0;	/* error was already reported */
405

406
	if (strbuf_read(&nbuf, async.out, len) < 0) {
407 408
		error("read from external filter %s failed", cmd);
		ret = 0;
409
	}
410
	if (close(async.out)) {
411
		error("read from external filter %s failed", cmd);
412
		ret = 0;
413
	}
414 415
	if (finish_async(&async)) {
		error("external filter %s failed", cmd);
416
		ret = 0;
417 418
	}

419
	if (ret) {
420
		strbuf_swap(dst, &nbuf);
421
	}
422
	strbuf_release(&nbuf);
423
	return ret;
424 425 426 427 428
}

static struct convert_driver {
	const char *name;
	struct convert_driver *next;
429 430
	const char *smudge;
	const char *clean;
431 432
} *user_convert, **user_convert_tail;

433
static int read_convert_config(const char *var, const char *value, void *cb)
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
{
	const char *ep, *name;
	int namelen;
	struct convert_driver *drv;

	/*
	 * External conversion drivers are configured using
	 * "filter.<name>.variable".
	 */
	if (prefixcmp(var, "filter.") || (ep = strrchr(var, '.')) == var + 6)
		return 0;
	name = var + 7;
	namelen = ep - name;
	for (drv = user_convert; drv; drv = drv->next)
		if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
			break;
	if (!drv) {
		drv = xcalloc(1, sizeof(struct convert_driver));
P
Pierre Habouzit 已提交
452
		drv->name = xmemdupz(name, namelen);
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
		*user_convert_tail = drv;
		user_convert_tail = &(drv->next);
	}

	ep++;

	/*
	 * filter.<name>.smudge and filter.<name>.clean specifies
	 * the command line:
	 *
	 *	command-line
	 *
	 * The command-line will not be interpolated in any way.
	 */

468 469 470 471 472
	if (!strcmp("smudge", ep))
		return git_config_string(&drv->smudge, var, value);

	if (!strcmp("clean", ep))
		return git_config_string(&drv->clean, var, value);
473 474 475 476

	return 0;
}

477
static void setup_convert_check(struct git_attr_check *check)
J
Junio C Hamano 已提交
478
{
479
	static struct git_attr *attr_text;
J
Junio C Hamano 已提交
480
	static struct git_attr *attr_crlf;
481
	static struct git_attr *attr_eol;
J
Junio C Hamano 已提交
482
	static struct git_attr *attr_ident;
483
	static struct git_attr *attr_filter;
J
Junio C Hamano 已提交
484

485 486
	if (!attr_text) {
		attr_text = git_attr("text");
487
		attr_crlf = git_attr("crlf");
488
		attr_eol = git_attr("eol");
489 490
		attr_ident = git_attr("ident");
		attr_filter = git_attr("filter");
491
		user_convert_tail = &user_convert;
492
		git_config(read_convert_config, NULL);
J
Junio C Hamano 已提交
493 494 495
	}
	check[0].attr = attr_crlf;
	check[1].attr = attr_ident;
496
	check[2].attr = attr_filter;
497
	check[3].attr = attr_eol;
498
	check[4].attr = attr_text;
J
Junio C Hamano 已提交
499 500 501 502 503
}

static int count_ident(const char *cp, unsigned long size)
{
	/*
504
	 * "$Id: 0000000000000000000000000000000000000000 $" <=> "$Id$"
J
Junio C Hamano 已提交
505 506 507 508 509 510 511 512 513
	 */
	int cnt = 0;
	char ch;

	while (size) {
		ch = *cp++;
		size--;
		if (ch != '$')
			continue;
514
		if (size < 3)
J
Junio C Hamano 已提交
515
			break;
516
		if (memcmp("Id", cp, 2))
J
Junio C Hamano 已提交
517
			continue;
518 519 520
		ch = cp[2];
		cp += 3;
		size -= 3;
J
Junio C Hamano 已提交
521
		if (ch == '$')
522
			cnt++; /* $Id$ */
J
Junio C Hamano 已提交
523 524 525 526
		if (ch != ':')
			continue;

		/*
527
		 * "$Id: ... "; scan up to the closing dollar sign and discard.
J
Junio C Hamano 已提交
528 529 530 531 532 533 534 535
		 */
		while (size) {
			ch = *cp++;
			size--;
			if (ch == '$') {
				cnt++;
				break;
			}
536 537
			if (ch == '\n')
				break;
J
Junio C Hamano 已提交
538 539 540 541 542
		}
	}
	return cnt;
}

543 544
static int ident_to_git(const char *path, const char *src, size_t len,
                        struct strbuf *buf, int ident)
J
Junio C Hamano 已提交
545
{
546
	char *dst, *dollar;
J
Junio C Hamano 已提交
547

548 549 550
	if (!ident || !count_ident(src, len))
		return 0;

551 552 553
	/* only grow if not in place */
	if (strbuf_avail(buf) + buf->len < len)
		strbuf_grow(buf, len - buf->len);
554 555 556 557 558 559 560 561 562 563 564 565 566 567
	dst = buf->buf;
	for (;;) {
		dollar = memchr(src, '$', len);
		if (!dollar)
			break;
		memcpy(dst, src, dollar + 1 - src);
		dst += dollar + 1 - src;
		len -= dollar + 1 - src;
		src  = dollar + 1;

		if (len > 3 && !memcmp(src, "Id:", 3)) {
			dollar = memchr(src + 3, '$', len - 3);
			if (!dollar)
				break;
568 569 570 571 572
			if (memchr(src + 3, '\n', dollar - src - 3)) {
				/* Line break before the next dollar. */
				continue;
			}

573 574
			memcpy(dst, "Id$", 3);
			dst += 3;
575 576
			len -= dollar + 1 - src;
			src  = dollar + 1;
J
Junio C Hamano 已提交
577 578
		}
	}
579 580 581
	memcpy(dst, src, len);
	strbuf_setlen(buf, dst + len - buf->buf);
	return 1;
J
Junio C Hamano 已提交
582 583
}

584 585
static int ident_to_worktree(const char *path, const char *src, size_t len,
                             struct strbuf *buf, int ident)
J
Junio C Hamano 已提交
586 587
{
	unsigned char sha1[20];
588
	char *to_free = NULL, *dollar, *spc;
589
	int cnt;
J
Junio C Hamano 已提交
590 591

	if (!ident)
592
		return 0;
J
Junio C Hamano 已提交
593

594
	cnt = count_ident(src, len);
J
Junio C Hamano 已提交
595
	if (!cnt)
596
		return 0;
J
Junio C Hamano 已提交
597

598 599
	/* are we "faking" in place editing ? */
	if (src == buf->buf)
600
		to_free = strbuf_detach(buf, NULL);
601
	hash_sha1_file(src, len, "blob", sha1);
J
Junio C Hamano 已提交
602

603 604 605 606 607 608 609 610 611
	strbuf_grow(buf, len + cnt * 43);
	for (;;) {
		/* step 1: run to the next '$' */
		dollar = memchr(src, '$', len);
		if (!dollar)
			break;
		strbuf_add(buf, src, dollar + 1 - src);
		len -= dollar + 1 - src;
		src  = dollar + 1;
612

613 614
		/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
		if (len < 3 || memcmp("Id", src, 2))
J
Junio C Hamano 已提交
615 616
			continue;

617 618 619 620 621 622 623
		/* step 3: skip over Id$ or Id:xxxxx$ */
		if (src[2] == '$') {
			src += 3;
			len -= 3;
		} else if (src[2] == ':') {
			/*
			 * It's possible that an expanded Id has crept its way into the
624 625 626 627
			 * repository, we cope with that by stripping the expansion out.
			 * This is probably not a good idea, since it will cause changes
			 * on checkout, which won't go away by stash, but let's keep it
			 * for git-style ids.
628 629 630 631 632 633
			 */
			dollar = memchr(src + 3, '$', len - 3);
			if (!dollar) {
				/* incomplete keyword, no more '$', so just quit the loop */
				break;
			}
634

635 636 637 638 639
			if (memchr(src + 3, '\n', dollar - src - 3)) {
				/* Line break before the next dollar. */
				continue;
			}

640 641 642 643 644 645 646 647 648
			spc = memchr(src + 4, ' ', dollar - src - 4);
			if (spc && spc < dollar-1) {
				/* There are spaces in unexpected places.
				 * This is probably an id from some other
				 * versioning system. Keep it for now.
				 */
				continue;
			}

649 650 651 652 653 654
			len -= dollar + 1 - src;
			src  = dollar + 1;
		} else {
			/* it wasn't a "Id$" or "Id:xxxx$" */
			continue;
		}
655

656 657 658 659
		/* step 4: substitute */
		strbuf_addstr(buf, "Id: ");
		strbuf_add(buf, sha1_to_hex(sha1), 40);
		strbuf_addstr(buf, " $");
J
Junio C Hamano 已提交
660
	}
661
	strbuf_add(buf, src, len);
J
Junio C Hamano 已提交
662

663 664
	free(to_free);
	return 1;
J
Junio C Hamano 已提交
665 666
}

667
static int git_path_check_crlf(const char *path, struct git_attr_check *check)
J
Junio C Hamano 已提交
668
{
669 670 671 672 673 674 675 676 677 678
	const char *value = check->value;

	if (ATTR_TRUE(value))
		return CRLF_TEXT;
	else if (ATTR_FALSE(value))
		return CRLF_BINARY;
	else if (ATTR_UNSET(value))
		;
	else if (!strcmp(value, "input"))
		return CRLF_INPUT;
679 680
	else if (!strcmp(value, "auto"))
		return CRLF_AUTO;
681
	return CRLF_GUESS;
J
Junio C Hamano 已提交
682 683
}

684 685 686 687 688 689 690 691 692 693 694 695 696
static int git_path_check_eol(const char *path, struct git_attr_check *check)
{
	const char *value = check->value;

	if (ATTR_UNSET(value))
		;
	else if (!strcmp(value, "lf"))
		return EOL_LF;
	else if (!strcmp(value, "crlf"))
		return EOL_CRLF;
	return EOL_UNSET;
}

697 698 699 700 701 702 703 704 705 706 707 708 709 710
static struct convert_driver *git_path_check_convert(const char *path,
					     struct git_attr_check *check)
{
	const char *value = check->value;
	struct convert_driver *drv;

	if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
		return NULL;
	for (drv = user_convert; drv; drv = drv->next)
		if (!strcmp(value, drv->name))
			return drv;
	return NULL;
}

J
Junio C Hamano 已提交
711 712 713 714 715 716 717
static int git_path_check_ident(const char *path, struct git_attr_check *check)
{
	const char *value = check->value;

	return !!ATTR_TRUE(value);
}

718 719
static enum action determine_action(enum action text_attr, enum eol eol_attr)
{
720
	if (text_attr == CRLF_BINARY)
721 722 723 724 725
		return CRLF_BINARY;
	if (eol_attr == EOL_LF)
		return CRLF_INPUT;
	if (eol_attr == EOL_CRLF)
		return CRLF_CRLF;
726
	return text_attr;
727 728
}

729 730
int convert_to_git(const char *path, const char *src, size_t len,
                   struct strbuf *dst, enum safe_crlf checksafe)
J
Junio C Hamano 已提交
731
{
732
	struct git_attr_check check[5];
733
	enum action action = CRLF_GUESS;
734
	enum eol eol_attr = EOL_UNSET;
735
	int ident = 0, ret = 0;
736
	const char *filter = NULL;
737 738

	setup_convert_check(check);
J
Junio C Hamano 已提交
739
	if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
740
		struct convert_driver *drv;
741 742 743
		action = git_path_check_crlf(path, check + 4);
		if (action == CRLF_GUESS)
			action = git_path_check_crlf(path, check + 0);
J
Junio C Hamano 已提交
744
		ident = git_path_check_ident(path, check + 1);
745
		drv = git_path_check_convert(path, check + 2);
746
		eol_attr = git_path_check_eol(path, check + 3);
747 748
		if (drv && drv->clean)
			filter = drv->clean;
J
Junio C Hamano 已提交
749 750
	}

751 752 753 754
	ret |= apply_filter(path, src, len, dst, filter);
	if (ret) {
		src = dst->buf;
		len = dst->len;
755
	}
756
	action = determine_action(action, eol_attr);
757
	ret |= crlf_to_git(path, src, len, dst, action, checksafe);
758 759 760
	if (ret) {
		src = dst->buf;
		len = dst->len;
761
	}
762
	return ret | ident_to_git(path, src, len, dst, ident);
J
Junio C Hamano 已提交
763 764
}

765 766 767
static int convert_to_working_tree_internal(const char *path, const char *src,
					    size_t len, struct strbuf *dst,
					    int normalizing)
J
Junio C Hamano 已提交
768
{
769
	struct git_attr_check check[5];
770
	enum action action = CRLF_GUESS;
771
	enum eol eol_attr = EOL_UNSET;
772
	int ident = 0, ret = 0;
773
	const char *filter = NULL;
774 775

	setup_convert_check(check);
J
Junio C Hamano 已提交
776
	if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
777
		struct convert_driver *drv;
778 779 780
		action = git_path_check_crlf(path, check + 4);
		if (action == CRLF_GUESS)
			action = git_path_check_crlf(path, check + 0);
J
Junio C Hamano 已提交
781
		ident = git_path_check_ident(path, check + 1);
782
		drv = git_path_check_convert(path, check + 2);
783
		eol_attr = git_path_check_eol(path, check + 3);
784 785
		if (drv && drv->smudge)
			filter = drv->smudge;
786
	}
J
Junio C Hamano 已提交
787

788 789 790 791
	ret |= ident_to_worktree(path, src, len, dst, ident);
	if (ret) {
		src = dst->buf;
		len = dst->len;
J
Junio C Hamano 已提交
792
	}
793 794 795 796 797 798 799 800 801 802 803
	/*
	 * CRLF conversion can be skipped if normalizing, unless there
	 * is a smudge filter.  The filter might expect CRLFs.
	 */
	if (filter || !normalizing) {
		action = determine_action(action, eol_attr);
		ret |= crlf_to_worktree(path, src, len, dst, action);
		if (ret) {
			src = dst->buf;
			len = dst->len;
		}
804
	}
805
	return ret | apply_filter(path, src, len, dst, filter);
J
Junio C Hamano 已提交
806
}
807

808 809 810 811 812
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
{
	return convert_to_working_tree_internal(path, src, len, dst, 0);
}

813 814
int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
{
815
	int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
816 817 818 819 820 821
	if (ret) {
		src = dst->buf;
		len = dst->len;
	}
	return ret | convert_to_git(path, src, len, dst, 0);
}