diff options
author | Junio C Hamano <gitster@pobox.com> | 2008-02-24 17:23:17 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2008-02-24 17:23:17 -0800 |
commit | e38f892d1832977511c4e7c82204c7f94c3a3232 (patch) | |
tree | ebbab519e098092d766d8391354995e5bfef6ba2 /ws.c | |
parent | dc31cd8fcc20d95a80da5ebe6feaab01539ebe4c (diff) | |
parent | fe3403c3205de44faa926a086b4b99f157fc63fe (diff) | |
download | git-e38f892d1832977511c4e7c82204c7f94c3a3232.tar.gz git-e38f892d1832977511c4e7c82204c7f94c3a3232.tar.xz |
Merge branch 'jc/apply-whitespace'
* jc/apply-whitespace:
ws_fix_copy(): move the whitespace fixing function to ws.c
apply: do not barf on patch with too large an offset
core.whitespace: cr-at-eol
git-apply --whitespace=fix: fix whitespace fuzz introduced by previous run
builtin-apply.c: pass ws_rule down to match_fragment()
builtin-apply.c: move copy_wsfix() function a bit higher.
builtin-apply.c: do not feed copy_wsfix() leading '+'
builtin-apply.c: simplify calling site to apply_line()
builtin-apply.c: clean-up apply_one_fragment()
builtin-apply.c: mark common context lines in lineinfo structure.
builtin-apply.c: optimize match_beginning/end processing a bit.
builtin-apply.c: make it more line oriented
builtin-apply.c: push match-beginning/end logic down
builtin-apply.c: restructure "offset" matching
builtin-apply.c: refactor small part that matches context
Diffstat (limited to 'ws.c')
-rw-r--r-- | ws.c | 119 |
1 files changed, 117 insertions, 2 deletions
@@ -14,6 +14,7 @@ static struct whitespace_rule { { "trailing-space", WS_TRAILING_SPACE }, { "space-before-tab", WS_SPACE_BEFORE_TAB }, { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB }, + { "cr-at-eol", WS_CR_AT_EOL }, }; unsigned parse_whitespace_rule(const char *string) @@ -124,6 +125,7 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, int written = 0; int trailing_whitespace = -1; int trailing_newline = 0; + int trailing_carriage_return = 0; int i; /* Logic is simpler if we temporarily ignore the trailing newline. */ @@ -131,6 +133,11 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, trailing_newline = 1; len--; } + if ((ws_rule & WS_CR_AT_EOL) && + len > 0 && line[len - 1] == '\r') { + trailing_carriage_return = 1; + len--; + } /* Check for trailing whitespace. */ if (ws_rule & WS_TRAILING_SPACE) { @@ -176,8 +183,10 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, } if (stream) { - /* Now the rest of the line starts at written. - * The non-highlighted part ends at trailing_whitespace. */ + /* + * Now the rest of the line starts at "written". + * The non-highlighted part ends at "trailing_whitespace". + */ if (trailing_whitespace == -1) trailing_whitespace = len; @@ -196,8 +205,114 @@ unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, len - trailing_whitespace, 1, stream); fputs(reset, stream); } + if (trailing_carriage_return) + fputc('\r', stream); if (trailing_newline) fputc('\n', stream); } 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; +} |