From: Junio C Hamano <gitster@pobox.com>
Date: Tue, 15 Sep 2009 10:38:30 +0000 (-0700)
Subject: Merge branch 'jc/maint-1.6.0-blank-at-eof' (early part) into jc/maint-blank-at-eof
X-Git-Tag: v1.6.5.3~11^2~2
X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/bb35fefbc952d5661d8b675aa5e0c1c49c515487

Merge branch 'jc/maint-1.6.0-blank-at-eof' (early part) into jc/maint-blank-at-eof

* 'jc/maint-1.6.0-blank-at-eof' (early part):
diff.c: shuffling code around
---

bb35fefbc952d5661d8b675aa5e0c1c49c515487
diff --cc diff.c
index 87a3e8956b,75489665ba..e03b16c006
--- a/diff.c
+++ b/diff.c
@@@ -174,93 -241,191 +174,218 @@@ static struct diff_tempfile 
  	char tmp_path[PATH_MAX];
  } diff_temp[2];
  
+ typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
+ 
+ struct emit_callback {
 -	struct xdiff_emit_state xm;
+ 	int color_diff;
+ 	unsigned ws_rule;
+ 	int blank_at_eof_in_preimage;
+ 	int blank_at_eof_in_postimage;
+ 	int lno_in_preimage;
+ 	int lno_in_postimage;
+ 	sane_truncate_fn truncate;
+ 	const char **label_path;
+ 	struct diff_words_data *diff_words;
+ 	int *found_changesp;
+ 	FILE *file;
+ };
+ 
+ static int count_lines(const char *data, int size)
+ {
+ 	int count, ch, completely_empty = 1, nl_just_seen = 0;
+ 	count = 0;
+ 	while (0 < size--) {
+ 		ch = *data++;
+ 		if (ch == '\n') {
+ 			count++;
+ 			nl_just_seen = 1;
+ 			completely_empty = 0;
+ 		}
+ 		else {
+ 			nl_just_seen = 0;
+ 			completely_empty = 0;
+ 		}
+ 	}
+ 	if (completely_empty)
+ 		return 0;
+ 	if (!nl_just_seen)
+ 		count++; /* no trailing newline */
+ 	return count;
+ }
+ 
 -static void print_line_count(FILE *file, int count)
 -{
 -	switch (count) {
 -	case 0:
 -		fprintf(file, "0,0");
 -		break;
 -	case 1:
 -		fprintf(file, "1");
 -		break;
 -	default:
 -		fprintf(file, "1,%d", count);
 -		break;
 -	}
 -}
 -
 -static void copy_file_with_prefix(FILE *file,
 -				  int prefix, const char *data, int size,
 -				  const char *set, const char *reset)
 -{
 -	int ch, nl_just_seen = 1;
 -	while (0 < size--) {
 -		ch = *data++;
 -		if (nl_just_seen) {
 -			fputs(set, file);
 -			putc(prefix, file);
 -		}
 -		if (ch == '\n') {
 -			nl_just_seen = 1;
 -			fputs(reset, file);
 -		} else
 -			nl_just_seen = 0;
 -		putc(ch, file);
 -	}
 -	if (!nl_just_seen)
 -		fprintf(file, "%s\n\\ No newline at end of file\n", reset);
 -}
 -
+ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
+ {
+ 	if (!DIFF_FILE_VALID(one)) {
+ 		mf->ptr = (char *)""; /* does not matter */
+ 		mf->size = 0;
+ 		return 0;
+ 	}
+ 	else if (diff_populate_filespec(one, 0))
+ 		return -1;
++
+ 	mf->ptr = one->data;
+ 	mf->size = one->size;
+ 	return 0;
+ }
+ 
+ static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
+ {
+ 	char *ptr = mf->ptr;
+ 	long size = mf->size;
+ 	int cnt = 0;
+ 
+ 	if (!size)
+ 		return cnt;
+ 	ptr += size - 1; /* pointing at the very end */
+ 	if (*ptr != '\n')
+ 		; /* incomplete line */
+ 	else
+ 		ptr--; /* skip the last LF */
+ 	while (mf->ptr < ptr) {
+ 		char *prev_eol;
+ 		for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--)
+ 			if (*prev_eol == '\n')
+ 				break;
+ 		if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule))
+ 			break;
+ 		cnt++;
+ 		ptr = prev_eol - 1;
+ 	}
+ 	return cnt;
+ }
+ 
+ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
+ 			       struct emit_callback *ecbdata)
+ {
+ 	int l1, l2, at;
+ 	unsigned ws_rule = ecbdata->ws_rule;
+ 	l1 = count_trailing_blank(mf1, ws_rule);
+ 	l2 = count_trailing_blank(mf2, ws_rule);
+ 	if (l2 <= l1) {
+ 		ecbdata->blank_at_eof_in_preimage = 0;
+ 		ecbdata->blank_at_eof_in_postimage = 0;
+ 		return;
+ 	}
+ 	at = count_lines(mf1->ptr, mf1->size);
+ 	ecbdata->blank_at_eof_in_preimage = (at - l1) + 1;
+ 
+ 	at = count_lines(mf2->ptr, mf2->size);
+ 	ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
+ }
+ 
+ static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
+ {
+ 	int has_trailing_newline, has_trailing_carriage_return;
+ 
+ 	has_trailing_newline = (len > 0 && line[len-1] == '\n');
+ 	if (has_trailing_newline)
+ 		len--;
+ 	has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
+ 	if (has_trailing_carriage_return)
+ 		len--;
+ 
+ 	fputs(set, file);
+ 	fwrite(line, len, 1, file);
+ 	fputs(reset, file);
+ 	if (has_trailing_carriage_return)
+ 		fputc('\r', file);
+ 	if (has_trailing_newline)
+ 		fputc('\n', file);
+ }
+ 
+ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len)
+ {
+ 	if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) &&
+ 	      ecbdata->blank_at_eof_in_preimage &&
+ 	      ecbdata->blank_at_eof_in_postimage &&
+ 	      ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage &&
+ 	      ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage))
+ 		return 0;
+ 	return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule);
+ }
+ 
+ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
+ {
+ 	const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
+ 	const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
+ 
+ 	if (!*ws)
+ 		emit_line(ecbdata->file, set, reset, line, len);
+ 	else if (new_blank_line_at_eof(ecbdata, line, len))
+ 		/* Blank line at EOF - paint '+' as well */
+ 		emit_line(ecbdata->file, ws, reset, line, len);
+ 	else {
+ 		/* Emit just the prefix, then the rest. */
+ 		emit_line(ecbdata->file, set, reset, line, 1);
+ 		ws_check_emit(line + 1, len - 1, ecbdata->ws_rule,
+ 			      ecbdata->file, set, reset, ws);
+ 	}
+ }
+ 
 +static struct diff_tempfile *claim_diff_tempfile(void) {
 +	int i;
 +	for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
 +		if (!diff_temp[i].name)
 +			return diff_temp + i;
 +	die("BUG: diff is failing to clean up its tempfiles");
 +}
 +
 +static int remove_tempfile_installed;
 +
 +static void remove_tempfile(void)
 +{
 +	int i;
 +	for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
 +		if (diff_temp[i].name == diff_temp[i].tmp_path)
 +			unlink_or_warn(diff_temp[i].name);
 +		diff_temp[i].name = NULL;
 +	}
 +}
 +
 +static void remove_tempfile_on_signal(int signo)
 +{
 +	remove_tempfile();
 +	sigchain_pop(signo);
 +	raise(signo);
 +}
 +
