diff options
Diffstat (limited to 'xdiff/xmerge.c')
| -rw-r--r-- | xdiff/xmerge.c | 107 | 
1 files changed, 87 insertions, 20 deletions
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 625198e058..f338ad6c75 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,  	return 0;  } -static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)  {  	xrecord_t **recs;  	int size = 0; @@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add  	if (add_nl) {  		i = recs[count - 1]->size;  		if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') { +			if (needs_cr) { +				if (dest) +					dest[size] = '\r'; +				size++; +			} +  			if (dest)  				dest[size] = '\n';  			size++; @@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add  	return size;  } -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ +	return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest); +} + +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest) +{ +	return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest); +} + +/* + * Returns 1 if the i'th line ends in CR/LF (if it is the last line and + * has no eol, the preceding line, if any), 0 if it ends in LF-only, and + * -1 if the line ending cannot be determined. + */ +static int is_eol_crlf(xdfile_t *file, int i)  { -	return xdl_recs_copy_0(0, xe, i, count, add_nl, dest); +	long size; + +	if (i < file->nrec - 1) +		/* All lines before the last *must* end in LF */ +		return (size = file->recs[i]->size) > 1 && +			file->recs[i]->ptr[size - 2] == '\r'; +	if (!file->nrec) +		/* Cannot determine eol style from empty file */ +		return -1; +	if ((size = file->recs[i]->size) && +			file->recs[i]->ptr[size - 1] == '\n') +		/* Last line; ends in LF; Is it CR/LF? */ +		return size > 1 && +			file->recs[i]->ptr[size - 2] == '\r'; +	if (!i) +		/* The only line has no eol */ +		return -1; +	/* Determine eol from second-to-last line */ +	return (size = file->recs[i - 1]->size) > 1 && +		file->recs[i - 1]->ptr[size - 2] == '\r';  } -static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest) +static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)  { -	return xdl_recs_copy_0(1, xe, i, count, add_nl, dest); +	int needs_cr; + +	/* Match post-images' preceding, or first, lines' end-of-line style */ +	needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0); +	if (needs_cr) +		needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0); +	/* Look at pre-image's first line, unless we already settled on LF */ +	if (needs_cr) +		needs_cr = is_eol_crlf(&xe1->xdf1, 0); +	/* If still undecided, use LF-only */ +	return needs_cr < 0 ? 0 : needs_cr;  }  static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1, @@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,  	int marker1_size = (name1 ? strlen(name1) + 1 : 0);  	int marker2_size = (name2 ? strlen(name2) + 1 : 0);  	int marker3_size = (name3 ? strlen(name3) + 1 : 0); +	int needs_cr = is_cr_needed(xe1, xe2, m);  	if (marker_size <= 0)  		marker_size = DEFAULT_CONFLICT_MARKER_SIZE;  	/* Before conflicting part */ -	size += xdl_recs_copy(xe1, i, m->i1 - i, 0, +	size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,  			      dest ? dest + size : NULL);  	if (!dest) { -		size += marker_size + 1 + marker1_size; +		size += marker_size + 1 + needs_cr + marker1_size;  	} else {  		memset(dest + size, '<', marker_size);  		size += marker_size; @@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,  			memcpy(dest + size + 1, name1, marker1_size - 1);  			size += marker1_size;  		} +		if (needs_cr) +			dest[size++] = '\r';  		dest[size++] = '\n';  	}  	/* Postimage from side #1 */ -	size += xdl_recs_copy(xe1, m->i1, m->chg1, 1, +	size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,  			      dest ? dest + size : NULL);  	if (style == XDL_MERGE_DIFF3) {  		/* Shared preimage */  		if (!dest) { -			size += marker_size + 1 + marker3_size; +			size += marker_size + 1 + needs_cr + marker3_size;  		} else {  			memset(dest + size, '|', marker_size);  			size += marker_size; @@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,  				memcpy(dest + size + 1, name3, marker3_size - 1);  				size += marker3_size;  			} +			if (needs_cr) +				dest[size++] = '\r';  			dest[size++] = '\n';  		} -		size += xdl_orig_copy(xe1, m->i0, m->chg0, 1, +		size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,  				      dest ? dest + size : NULL);  	}  	if (!dest) { -		size += marker_size + 1; +		size += marker_size + 1 + needs_cr;  	} else {  		memset(dest + size, '=', marker_size);  		size += marker_size; +		if (needs_cr) +			dest[size++] = '\r';  		dest[size++] = '\n';  	}  	/* Postimage from side #2 */ -	size += xdl_recs_copy(xe2, m->i2, m->chg2, 1, +	size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,  			      dest ? dest + size : NULL);  	if (!dest) { -		size += marker_size + 1 + marker2_size; +		size += marker_size + 1 + needs_cr + marker2_size;  	} else {  		memset(dest + size, '>', marker_size);  		size += marker_size; @@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,  			memcpy(dest + size + 1, name2, marker2_size - 1);  			size += marker2_size;  		} +		if (needs_cr) +			dest[size++] = '\r';  		dest[size++] = '\n';  	}  	return size; @@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,  						  marker_size);  		else if (m->mode & 3) {  			/* Before conflicting part */ -			size += xdl_recs_copy(xe1, i, m->i1 - i, 0, +			size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,  					      dest ? dest + size : NULL);  			/* Postimage from side #1 */ -			if (m->mode & 1) -				size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2), +			if (m->mode & 1) { +				int needs_cr = is_cr_needed(xe1, xe2, m); + +				size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),  						      dest ? dest + size : NULL); +			}  			/* Postimage from side #2 */  			if (m->mode & 2) -				size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, +				size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,  						      dest ? dest + size : NULL);  		} else  			continue;  		i = m->i1 + m->chg1;  	} -	size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, +	size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,  			      dest ? dest + size : NULL);  	return size;  } @@ -579,8 +641,11 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,  	result->ptr = NULL;  	result->size = 0; -	if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0 || -			xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { +	if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) { +		return -1; +	} +	if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) { +		xdl_free_env(&xe1);  		return -1;  	}  	if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 || @@ -592,6 +657,8 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,  	if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 ||  	    xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 ||  	    xdl_build_script(&xe2, &xscr2) < 0) { +		xdl_free_script(xscr1); +		xdl_free_env(&xe1);  		xdl_free_env(&xe2);  		return -1;  	}  | 
