ws_fix_copy(): move the whitespace fixing function to ws.c

This is used by git-apply but we can use it elsewhere by slightly
generalizing it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/builtin-apply.c b/builtin-apply.c
index 5ed4e91..64471a2 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -1515,110 +1515,6 @@
 	}
 }
 
-static int copy_wsfix(char *output, const char *patch, int plen,
-		      unsigned ws_rule, int count_error)
-{
-	/*
-	 * plen is number of bytes to be copied from patch, starting
-	 * at patch.  Typically patch[plen-1] is '\n', unless this is
-	 * the incomplete last line.
-	 */
-	int i;
-	int add_nl_to_tail = 0;
-	int add_cr_to_tail = 0;
-	int fixed = 0;
-	int last_tab_in_indent = -1;
-	int last_space_in_indent = -1;
-	int need_fix_leading_space = 0;
-	char *buf;
-
-	/*
-	 * Strip trailing whitespace
-	 */
-	if ((ws_rule & WS_TRAILING_SPACE) &&
-	    (2 < plen && isspace(patch[plen-2]))) {
-		if (patch[plen - 1] == '\n') {
-			add_nl_to_tail = 1;
-			plen--;
-			if (1 < plen && patch[plen - 1] == '\r') {
-				add_cr_to_tail = !!(ws_rule & WS_CR_AT_EOL);
-				plen--;
-			}
-		}
-		if (0 < plen && isspace(patch[plen - 1])) {
-			while (0 < plen && isspace(patch[plen-1]))
-				plen--;
-			fixed = 1;
-		}
-	}
-
-	/*
-	 * Check leading whitespaces (indent)
-	 */
-	for (i = 0; i < plen; i++) {
-		char ch = patch[i];
-		if (ch == '\t') {
-			last_tab_in_indent = i;
-			if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
-			    0 <= last_space_in_indent)
-			    need_fix_leading_space = 1;
-		} else if (ch == ' ') {
-			last_space_in_indent = i;
-			if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
-			    8 <= i - last_tab_in_indent)
-				need_fix_leading_space = 1;
-		} else
-			break;
-	}
-
-	buf = output;
-	if (need_fix_leading_space) {
-		/* Process indent ourselves */
-		int consecutive_spaces = 0;
-		int last = last_tab_in_indent + 1;
-
-		if (ws_rule & WS_INDENT_WITH_NON_TAB) {
-			/* have "last" point at one past the indent */
-			if (last_tab_in_indent < last_space_in_indent)
-				last = last_space_in_indent + 1;
-			else
-				last = last_tab_in_indent + 1;
-		}
-
-		/*
-		 * between patch[0..last-1], strip the funny spaces,
-		 * updating them to tab as needed.
-		 */
-		for (i = 0; i < last; i++) {
-			char ch = patch[i];
-			if (ch != ' ') {
-				consecutive_spaces = 0;
-				*output++ = ch;
-			} else {
-				consecutive_spaces++;
-				if (consecutive_spaces == 8) {
-					*output++ = '\t';
-					consecutive_spaces = 0;
-				}
-			}
-		}
-		while (0 < consecutive_spaces--)
-			*output++ = ' ';
-		plen -= last;
-		patch += last;
-		fixed = 1;
-	}
-
-	memcpy(output, patch, plen);
-	if (add_cr_to_tail)
-		output[plen++] = '\r';
-	if (add_nl_to_tail)
-		output[plen++] = '\n';
-	if (fixed && count_error)
-		applied_after_fixing_ws++;
-	return output + plen - buf;
-}
-
 static void update_pre_post_images(struct image *preimage,
 				   struct image *postimage,
 				   char *buf,
@@ -1740,14 +1636,14 @@
 		int match;
 
 		/* Try fixing the line in the preimage */
-		fixlen = copy_wsfix(buf, orig, oldlen, ws_rule, 0);
+		fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
 
 		/* Try fixing the line in the target */
 		if (sizeof(tgtfixbuf) < tgtlen)
 			tgtfix = tgtfixbuf;
 		else
 			tgtfix = xmalloc(tgtlen);
-		tgtfixlen = copy_wsfix(tgtfix, target, tgtlen, ws_rule, 0);
+		tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);
 
 		/*
 		 * If they match, either the preimage was based on
@@ -2006,8 +1902,7 @@
 				added = plen;
 			}
 			else {
-				added = copy_wsfix(new, patch + 1, plen,
-						   ws_rule, 1);
+				added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
 			}
 			add_line_info(&postimage, new, added,
 				      (first == '+' ? 0 : LINE_COMMON));
diff --git a/cache.h b/cache.h
index ad11c90..3d4c6b0 100644
--- a/cache.h
+++ b/cache.h
@@ -661,6 +661,7 @@
     FILE *stream, const char *set,
     const char *reset, const char *ws);
 extern char *whitespace_error_string(unsigned ws);
+extern int ws_fix_copy(char *, const char *, int, unsigned, int *);
 
 /* ls-files */
 int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);