- static int count_lines(const char *data, int size)
- {
- 	int count, ch, completely_empty = 1, nl_just_seen = 0;
- 	count = 0;
- 	while (0 < size--) {
- 		ch = *data++;
- 		if (ch == '\n') {
- 			count++;
- 			nl_just_seen = 1;
- 			completely_empty = 0;
- 		}
- 		else {
- 			nl_just_seen = 0;
- 			completely_empty = 0;
- 		}
- 	}
- 	if (completely_empty)
- 		return 0;
- 	if (!nl_just_seen)
- 		count++; /* no trailing newline */
- 	return count;
- }
- 
 +static void print_line_count(FILE *file, int count)
 +{
 +	switch (count) {
 +	case 0:
 +		fprintf(file, "0,0");
 +		break;
 +	case 1:
 +		fprintf(file, "1");
 +		break;
 +	default:
 +		fprintf(file, "1,%d", count);
 +		break;
 +	}
 +}
 +
 +static void copy_file_with_prefix(FILE *file,
 +				  int prefix, const char *data, int size,
 +				  const char *set, const char *reset)
 +{
 +	int ch, nl_just_seen = 1;
 +	while (0 < size--) {
 +		ch = *data++;
 +		if (nl_just_seen) {
 +			fputs(set, file);
 +			putc(prefix, file);
 +		}
 +		if (ch == '\n') {
 +			nl_just_seen = 1;
 +			fputs(reset, file);
 +		} else
 +			nl_just_seen = 0;
 +		putc(ch, file);
 +	}
 +	if (!nl_just_seen)
 +		fprintf(file, "%s\n\\ No newline at end of file\n", reset);
 +}
 +
  static void emit_rewrite_diff(const char *name_a,
  			      const char *name_b,
  			      struct diff_filespec *one,
@@@ -332,26 -465,11 +457,11 @@@
  	print_line_count(o->file, lc_b);
  	fprintf(o->file, " @@%s\n", reset);
  	if (lc_a)
 -		copy_file_with_prefix(o->file, '-', one->data, one->size, old, reset);
 +		copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset);
  	if (lc_b)
 -		copy_file_with_prefix(o->file, '+', two->data, two->size, new, reset);
 +		copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset);
  }
  
- static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
- {
- 	if (!DIFF_FILE_VALID(one)) {
- 		mf->ptr = (char *)""; /* does not matter */
- 		mf->size = 0;
- 		return 0;
- 	}
- 	else if (diff_populate_filespec(one, 0))
- 		return -1;
- 
- 	mf->ptr = one->data;
- 	mf->size = one->size;
- 	return 0;
- }
- 
  struct diff_words_buffer {
  	mmfile_t text;
  	long alloc;
@@@ -497,54 -560,42 +607,38 @@@ static void diff_words_show(struct diff
  	xdemitconf_t xecfg;
  	xdemitcb_t ecb;
  	mmfile_t minus, plus;
 -	int i;
  
 -	memset(&xecfg, 0, sizeof(xecfg));
 -	minus.size = diff_words->minus.text.size;
 -	minus.ptr = xmalloc(minus.size);
 -	memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
 -	for (i = 0; i < minus.size; i++)
 -		if (isspace(minus.ptr[i]))
 -			minus.ptr[i] = '\n';
 -	diff_words->minus.current = 0;
 -
 -	plus.size = diff_words->plus.text.size;
 -	plus.ptr = xmalloc(plus.size);
 -	memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
 -	for (i = 0; i < plus.size; i++)
 -		if (isspace(plus.ptr[i]))
 -			plus.ptr[i] = '\n';
 -	diff_words->plus.current = 0;
 +	/* special case: only removal */
 +	if (!diff_words->plus.text.size) {
 +		color_fwrite_lines(diff_words->file,
 +			diff_get_color(1, DIFF_FILE_OLD),
 +			diff_words->minus.text.size, diff_words->minus.text.ptr);
 +		diff_words->minus.text.size = 0;
 +		return;
 +	}
  
 -	xpp.flags = XDF_NEED_MINIMAL;
 -	xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
 -	ecb.outf = xdiff_outf;
 -	ecb.priv = diff_words;
 -	diff_words->xm.consume = fn_out_diff_words_aux;
 -	xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 +	diff_words->current_plus = diff_words->plus.text.ptr;
  
 +	memset(&xpp, 0, sizeof(xpp));
 +	memset(&xecfg, 0, sizeof(xecfg));
 +	diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
 +	diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
 +	xpp.flags = XDF_NEED_MINIMAL;
 +	/* as only the hunk header will be parsed, we need a 0-context */
 +	xecfg.ctxlen = 0;
 +	xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
 +		      &xpp, &xecfg, &ecb);
  	free(minus.ptr);
  	free(plus.ptr);
 +	if (diff_words->current_plus != diff_words->plus.text.ptr +
 +			diff_words->plus.text.size)
 +		fwrite(diff_words->current_plus,
 +			diff_words->plus.text.ptr + diff_words->plus.text.size
 +			- diff_words->current_plus, 1,
 +			diff_words->file);
  	diff_words->minus.text.size = diff_words->plus.text.size = 0;
 -
 -	if (diff_words->minus.suppressed_newline) {
 -		putc('\n', diff_words->file);
 -		diff_words->minus.suppressed_newline = 0;
 -	}
  }
  
- typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
- 
- struct emit_callback {
- 	int color_diff;
- 	unsigned ws_rule;
- 	int blank_at_eof_in_preimage;
- 	int blank_at_eof_in_postimage;
- 	int lno_in_preimage;
- 	int lno_in_postimage;
- 	sane_truncate_fn truncate;
- 	const char **label_path;
- 	struct diff_words_data *diff_words;
- 	int *found_changesp;
- 	FILE *file;
- };
- 
  static void free_diff_words_data(struct emit_callback *ecbdata)
  {
  	if (ecbdata->diff_words) {
@@@ -1393,108 -1390,125 +1438,63 @@@ static void emit_binary_diff(FILE *file
  	emit_binary_diff_body(file, two, one);
  }
  
 -static void setup_diff_attr_check(struct git_attr_check *check)
 +static void diff_filespec_load_driver(struct diff_filespec *one)
  {
 -	static struct git_attr *attr_diff;
 -
 -	if (!attr_diff) {
 -		attr_diff = git_attr("diff", 4);
 -	}
 -	check[0].attr = attr_diff;
 +	if (!one->driver)
 +		one->driver = userdiff_find_by_path(one->path);
 +	if (!one->driver)
 +		one->driver = userdiff_find_by_name("default");
  }
  
 -static void diff_filespec_check_attr(struct diff_filespec *one)
 +int diff_filespec_is_binary(struct diff_filespec *one)
  {
 -	struct git_attr_check attr_diff_check;
 -	int check_from_data = 0;
 -
 -	if (one->checked_attr)
 -		return;
 -
 -	setup_diff_attr_check(&attr_diff_check);
 -	one->is_binary = 0;
 -	one->funcname_pattern_ident = NULL;
 -
 -	if (!git_checkattr(one->path, 1, &attr_diff_check)) {
 -		const char *value;
 -
 -		/* binaryness */
 -		value = attr_diff_check.value;
 -		if (ATTR_TRUE(value))
 -			;
 -		else if (ATTR_FALSE(value))
 -			one->is_binary = 1;
 -		else
 -			check_from_data = 1;
 -
 -		/* funcname pattern ident */
 -		if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
 -			;
 -		else
 -			one->funcname_pattern_ident = value;
 -	}
 -
 -	if (check_from_data) {
 -		if (!one->data && DIFF_FILE_VALID(one))
 -			diff_populate_filespec(one, 0);
 -
 -		if (one->data)
 -			one->is_binary = buffer_is_binary(one->data, one->size);
 +	if (one->is_binary == -1) {
 +		diff_filespec_load_driver(one);
 +		if (one->driver->binary != -1)
 +			one->is_binary = one->driver->binary;
 +		else {
 +			if (!one->data && DIFF_FILE_VALID(one))
 +				diff_populate_filespec(one, 0);
 +			if (one->data)
 +				one->is_binary = buffer_is_binary(one->data,
 +						one->size);
 +			if (one->is_binary == -1)
 +				one->is_binary = 0;
 +		}
  	}
 +	return one->is_binary;
  }
  
 -int diff_filespec_is_binary(struct diff_filespec *one)
 +static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)
  {
 -	diff_filespec_check_attr(one);
 -	return one->is_binary;
 +	diff_filespec_load_driver(one);
 +	return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
  }
  
 -static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
 -{
 -	struct funcname_pattern_list *pp;
 -
 -	for (pp = funcname_pattern_list; pp; pp = pp->next)
 -		if (!strcmp(ident, pp->e.name))
 -			return &pp->e;
 -	return NULL;
 -}
 -
 -static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
 -	{ "java",
 -	  "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
 -	  "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
 -	  REG_EXTENDED },
 -	{ "pascal",
 -	  "^((procedure|function|constructor|destructor|interface|"
 -		"implementation|initialization|finalization)[ \t]*.*)$"
 -	  "|"
 -	  "^(.*=[ \t]*(class|record).*)$",
 -	  REG_EXTENDED },
 -	{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
 -	  REG_EXTENDED },
 -	{ "tex",
 -	  "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
 -	  REG_EXTENDED },
 -	{ "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
 -	  REG_EXTENDED },
 -};
 -
 -static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
 +static const char *userdiff_word_regex(struct diff_filespec *one)
  {
 -	const char *ident;
 -	const struct funcname_pattern_entry *pe;
 -	int i;
 -
 -	diff_filespec_check_attr(one);
 -	ident = one->funcname_pattern_ident;
 -
 -	if (!ident)
 -		/*
 -		 * If the config file has "funcname.default" defined, that
 -		 * regexp is used; otherwise NULL is returned and xemit uses
 -		 * the built-in default.
 -		 */
 -		return funcname_pattern("default");
 -
 -	/* Look up custom "funcname.$ident" regexp from config. */
 -	pe = funcname_pattern(ident);
 -	if (pe)
 -		return pe;
 +	diff_filespec_load_driver(one);
 +	return one->driver->word_regex;
 +}
  
 -	/*
 -	 * And define built-in fallback patterns here.  Note that
 -	 * these can be overridden by the user's config settings.
 -	 */
 -	for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
 -		if (!strcmp(ident, builtin_funcname_pattern[i].name))
 -			return &builtin_funcname_pattern[i];
 +void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
 +{
 +	if (!options->a_prefix)
 +		options->a_prefix = a;
 +	if (!options->b_prefix)
 +		options->b_prefix = b;
 +}
  
 -	return NULL;
 +static const char *get_textconv(struct diff_filespec *one)
 +{
 +	if (!DIFF_FILE_VALID(one))
 +		return NULL;
 +	if (!S_ISREG(one->mode))
 +		return NULL;
 +	diff_filespec_load_driver(one);
 +	return one->driver->textconv;
  }
  
- static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
- {
- 	char *ptr = mf->ptr;
- 	long size = mf->size;
- 	int cnt = 0;
- 
- 	if (!size)
- 		return cnt;
- 	ptr += size - 1; /* pointing at the very end */
- 	if (*ptr != '\n')
- 		; /* incomplete line */
- 	else
- 		ptr--; /* skip the last LF */
- 	while (mf->ptr < ptr) {
- 		char *prev_eol;
- 		for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--)
- 			if (*prev_eol == '\n')
- 				break;
- 		if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule))
- 			break;
- 		cnt++;
- 		ptr = prev_eol - 1;
- 	}
- 	return cnt;
- }
- 
- static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
- 			       struct emit_callback *ecbdata)
- {
- 	int l1, l2, at;
- 	unsigned ws_rule = ecbdata->ws_rule;
- 	l1 = count_trailing_blank(mf1, ws_rule);
- 	l2 = count_trailing_blank(mf2, ws_rule);
- 	if (l2 <= l1) {
- 		ecbdata->blank_at_eof_in_preimage = 0;
- 		ecbdata->blank_at_eof_in_postimage = 0;
- 		return;
- 	}
- 	at = count_lines(mf1->ptr, mf1->size);
- 	ecbdata->blank_at_eof_in_preimage = (at - l1) + 1;
- 
- 	at = count_lines(mf2->ptr, mf2->size);
- 	ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
- }
- 
  static void builtin_diff(const char *name_a,
  			 const char *name_b,
  			 struct diff_filespec *one,