diff --git a/ws.c b/ws.c
index 5a9ac45..522f646 100644
--- a/ws.c
+++ b/ws.c
@@ -212,3 +212,107 @@
 	}
 	return result;
 }
+
+/* Copy the line to the buffer while fixing whitespaces */
+int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *error_count)
+{
+	/*
+	 * len is number of bytes to be copied from src, starting
+	 * at src.  Typically src[len-1] is '\n', unless this is
+	 * the incomplete last line.
+	 */
+	int i;
+	int add_nl_to_tail = 0;
+	int add_cr_to_tail = 0;
+	int fixed = 0;
+	int last_tab_in_indent = -1;
+	int last_space_in_indent = -1;
+	int need_fix_leading_space = 0;
+	char *buf;
+
+	/*
+	 * Strip trailing whitespace
+	 */
+	if ((ws_rule & WS_TRAILING_SPACE) &&
+	    (2 < len && isspace(src[len-2]))) {
+		if (src[len - 1] == '\n') {
+			add_nl_to_tail = 1;
+			len--;
+			if (1 < len && src[len - 1] == '\r') {
+				add_cr_to_tail = !!(ws_rule & WS_CR_AT_EOL);
+				len--;
+			}
+		}
+		if (0 < len && isspace(src[len - 1])) {
+			while (0 < len && isspace(src[len-1]))
+				len--;
+			fixed = 1;
+		}
+	}
+
+	/*
+	 * Check leading whitespaces (indent)
+	 */
+	for (i = 0; i < len; i++) {
+		char ch = src[i];
+		if (ch == '\t') {
+			last_tab_in_indent = i;
+			if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
+			    0 <= last_space_in_indent)
+			    need_fix_leading_space = 1;
+		} else if (ch == ' ') {
+			last_space_in_indent = i;
+			if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+			    8 <= i - last_tab_in_indent)
+				need_fix_leading_space = 1;
+		} else
+			break;
+	}
+
+	buf = dst;
+	if (need_fix_leading_space) {
+		/* Process indent ourselves */
+		int consecutive_spaces = 0;
+		int last = last_tab_in_indent + 1;
+
+		if (ws_rule & WS_INDENT_WITH_NON_TAB) {
+			/* have "last" point at one past the indent */
+			if (last_tab_in_indent < last_space_in_indent)
+				last = last_space_in_indent + 1;
+			else
+				last = last_tab_in_indent + 1;
+		}
+
+		/*
+		 * between src[0..last-1], strip the funny spaces,
+		 * updating them to tab as needed.
+		 */
+		for (i = 0; i < last; i++) {
+			char ch = src[i];
+			if (ch != ' ') {
+				consecutive_spaces = 0;
+				*dst++ = ch;
+			} else {
+				consecutive_spaces++;
+				if (consecutive_spaces == 8) {
+					*dst++ = '\t';
+					consecutive_spaces = 0;
+				}
+			}
+		}
+		while (0 < consecutive_spaces--)
+			*dst++ = ' ';
+		len -= last;
+		src += last;
+		fixed = 1;
+	}
+
+	memcpy(dst, src, len);
+	if (add_cr_to_tail)
+		dst[len++] = '\r';
+	if (add_nl_to_tail)
+		dst[len++] = '\n';
+	if (fixed && error_count)
+		(*error_count)++;
+	return dst + len - buf;
+}